diff options
| author | Christian Brauner <brauner@kernel.org> | 2026-04-01 12:15:58 +0200 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-04-09 14:36:52 +0200 |
| commit | e3b2cf6e5dba416a03152f299d99982dfe1e861d (patch) | |
| tree | d10833a41819fac2d0c066bd80def58a36453228 /fs | |
| parent | 07712db80857d5d09ae08f3df85a708ecfc3b61f (diff) | |
| download | linux-e3b2cf6e5dba416a03152f299d99982dfe1e861d.tar.gz linux-e3b2cf6e5dba416a03152f299d99982dfe1e861d.zip | |
kernfs: pass struct ns_common instead of const void * for namespace tags
kernfs has historically used const void * to pass around namespace tags
used for directory-level namespace filtering. The only current user of
this is sysfs network namespace tagging where struct net pointers are
cast to void *.
Replace all const void * namespace parameters with const struct
ns_common * throughout the kernfs, sysfs, and kobject namespace layers.
This includes the kobj_ns_type_operations callbacks, kobject_namespace(),
and all sysfs/kernfs APIs that accept or return namespace tags.
Passing struct ns_common is needed because various codepaths require
access to the underlying namespace. A struct ns_common can always be
converted back to the concrete namespace type (e.g., struct net) via
container_of() or to_ns_common() in the reverse direction.
This is a preparatory change for switching to ns_id-based directory
iteration to prevent a KASLR pointer leak through the current use of
raw namespace pointers as hash seeds and comparison keys.
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/kernfs/dir.c | 30 | ||||
| -rw-r--r-- | fs/kernfs/file.c | 2 | ||||
| -rw-r--r-- | fs/kernfs/kernfs-internal.h | 2 | ||||
| -rw-r--r-- | fs/kernfs/mount.c | 2 | ||||
| -rw-r--r-- | fs/nfs/sysfs.c | 16 | ||||
| -rw-r--r-- | fs/sysfs/dir.c | 6 | ||||
| -rw-r--r-- | fs/sysfs/file.c | 8 | ||||
| -rw-r--r-- | fs/sysfs/mount.c | 10 | ||||
| -rw-r--r-- | fs/sysfs/symlink.c | 7 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 4 |
10 files changed, 49 insertions, 38 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 8d40c4b1db9ff..be262145ae084 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -313,7 +313,8 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) * * Return: 31-bit hash of ns + name (so it fits in an off_t) */ -static unsigned int kernfs_name_hash(const char *name, const void *ns) +static unsigned int kernfs_name_hash(const char *name, + const struct ns_common *ns) { unsigned long hash = init_name_hash(ns); unsigned int len = strlen(name); @@ -330,7 +331,7 @@ static unsigned int kernfs_name_hash(const char *name, const void *ns) } static int kernfs_name_compare(unsigned int hash, const char *name, - const void *ns, const struct kernfs_node *kn) + const struct ns_common *ns, const struct kernfs_node *kn) { if (hash < kn->hash) return -1; @@ -856,7 +857,7 @@ out_unlock: */ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, const unsigned char *name, - const void *ns) + const struct ns_common *ns) { struct rb_node *node = parent->dir.children.rb_node; bool has_ns = kernfs_ns_enabled(parent); @@ -889,7 +890,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent, const unsigned char *path, - const void *ns) + const struct ns_common *ns) { ssize_t len; char *p, *name; @@ -930,7 +931,8 @@ static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent, * Return: pointer to the found kernfs_node on success, %NULL on failure. */ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, - const char *name, const void *ns) + const char *name, + const struct ns_common *ns) { struct kernfs_node *kn; struct kernfs_root *root = kernfs_root(parent); @@ -956,7 +958,8 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); * Return: pointer to the found kernfs_node on success, %NULL on failure. */ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, - const char *path, const void *ns) + const char *path, + const struct ns_common *ns) { struct kernfs_node *kn; struct kernfs_root *root = kernfs_root(parent); @@ -1079,7 +1082,8 @@ struct kernfs_node *kernfs_root_to_node(struct kernfs_root *root) struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, umode_t mode, kuid_t uid, kgid_t gid, - void *priv, const void *ns) + void *priv, + const struct ns_common *ns) { struct kernfs_node *kn; int rc; @@ -1221,7 +1225,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, struct kernfs_node *kn; struct kernfs_root *root; struct inode *inode = NULL; - const void *ns = NULL; + const struct ns_common *ns = NULL; root = kernfs_root(parent); down_read(&root->kernfs_rwsem); @@ -1702,7 +1706,7 @@ bool kernfs_remove_self(struct kernfs_node *kn) * Return: %0 on success, -ENOENT if such entry doesn't exist. */ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, - const void *ns) + const struct ns_common *ns) { struct kernfs_node *kn; struct kernfs_root *root; @@ -1741,7 +1745,7 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, * Return: %0 on success, -errno on failure. */ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - const char *new_name, const void *new_ns) + const char *new_name, const struct ns_common *new_ns) { struct kernfs_node *old_parent; struct kernfs_root *root; @@ -1832,7 +1836,7 @@ static int kernfs_dir_fop_release(struct inode *inode, struct file *filp) return 0; } -static struct kernfs_node *kernfs_dir_pos(const void *ns, +static struct kernfs_node *kernfs_dir_pos(const struct ns_common *ns, struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) { if (pos) { @@ -1867,7 +1871,7 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns, return pos; } -static struct kernfs_node *kernfs_dir_next_pos(const void *ns, +static struct kernfs_node *kernfs_dir_next_pos(const struct ns_common *ns, struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) { pos = kernfs_dir_pos(ns, parent, ino, pos); @@ -1889,7 +1893,7 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) struct kernfs_node *parent = kernfs_dentry_node(dentry); struct kernfs_node *pos = file->private_data; struct kernfs_root *root; - const void *ns = NULL; + const struct ns_common *ns = NULL; if (!dir_emit_dots(file, ctx)) return 0; diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index e32406d62c0d3..1163aa7697384 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -1045,7 +1045,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, umode_t mode, kuid_t uid, kgid_t gid, loff_t size, const struct kernfs_ops *ops, - void *priv, const void *ns, + void *priv, const struct ns_common *ns, struct lock_class_key *key) { struct kernfs_node *kn; diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 6061b6f70d2a3..b1fd9622a5e34 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -97,7 +97,7 @@ struct kernfs_super_info { * instance. If multiple tags become necessary, make the following * an array and compare kernfs_node tag against every entry. */ - const void *ns; + const struct ns_common *ns; /* anchored at kernfs_root->supers, protected by kernfs_rwsem */ struct list_head node; diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 048f00b73b717..6e3217b6e4811 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -345,7 +345,7 @@ static int kernfs_set_super(struct super_block *sb, struct fs_context *fc) * * Return: the namespace tag associated with kernfs super_block @sb. */ -const void *kernfs_super_ns(struct super_block *sb) +const struct ns_common *kernfs_super_ns(struct super_block *sb) { struct kernfs_super_info *info = kernfs_info(sb); diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c index 7d8921f524a69..1da4f707f9efe 100644 --- a/fs/nfs/sysfs.c +++ b/fs/nfs/sysfs.c @@ -11,6 +11,7 @@ #include <linux/netdevice.h> #include <linux/string.h> #include <linux/nfs_fs.h> +#include <net/net_namespace.h> #include <linux/rcupdate.h> #include <linux/lockd/lockd.h> @@ -127,9 +128,10 @@ static void nfs_netns_client_release(struct kobject *kobj) kfree(rcu_dereference_raw(c->identifier)); } -static const void *nfs_netns_client_namespace(const struct kobject *kobj) +static const struct ns_common *nfs_netns_client_namespace(const struct kobject *kobj) { - return container_of(kobj, struct nfs_netns_client, kobject)->net; + return to_ns_common(container_of(kobj, struct nfs_netns_client, + kobject)->net); } static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier, @@ -156,9 +158,10 @@ static void nfs_netns_object_release(struct kobject *kobj) kfree(c); } -static const void *nfs_netns_namespace(const struct kobject *kobj) +static const struct ns_common *nfs_netns_namespace(const struct kobject *kobj) { - return container_of(kobj, struct nfs_netns_client, nfs_net_kobj)->net; + return to_ns_common(container_of(kobj, struct nfs_netns_client, + nfs_net_kobj)->net); } static struct kobj_type nfs_netns_object_type = { @@ -350,9 +353,10 @@ static void nfs_sysfs_sb_release(struct kobject *kobj) /* no-op: why? see lib/kobject.c kobject_cleanup() */ } -static const void *nfs_netns_server_namespace(const struct kobject *kobj) +static const struct ns_common *nfs_netns_server_namespace(const struct kobject *kobj) { - return container_of(kobj, struct nfs_server, kobj)->nfs_client->cl_net; + return to_ns_common(container_of(kobj, struct nfs_server, + kobj)->nfs_client->cl_net); } static struct kobj_type nfs_sb_ktype = { diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 94e12efd92f21..ffdcd4153c584 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -37,7 +37,7 @@ void sysfs_warn_dup(struct kernfs_node *parent, const char *name) * @kobj: object we're creating directory for * @ns: the namespace tag to use */ -int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) +int sysfs_create_dir_ns(struct kobject *kobj, const struct ns_common *ns) { struct kernfs_node *parent, *kn; kuid_t uid; @@ -103,7 +103,7 @@ void sysfs_remove_dir(struct kobject *kobj) } int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, - const void *new_ns) + const struct ns_common *new_ns) { struct kernfs_node *parent; int ret; @@ -115,7 +115,7 @@ int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, } int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, - const void *new_ns) + const struct ns_common *new_ns) { struct kernfs_node *kn = kobj->sd; struct kernfs_node *new_parent; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index a8176c875f55e..5709cede1d756 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -272,7 +272,7 @@ static const struct kernfs_ops sysfs_bin_kfops_mmap = { int sysfs_add_file_mode_ns(struct kernfs_node *parent, const struct attribute *attr, umode_t mode, kuid_t uid, - kgid_t gid, const void *ns) + kgid_t gid, const struct ns_common *ns) { struct kobject *kobj = parent->priv; const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops; @@ -322,7 +322,7 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent, int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent, const struct bin_attribute *battr, umode_t mode, size_t size, - kuid_t uid, kgid_t gid, const void *ns) + kuid_t uid, kgid_t gid, const struct ns_common *ns) { const struct attribute *attr = &battr->attr; struct lock_class_key *key = NULL; @@ -362,7 +362,7 @@ int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent, * @ns: namespace the new file should belong to */ int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, - const void *ns) + const struct ns_common *ns) { kuid_t uid; kgid_t gid; @@ -505,7 +505,7 @@ EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection); * Hash the attribute name and namespace tag and kill the victim. */ void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, - const void *ns) + const struct ns_common *ns) { struct kernfs_node *parent = kobj->sd; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index e65c60158a04a..b199e8ff79b1f 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -55,7 +55,7 @@ static const struct fs_context_operations sysfs_fs_context_ops = { static int sysfs_init_fs_context(struct fs_context *fc) { struct kernfs_fs_context *kfc; - struct net *netns; + struct ns_common *ns; if (!(fc->sb_flags & SB_KERNMOUNT)) { if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) @@ -66,12 +66,14 @@ static int sysfs_init_fs_context(struct fs_context *fc) if (!kfc) return -ENOMEM; - kfc->ns_tag = netns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); + kfc->ns_tag = ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); kfc->root = sysfs_root; kfc->magic = SYSFS_MAGIC; fc->fs_private = kfc; fc->ops = &sysfs_fs_context_ops; - if (netns) { + if (ns) { + struct net *netns = to_net_ns(ns); + put_user_ns(fc->user_ns); fc->user_ns = get_user_ns(netns->user_ns); } @@ -81,7 +83,7 @@ static int sysfs_init_fs_context(struct fs_context *fc) static void sysfs_kill_sb(struct super_block *sb) { - void *ns = (void *)kernfs_super_ns(sb); + struct ns_common *ns = (struct ns_common *)kernfs_super_ns(sb); kernfs_kill_sb(sb); kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 5603530a1a520..5f9c05fb13940 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -121,7 +121,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn); void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, const char *name) { - const void *ns = NULL; + const struct ns_common *ns = NULL; /* * We don't own @target and it may be removed at any time. @@ -164,10 +164,11 @@ EXPORT_SYMBOL_GPL(sysfs_remove_link); * A helper function for the common rename symlink idiom. */ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, - const char *old, const char *new, const void *new_ns) + const char *old, const char *new, + const struct ns_common *new_ns) { struct kernfs_node *parent, *kn = NULL; - const void *old_ns = NULL; + const struct ns_common *old_ns = NULL; int result; if (!kobj) diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 8e012f25e1c06..f4583dcafcd1e 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -29,10 +29,10 @@ void sysfs_warn_dup(struct kernfs_node *parent, const char *name); */ int sysfs_add_file_mode_ns(struct kernfs_node *parent, const struct attribute *attr, umode_t amode, kuid_t uid, - kgid_t gid, const void *ns); + kgid_t gid, const struct ns_common *ns); int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent, const struct bin_attribute *battr, umode_t mode, size_t size, - kuid_t uid, kgid_t gid, const void *ns); + kuid_t uid, kgid_t gid, const struct ns_common *ns); /* * symlink.c |
