Linux ns 4. UTS Namespace 详解

目录

  • 1. 使用简介
    • 1.1 hostname
    • 1.2 domainname
    • 1.3 uname
  • 2. 代码分析
    • 2.1 copy_utsname()
    • 2.2 sethostname()
    • 2.3 gethostname()
    • 2.4 setdomainname()
    • 2.5 uname()
  • 参考文档:

1. 使用简介

UTS(UNIX Time Sharing) namespace 是最简单的一种 namespace。UTS 中主要包含了主机名(hostname)、域名(domainname)和一些版本信息:

struct uts_namespace {struct kref kref;struct new_utsname name;                // UTS 主要存储的信息struct user_namespace *user_ns;struct ucounts *ucounts;struct ns_common ns;
} __randomize_layout;↓struct new_utsname {char sysname[__NEW_UTS_LEN + 1];char nodename[__NEW_UTS_LEN + 1];       // host namechar release[__NEW_UTS_LEN + 1];char version[__NEW_UTS_LEN + 1];char machine[__NEW_UTS_LEN + 1];char domainname[__NEW_UTS_LEN + 1];     // domain name
};

其中主机名(hostname)、域名(domainname)是可以被修改的,其他只能被读取。UTS 的主要作用就是给用户态、内核态提供这些信息。

1.1 hostname

针对主机名(hostname),系统提供了 hostname 命令来进行读取和设置。下面举例说明其使用方法:

1、查看普通进程的 hostname :

pwl@ubuntu:~$ hostname
ubuntu                                      // 当前 hostname 为 ubuntu

2、创建一个新的 UTS namespace,并设置新的 hostname :

pwl@ubuntu:~$ sudo unshare --uts /bin/bash
[sudo] password for pwl: 
root@ubuntu:~# hostname
ubuntu
root@ubuntu:~# hostname test                
root@ubuntu:~# hostname
test                                        // 在新的 UTS namespace 中更改 hostname 为 test
pwl@ubuntu:~$ hostname
ubuntu                                      // 在旧的 UTS namespace 中的 hostname 仍然为 ubuntu

1.2 domainname

针对域名(domainname),系统提供了 domainname 命令来进行读取和设置。下面举例说明其使用方法:

1、查看普通进程的 hostname :

pwl@ubuntu:~$ domainname
(none)                                      // 当前 hostname 为空

2、创建一个新的 UTS namespace,并设置新的 hostname :

pwl@ubuntu:~$ domainname
(none)
pwl@ubuntu:~$ sudo unshare --uts /bin/bash
root@ubuntu:~# domainname
(none)
root@ubuntu:~# domainname test
root@ubuntu:~# domainname
test                                        // 在新的 UTS namespace 中更改 hostname 为 test
root@ubuntu:~# 
pwl@ubuntu:~$ domainname
(none)                                      // 在旧的 UTS namespace 中的 hostname 仍然为空

1.3 uname

针对 UTS 提供的其他信息,系统提供了 uname 命令来进行读取,且不支持配置。

pwl@ubuntu:~$ uname -a
Linux ubuntu 4.15.0-123-generic #126-Ubuntu SMP Wed Oct 21 09:40:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
pwl@ubuntu:~$ uname --help
Usage: uname [OPTION]...
Print certain system information.  With no OPTION, same as -s.-a, --all                print all information, in the following order,except omit -p and -i if unknown:-s, --kernel-name        print the kernel name-n, --nodename           print the network node hostname-r, --kernel-release     print the kernel release-v, --kernel-version     print the kernel version-m, --machine            print the machine hardware name-p, --processor          print the processor type (non-portable)-i, --hardware-platform  print the hardware platform (non-portable)-o, --operating-system   print the operating system--help     display this help and exit--version  output version information and exit

2. 代码分析

我们简单分析一下 UTS namespace 的创建代码,以及几个相关系统调用的代码。

2.1 copy_utsname()

在进程创建或者 unshare()/setns() 系统调用时,如果设置了 CLONE_NEWUTS 标志会调用 copy_utsname() 创建一个新的 UTS namespace。其中的核心是创建一个新的 struct uts_namespace 结构,首先把旧的 struct uts_namespace 树复制过来:

struct uts_namespace *copy_utsname(unsigned long flags,struct user_namespace *user_ns, struct uts_namespace *old_ns)
{struct uts_namespace *new_ns;BUG_ON(!old_ns);get_uts_ns(old_ns);if (!(flags & CLONE_NEWUTS))return old_ns;new_ns = clone_uts_ns(user_ns, old_ns);put_uts_ns(old_ns);return new_ns;
}↓static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns,struct uts_namespace *old_ns)
{struct uts_namespace *ns;struct ucounts *ucounts;int err;err = -ENOSPC;ucounts = inc_uts_namespaces(user_ns);if (!ucounts)goto fail;err = -ENOMEM;/* (1) 创建一个新的 uts namespace 结构 */ns = create_uts_ns();if (!ns)goto fail_dec;/* (2) 分配一个新的 namespace 编号 */err = ns_alloc_inum(&ns->ns);if (err)goto fail_free;ns->ucounts = ucounts;ns->ns.ops = &utsns_operations;down_read(&uts_sem);/* (3) 拷贝旧的 uts namespace 的内容 */memcpy(&ns->name, &old_ns->name, sizeof(ns->name));ns->user_ns = get_user_ns(user_ns);up_read(&uts_sem);return ns;fail_free:kfree(ns);
fail_dec:dec_uts_namespaces(ucounts);
fail:return ERR_PTR(err);
}

后面使用 sethostname()/setdomainname() 系统调用来独立的设置各个 uts namespace 下的 hostname/domainname。

2.2 sethostname()

SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
{int errno;char tmp[__NEW_UTS_LEN];if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))return -EPERM;if (len < 0 || len > __NEW_UTS_LEN)return -EINVAL;errno = -EFAULT;if (!copy_from_user(tmp, name, len)) {struct new_utsname *u;down_write(&uts_sem);u = utsname();/* (1) 设置当前 uts namespace 中的 uts_ns->name->nodename */memcpy(u->nodename, tmp, len);memset(u->nodename + len, 0, sizeof(u->nodename) - len);errno = 0;uts_proc_notify(UTS_PROC_HOSTNAME);up_write(&uts_sem);}return errno;
}↓static inline struct new_utsname *utsname(void)
{return ¤t->nsproxy->uts_ns->name;
}

2.3 gethostname()

SYSCALL_DEFINE2(gethostname, char __user *, name, int, len)
{int i;struct new_utsname *u;char tmp[__NEW_UTS_LEN + 1];if (len < 0)return -EINVAL;down_read(&uts_sem);u = utsname();i = 1 + strlen(u->nodename);if (i > len)i = len;/* (1) 获取当前 uts namespace 中的 uts_ns->name->nodename */memcpy(tmp, u->nodename, i);up_read(&uts_sem);if (copy_to_user(name, tmp, i))return -EFAULT;return 0;
}

2.4 setdomainname()

SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
{int errno;char tmp[__NEW_UTS_LEN];if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))return -EPERM;if (len < 0 || len > __NEW_UTS_LEN)return -EINVAL;errno = -EFAULT;if (!copy_from_user(tmp, name, len)) {struct new_utsname *u;down_write(&uts_sem);u = utsname();/* (1) 设置当前 uts namespace 中的 uts_ns->name->domainname */memcpy(u->domainname, tmp, len);memset(u->domainname + len, 0, sizeof(u->domainname) - len);errno = 0;uts_proc_notify(UTS_PROC_DOMAINNAME);up_write(&uts_sem);}return errno;
}

2.5 uname()

SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
{struct new_utsname tmp;down_read(&uts_sem);/* (1) 获取当前 uts namespace 中的所有信息 */memcpy(&tmp, utsname(), sizeof(tmp));up_read(&uts_sem);if (copy_to_user(name, &tmp, sizeof(tmp)))return -EFAULT;if (override_release(name->release, sizeof(name->release)))return -EFAULT;if (override_architecture(name))return -EFAULT;return 0;
}

参考文档:

1.UTS namespace详解
2.Linux内核命名空间之(4)uts namespace


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部