summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-04-01 12:15:58 +0200
committerChristian Brauner <brauner@kernel.org>2026-04-09 14:36:52 +0200
commite3b2cf6e5dba416a03152f299d99982dfe1e861d (patch)
treed10833a41819fac2d0c066bd80def58a36453228 /fs
parent07712db80857d5d09ae08f3df85a708ecfc3b61f (diff)
downloadlinux-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.c30
-rw-r--r--fs/kernfs/file.c2
-rw-r--r--fs/kernfs/kernfs-internal.h2
-rw-r--r--fs/kernfs/mount.c2
-rw-r--r--fs/nfs/sysfs.c16
-rw-r--r--fs/sysfs/dir.c6
-rw-r--r--fs/sysfs/file.c8
-rw-r--r--fs/sysfs/mount.c10
-rw-r--r--fs/sysfs/symlink.c7
-rw-r--r--fs/sysfs/sysfs.h4
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