When the UTS namespace gets initialized, a directory called 'uts' is added to namespacesfs. This directory represents the main UTS namespace and also serves as a trunk (parent) of all other UTS namespaces. Every time when a new UTS namespace is created a corresponding directory is added to 'namespacefs/uts/'. The 'inum' of the new namespace gives the name of its directory. When a UTS namespace is destroyed the corresponding directory is removed. Each directory contains a file called 'uname' that can be used to get the unique data fields of the uts namespaces(sysname, nodename, ...). Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@xxxxxxxxx> --- fs/namespacefs/inode.c | 57 +++++++++++++++++++++++++++++++++++++ include/linux/namespacefs.h | 13 +++++++++ kernel/utsname.c | 9 ++++++ 3 files changed, 79 insertions(+) diff --git a/fs/namespacefs/inode.c b/fs/namespacefs/inode.c index 55d71733164c..4b661bdd4d9c 100644 --- a/fs/namespacefs/inode.c +++ b/fs/namespacefs/inode.c @@ -14,6 +14,7 @@ #include <linux/proc_ns.h> #include <linux/seq_file.h> #include <linux/pid_namespace.h> +#include <linux/utsname.h> static struct vfsmount *namespacefs_mount; static int namespacefs_mount_count; @@ -309,6 +310,58 @@ void namespacefs_remove_pid_ns_dir(struct pid_namespace *ns) namespacefs_remove_dir(ns->ns.dentry); } +#define _UNAME_N_FIELDS 6 +#define _UNAME_MAX_LEN ((__NEW_UTS_LEN + 1) * _UNAME_N_FIELDS) + +static ssize_t uts_ns_read(struct file *file, char __user *ubuf, + size_t count, loff_t *pos) +{ + struct new_utsname *name = file->private_data; + char buff[_UNAME_MAX_LEN + 1]; + int n; + + n = snprintf(buff, _UNAME_MAX_LEN + 1, + "%s %s %s %s %s %s\n", + name->sysname, + name->nodename, + name->release, + name->version, + name->machine, + name->domainname); + + return simple_read_from_buffer(ubuf, count, pos, buff, n); +} + +static const struct file_operations uts_fops = { + .open = simple_open, + .read = uts_ns_read, + .llseek = default_llseek, +}; + +int namespacefs_create_uts_ns_dir(struct uts_namespace *ns) +{ + struct dentry *dentry; + int err; + + err = create_inode_dir(&ns->ns, init_uts_ns.ns.dentry, ns->user_ns); + if (err) + return err; + + dentry = namespacefs_create_file("uname", ns->ns.dentry, ns->user_ns, + &uts_fops, &ns->name); + if (IS_ERR(dentry)) { + dput(ns->ns.dentry); + return PTR_ERR(dentry); + } + + return 0; +} + +void namespacefs_remove_uts_ns_dir(struct uts_namespace *ns) +{ + namespacefs_remove_dir(ns->ns.dentry); +} + static int add_ns_dentry(struct ns_common *ns) { struct dentry *dentry = @@ -340,6 +393,10 @@ static int __init namespacefs_init(void) if (err) goto unreg; + err = add_ns_dentry(&init_uts_ns.ns); + if (err) + goto unreg; + return 0; unreg: diff --git a/include/linux/namespacefs.h b/include/linux/namespacefs.h index f41499a7635a..3815a7bbeb1c 100644 --- a/include/linux/namespacefs.h +++ b/include/linux/namespacefs.h @@ -21,6 +21,8 @@ namespacefs_create_dir(const char *name, struct dentry *parent, void namespacefs_remove_dir(struct dentry *dentry); int namespacefs_create_pid_ns_dir(struct pid_namespace *ns); void namespacefs_remove_pid_ns_dir(struct pid_namespace *ns); +int namespacefs_create_uts_ns_dir(struct uts_namespace *ns); +void namespacefs_remove_uts_ns_dir(struct uts_namespace *ns); #else @@ -55,6 +57,17 @@ namespacefs_remove_pid_ns_dir(struct pid_namespace *ns) { } +static inline int +namespacefs_create_uts_ns_dir(struct uts_namespace *ns) +{ + return 0; +} + +static inline void +namespacefs_remove_uts_ns_dir(struct uts_namespace *ns) +{ +} + #endif /* CONFIG_NAMESPACE_FS */ #endif diff --git a/kernel/utsname.c b/kernel/utsname.c index b1ac3ca870f2..d44b307cffdc 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/cred.h> #include <linux/user_namespace.h> +#include <linux/namespacefs.h> #include <linux/proc_ns.h> #include <linux/sched/task.h> @@ -70,8 +71,15 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); ns->user_ns = get_user_ns(user_ns); up_read(&uts_sem); + + err = namespacefs_create_uts_ns_dir(ns); + if (err) + goto fail_free_inum; + return ns; +fail_free_inum: + ns_free_inum(&ns->ns); fail_free: kmem_cache_free(uts_ns_cache, ns); fail_dec: @@ -105,6 +113,7 @@ struct uts_namespace *copy_utsname(unsigned long flags, void free_uts_ns(struct uts_namespace *ns) { + namespacefs_remove_uts_ns_dir(ns); dec_uts_namespaces(ns->ucounts); put_user_ns(ns->user_ns); ns_free_inum(&ns->ns); -- 2.33.1