Merge patch series "ns: tweak ns common handling"
Christian Brauner <brauner@kernel.org> says: This contains three minor tweaks for namespace handling: * Make struct ns_tree private. There's no need for anything to access that directly. * Drop a debug assert that would trigger in conditions that are benign. * Move the type of the namespace out of struct proc_ns_operations and into struct ns_common. This eliminates a pointer dereference and also allows assertions to work when the namespace type is disabled and the operations field set to NULL. * patches from https://lore.kernel.org/20250924-work-namespaces-fixes-v1-0-8fb682c8678e@kernel.org: ns: drop assert ns: move ns type into struct ns_common nstree: make struct ns_tree private Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
commit
6e65f4e8fc
|
@ -4927,7 +4927,7 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize,
|
|||
return -EINVAL;
|
||||
|
||||
ns = get_proc_ns(file_inode(fd_file(f)));
|
||||
if (ns->ops->type != CLONE_NEWUSER)
|
||||
if (ns->ns_type != CLONE_NEWUSER)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
@ -5830,7 +5830,7 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
|
|||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ns = get_proc_ns(file_inode(fd_file(f)));
|
||||
if (ns->ops->type != CLONE_NEWNS)
|
||||
if (ns->ns_type != CLONE_NEWNS)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mnt_ns = to_mnt_ns(ns);
|
||||
|
@ -6016,6 +6016,7 @@ struct mnt_namespace init_mnt_ns = {
|
|||
.ns.ops = &mntns_operations,
|
||||
.user_ns = &init_user_ns,
|
||||
.ns.__ns_ref = REFCOUNT_INIT(1),
|
||||
.ns.ns_type = ns_common_type(&init_mnt_ns),
|
||||
.passive = REFCOUNT_INIT(1),
|
||||
.mounts = RB_ROOT,
|
||||
.poll = __WAIT_QUEUE_HEAD_INITIALIZER(init_mnt_ns.poll),
|
||||
|
@ -6333,7 +6334,6 @@ static struct user_namespace *mntns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations mntns_operations = {
|
||||
.name = "mnt",
|
||||
.type = CLONE_NEWNS,
|
||||
.get = mntns_get,
|
||||
.put = mntns_put,
|
||||
.install = mntns_install,
|
||||
|
|
18
fs/nsfs.c
18
fs/nsfs.c
|
@ -219,9 +219,9 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
|||
return -EINVAL;
|
||||
return open_related_ns(ns, ns->ops->get_parent);
|
||||
case NS_GET_NSTYPE:
|
||||
return ns->ops->type;
|
||||
return ns->ns_type;
|
||||
case NS_GET_OWNER_UID:
|
||||
if (ns->ops->type != CLONE_NEWUSER)
|
||||
if (ns->ns_type != CLONE_NEWUSER)
|
||||
return -EINVAL;
|
||||
user_ns = container_of(ns, struct user_namespace, ns);
|
||||
argp = (uid_t __user *) arg;
|
||||
|
@ -234,7 +234,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
|||
case NS_GET_PID_IN_PIDNS:
|
||||
fallthrough;
|
||||
case NS_GET_TGID_IN_PIDNS: {
|
||||
if (ns->ops->type != CLONE_NEWPID)
|
||||
if (ns->ns_type != CLONE_NEWPID)
|
||||
return -EINVAL;
|
||||
|
||||
ret = -ESRCH;
|
||||
|
@ -273,7 +273,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
|||
return ret;
|
||||
}
|
||||
case NS_GET_MNTNS_ID:
|
||||
if (ns->ops->type != CLONE_NEWNS)
|
||||
if (ns->ns_type != CLONE_NEWNS)
|
||||
return -EINVAL;
|
||||
fallthrough;
|
||||
case NS_GET_ID: {
|
||||
|
@ -293,7 +293,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
|||
struct mnt_ns_info __user *uinfo = (struct mnt_ns_info __user *)arg;
|
||||
size_t usize = _IOC_SIZE(ioctl);
|
||||
|
||||
if (ns->ops->type != CLONE_NEWNS)
|
||||
if (ns->ns_type != CLONE_NEWNS)
|
||||
return -EINVAL;
|
||||
|
||||
if (!uinfo)
|
||||
|
@ -314,7 +314,7 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
|
|||
struct file *f __free(fput) = NULL;
|
||||
size_t usize = _IOC_SIZE(ioctl);
|
||||
|
||||
if (ns->ops->type != CLONE_NEWNS)
|
||||
if (ns->ns_type != CLONE_NEWNS)
|
||||
return -EINVAL;
|
||||
|
||||
if (usize < MNT_NS_INFO_SIZE_VER0)
|
||||
|
@ -453,7 +453,7 @@ static int nsfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
|
|||
}
|
||||
|
||||
fid->ns_id = ns->ns_id;
|
||||
fid->ns_type = ns->ops->type;
|
||||
fid->ns_type = ns->ns_type;
|
||||
fid->ns_inum = inode->i_ino;
|
||||
return FILEID_NSFS;
|
||||
}
|
||||
|
@ -489,14 +489,14 @@ static struct dentry *nsfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
|
|||
return NULL;
|
||||
|
||||
VFS_WARN_ON_ONCE(ns->ns_id != fid->ns_id);
|
||||
VFS_WARN_ON_ONCE(ns->ops->type != fid->ns_type);
|
||||
VFS_WARN_ON_ONCE(ns->ns_type != fid->ns_type);
|
||||
VFS_WARN_ON_ONCE(ns->inum != fid->ns_inum);
|
||||
|
||||
if (!__ns_ref_get(ns))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (ns->ops->type) {
|
||||
switch (ns->ns_type) {
|
||||
#ifdef CONFIG_CGROUPS
|
||||
case CLONE_NEWCGROUP:
|
||||
if (!current_in_namespace(to_cg_ns(ns)))
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <uapi/linux/sched.h>
|
||||
|
||||
struct proc_ns_operations;
|
||||
|
||||
|
@ -37,6 +38,7 @@ extern const struct proc_ns_operations timens_operations;
|
|||
extern const struct proc_ns_operations timens_for_children_operations;
|
||||
|
||||
struct ns_common {
|
||||
u32 ns_type;
|
||||
struct dentry *stashed;
|
||||
const struct proc_ns_operations *ops;
|
||||
unsigned int inum;
|
||||
|
@ -51,7 +53,7 @@ struct ns_common {
|
|||
};
|
||||
};
|
||||
|
||||
int __ns_common_init(struct ns_common *ns, const struct proc_ns_operations *ops, int inum);
|
||||
int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum);
|
||||
void __ns_common_free(struct ns_common *ns);
|
||||
|
||||
#define to_ns_common(__ns) \
|
||||
|
@ -106,10 +108,28 @@ void __ns_common_free(struct ns_common *ns);
|
|||
struct user_namespace *: (IS_ENABLED(CONFIG_USER_NS) ? &userns_operations : NULL), \
|
||||
struct uts_namespace *: (IS_ENABLED(CONFIG_UTS_NS) ? &utsns_operations : NULL))
|
||||
|
||||
#define ns_common_init(__ns) \
|
||||
__ns_common_init(to_ns_common(__ns), to_ns_operations(__ns), (((__ns) == ns_init_ns(__ns)) ? ns_init_inum(__ns) : 0))
|
||||
#define ns_common_type(__ns) \
|
||||
_Generic((__ns), \
|
||||
struct cgroup_namespace *: CLONE_NEWCGROUP, \
|
||||
struct ipc_namespace *: CLONE_NEWIPC, \
|
||||
struct mnt_namespace *: CLONE_NEWNS, \
|
||||
struct net *: CLONE_NEWNET, \
|
||||
struct pid_namespace *: CLONE_NEWPID, \
|
||||
struct time_namespace *: CLONE_NEWTIME, \
|
||||
struct user_namespace *: CLONE_NEWUSER, \
|
||||
struct uts_namespace *: CLONE_NEWUTS)
|
||||
|
||||
#define ns_common_init_inum(__ns, __inum) __ns_common_init(to_ns_common(__ns), to_ns_operations(__ns), __inum)
|
||||
#define ns_common_init(__ns) \
|
||||
__ns_common_init(to_ns_common(__ns), \
|
||||
ns_common_type(__ns), \
|
||||
to_ns_operations(__ns), \
|
||||
(((__ns) == ns_init_ns(__ns)) ? ns_init_inum(__ns) : 0))
|
||||
|
||||
#define ns_common_init_inum(__ns, __inum) \
|
||||
__ns_common_init(to_ns_common(__ns), \
|
||||
ns_common_type(__ns), \
|
||||
to_ns_operations(__ns), \
|
||||
__inum)
|
||||
|
||||
#define ns_common_free(__ns) __ns_common_free(to_ns_common((__ns)))
|
||||
|
||||
|
|
|
@ -9,19 +9,6 @@
|
|||
#include <linux/rculist.h>
|
||||
#include <linux/cookie.h>
|
||||
|
||||
/**
|
||||
* struct ns_tree - Namespace tree
|
||||
* @ns_tree: Rbtree of namespaces of a particular type
|
||||
* @ns_list: Sequentially walkable list of all namespaces of this type
|
||||
* @ns_tree_lock: Seqlock to protect the tree and list
|
||||
*/
|
||||
struct ns_tree {
|
||||
struct rb_root ns_tree;
|
||||
struct list_head ns_list;
|
||||
seqlock_t ns_tree_lock;
|
||||
int type;
|
||||
};
|
||||
|
||||
extern struct ns_tree cgroup_ns_tree;
|
||||
extern struct ns_tree ipc_ns_tree;
|
||||
extern struct ns_tree mnt_ns_tree;
|
||||
|
|
|
@ -17,7 +17,6 @@ struct inode;
|
|||
struct proc_ns_operations {
|
||||
const char *name;
|
||||
const char *real_ns_name;
|
||||
int type;
|
||||
struct ns_common *(*get)(struct task_struct *task);
|
||||
void (*put)(struct ns_common *ns);
|
||||
int (*install)(struct nsset *nsset, struct ns_common *ns);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/utsname.h>
|
||||
|
||||
struct uts_namespace init_uts_ns = {
|
||||
.ns.ns_type = ns_common_type(&init_uts_ns),
|
||||
.ns.__ns_ref = REFCOUNT_INIT(2),
|
||||
.name = {
|
||||
.sysname = UTS_SYSNAME,
|
||||
|
|
|
@ -33,6 +33,7 @@ struct ipc_namespace init_ipc_ns = {
|
|||
#ifdef CONFIG_IPC_NS
|
||||
.ns.ops = &ipcns_operations,
|
||||
#endif
|
||||
.ns.ns_type = ns_common_type(&init_ipc_ns),
|
||||
};
|
||||
|
||||
struct msg_msgseg {
|
||||
|
|
|
@ -248,7 +248,6 @@ static struct user_namespace *ipcns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations ipcns_operations = {
|
||||
.name = "ipc",
|
||||
.type = CLONE_NEWIPC,
|
||||
.get = ipcns_get,
|
||||
.put = ipcns_put,
|
||||
.install = ipcns_install,
|
||||
|
|
|
@ -224,6 +224,7 @@ struct cgroup_namespace init_cgroup_ns = {
|
|||
.ns.ops = &cgroupns_operations,
|
||||
.ns.inum = ns_init_inum(&init_cgroup_ns),
|
||||
.root_cset = &init_css_set,
|
||||
.ns.ns_type = ns_common_type(&init_cgroup_ns),
|
||||
};
|
||||
|
||||
static struct file_system_type cgroup2_fs_type;
|
||||
|
|
|
@ -137,7 +137,6 @@ static struct user_namespace *cgroupns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations cgroupns_operations = {
|
||||
.name = "cgroup",
|
||||
.type = CLONE_NEWCGROUP,
|
||||
.get = cgroupns_get,
|
||||
.put = cgroupns_put,
|
||||
.install = cgroupns_install,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#ifdef CONFIG_DEBUG_VFS
|
||||
static void ns_debug(struct ns_common *ns, const struct proc_ns_operations *ops)
|
||||
{
|
||||
switch (ns->ops->type) {
|
||||
switch (ns->ns_type) {
|
||||
#ifdef CONFIG_CGROUPS
|
||||
case CLONE_NEWCGROUP:
|
||||
VFS_WARN_ON_ONCE(ops != &cgroupns_operations);
|
||||
|
@ -46,18 +46,17 @@ static void ns_debug(struct ns_common *ns, const struct proc_ns_operations *ops)
|
|||
VFS_WARN_ON_ONCE(ops != &utsns_operations);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
VFS_WARN_ON_ONCE(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int __ns_common_init(struct ns_common *ns, const struct proc_ns_operations *ops, int inum)
|
||||
int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum)
|
||||
{
|
||||
refcount_set(&ns->__ns_ref, 1);
|
||||
ns->stashed = NULL;
|
||||
ns->ops = ops;
|
||||
ns->ns_id = 0;
|
||||
ns->ns_type = ns_type;
|
||||
RB_CLEAR_NODE(&ns->ns_tree_node);
|
||||
INIT_LIST_HEAD(&ns->ns_list_node);
|
||||
|
||||
|
|
|
@ -545,9 +545,9 @@ SYSCALL_DEFINE2(setns, int, fd, int, flags)
|
|||
|
||||
if (proc_ns_file(fd_file(f))) {
|
||||
ns = get_proc_ns(file_inode(fd_file(f)));
|
||||
if (flags && (ns->ops->type != flags))
|
||||
if (flags && (ns->ns_type != flags))
|
||||
err = -EINVAL;
|
||||
flags = ns->ops->type;
|
||||
flags = ns->ns_type;
|
||||
} else if (!IS_ERR(pidfd_pid(fd_file(f)))) {
|
||||
err = check_setns_flags(flags);
|
||||
} else {
|
||||
|
|
|
@ -4,6 +4,20 @@
|
|||
#include <linux/proc_ns.h>
|
||||
#include <linux/vfsdebug.h>
|
||||
|
||||
/**
|
||||
* struct ns_tree - Namespace tree
|
||||
* @ns_tree: Rbtree of namespaces of a particular type
|
||||
* @ns_list: Sequentially walkable list of all namespaces of this type
|
||||
* @ns_tree_lock: Seqlock to protect the tree and list
|
||||
* @type: type of namespaces in this tree
|
||||
*/
|
||||
struct ns_tree {
|
||||
struct rb_root ns_tree;
|
||||
struct list_head ns_list;
|
||||
seqlock_t ns_tree_lock;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct ns_tree mnt_ns_tree = {
|
||||
.ns_tree = RB_ROOT,
|
||||
.ns_list = LIST_HEAD_INIT(mnt_ns_tree.ns_list),
|
||||
|
@ -92,7 +106,7 @@ void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree *ns_tree)
|
|||
|
||||
write_seqlock(&ns_tree->ns_tree_lock);
|
||||
|
||||
VFS_WARN_ON_ONCE(ns->ops->type != ns_tree->type);
|
||||
VFS_WARN_ON_ONCE(ns->ns_type != ns_tree->type);
|
||||
|
||||
node = rb_find_add_rcu(&ns->ns_tree_node, &ns_tree->ns_tree, ns_cmp);
|
||||
/*
|
||||
|
@ -114,7 +128,7 @@ void __ns_tree_remove(struct ns_common *ns, struct ns_tree *ns_tree)
|
|||
{
|
||||
VFS_WARN_ON_ONCE(RB_EMPTY_NODE(&ns->ns_tree_node));
|
||||
VFS_WARN_ON_ONCE(list_empty(&ns->ns_list_node));
|
||||
VFS_WARN_ON_ONCE(ns->ops->type != ns_tree->type);
|
||||
VFS_WARN_ON_ONCE(ns->ns_type != ns_tree->type);
|
||||
|
||||
write_seqlock(&ns_tree->ns_tree_lock);
|
||||
rb_erase(&ns->ns_tree_node, &ns_tree->ns_tree);
|
||||
|
@ -183,7 +197,7 @@ struct ns_common *ns_tree_lookup_rcu(u64 ns_id, int ns_type)
|
|||
if (!node)
|
||||
return NULL;
|
||||
|
||||
VFS_WARN_ON_ONCE(node_to_ns(node)->ops->type != ns_type);
|
||||
VFS_WARN_ON_ONCE(node_to_ns(node)->ns_type != ns_type);
|
||||
|
||||
return node_to_ns(node);
|
||||
}
|
||||
|
@ -211,7 +225,7 @@ struct ns_common *__ns_tree_adjoined_rcu(struct ns_common *ns,
|
|||
if (list_is_head(list, &ns_tree->ns_list))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
VFS_WARN_ON_ONCE(list_entry_rcu(list, struct ns_common, ns_list_node)->ops->type != ns_tree->type);
|
||||
VFS_WARN_ON_ONCE(list_entry_rcu(list, struct ns_common, ns_list_node)->ns_type != ns_tree->type);
|
||||
|
||||
return list_entry_rcu(list, struct ns_common, ns_list_node);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ struct pid_namespace init_pid_ns = {
|
|||
#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE)
|
||||
.memfd_noexec_scope = MEMFD_NOEXEC_SCOPE_EXEC,
|
||||
#endif
|
||||
.ns.ns_type = ns_common_type(&init_pid_ns),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(init_pid_ns);
|
||||
|
||||
|
|
|
@ -443,7 +443,6 @@ static struct user_namespace *pidns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations pidns_operations = {
|
||||
.name = "pid",
|
||||
.type = CLONE_NEWPID,
|
||||
.get = pidns_get,
|
||||
.put = pidns_put,
|
||||
.install = pidns_install,
|
||||
|
@ -454,7 +453,6 @@ const struct proc_ns_operations pidns_operations = {
|
|||
const struct proc_ns_operations pidns_for_children_operations = {
|
||||
.name = "pid_for_children",
|
||||
.real_ns_name = "pid",
|
||||
.type = CLONE_NEWPID,
|
||||
.get = pidns_for_children_get,
|
||||
.put = pidns_put,
|
||||
.install = pidns_install,
|
||||
|
|
|
@ -462,7 +462,6 @@ out:
|
|||
|
||||
const struct proc_ns_operations timens_operations = {
|
||||
.name = "time",
|
||||
.type = CLONE_NEWTIME,
|
||||
.get = timens_get,
|
||||
.put = timens_put,
|
||||
.install = timens_install,
|
||||
|
@ -472,7 +471,6 @@ const struct proc_ns_operations timens_operations = {
|
|||
const struct proc_ns_operations timens_for_children_operations = {
|
||||
.name = "time_for_children",
|
||||
.real_ns_name = "time",
|
||||
.type = CLONE_NEWTIME,
|
||||
.get = timens_for_children_get,
|
||||
.put = timens_put,
|
||||
.install = timens_install,
|
||||
|
@ -480,6 +478,7 @@ const struct proc_ns_operations timens_for_children_operations = {
|
|||
};
|
||||
|
||||
struct time_namespace init_time_ns = {
|
||||
.ns.ns_type = ns_common_type(&init_time_ns),
|
||||
.ns.__ns_ref = REFCOUNT_INIT(3),
|
||||
.user_ns = &init_user_ns,
|
||||
.ns.inum = ns_init_inum(&init_time_ns),
|
||||
|
|
|
@ -65,6 +65,7 @@ struct user_namespace init_user_ns = {
|
|||
.nr_extents = 1,
|
||||
},
|
||||
},
|
||||
.ns.ns_type = ns_common_type(&init_user_ns),
|
||||
.ns.__ns_ref = REFCOUNT_INIT(3),
|
||||
.owner = GLOBAL_ROOT_UID,
|
||||
.group = GLOBAL_ROOT_GID,
|
||||
|
|
|
@ -1400,7 +1400,6 @@ static struct user_namespace *userns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations userns_operations = {
|
||||
.name = "user",
|
||||
.type = CLONE_NEWUSER,
|
||||
.get = userns_get,
|
||||
.put = userns_put,
|
||||
.install = userns_install,
|
||||
|
|
|
@ -146,7 +146,6 @@ static struct user_namespace *utsns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations utsns_operations = {
|
||||
.name = "uts",
|
||||
.type = CLONE_NEWUTS,
|
||||
.get = utsns_get,
|
||||
.put = utsns_put,
|
||||
.install = utsns_install,
|
||||
|
|
|
@ -1543,7 +1543,6 @@ static struct user_namespace *netns_owner(struct ns_common *ns)
|
|||
|
||||
const struct proc_ns_operations netns_operations = {
|
||||
.name = "net",
|
||||
.type = CLONE_NEWNET,
|
||||
.get = netns_get,
|
||||
.put = netns_put,
|
||||
.install = netns_install,
|
||||
|
|
Loading…
Reference in New Issue