UNSHARE - Linux手册页

时间:2019-08-20 17:59:36  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-04-11

名称

unshare-取消流程执行上下文的关联

语法

#define _GNU_SOURCE
#include <sched.h>

int unshare(int flags);

说明

unshare()允许进程(或线程)取消其执行上下文的当前与其他进程(或线程)共享的部分的关联。当使用fork(2)或vfork(2)创建新进程时,执行上下文的一部分(例如mount命名空间)被隐式共享,而其他部分(例如虚拟内存)在创建文件时可能会被显式请求共享。进程或线程使用clone(2)。

unshare()的主要用途是允许进程控制其共享执行上下文,而无需创建新进程。

flags参数是一个位掩码,它指定应共享执行上下文的哪些部分。通过对以下常量中的零个或多个进行"或"运算来指定此参数:

CLONE_FILES
反转clone(2)CLONE_FILES标志的作用。取消共享文件描述符表,以便调用进程不再与任何其他进程共享其文件描述符。
CLONE_FS
反转clone(2)CLONE_FS标志的作用。取消共享文件系统属性,以便调用进程不再与任何其他进程共享其根目录(chroot(2)),当前目录(chdir(2))或umask(umask(2))属性。
CLONE_NEWCGROUP(since Linux 4.6)
该标志与clone(2)CLONE_NEWCGROUP标志具有相同的作用。取消共享cgroup命名空间。使用CLONE_NEWCGROUP需要CAP_SYS_ADMIN功能。
CLONE_NEWIPC(since Linux 2.6.19)
该标志与clone(2)CLONE_NEWIPC标志具有相同的作用。取消共享IPC名称空间,以便调用进程具有IPC名称空间的私有副本,该副本不会与任何其他进程共享。指定此标志也会自动暗示CLONE_SYSVSEM。使用CLONE_NEWIPC需要CAP_SYS_ADMIN功能。
CLONE_NEWNET(since Linux 2.6.24)
该标志与clone(2)CLONE_NEWNET标志具有相同的作用。取消共享网络名称空间,以便将调用进程移到新的网络名称空间中,该名称空间不会与任何以前存在的进程共享。使用CLONE_NEWNET需要CAP_SYS_ADMIN功能。
CLONE_NEWNS
该标志与clone(2)CLONE_NEWNS标志具有相同的作用。取消共享安装名称空间,以便调用进程具有其名称空间的私有副本,该副本不与任何其他进程共享。指定此标志也会自动暗示CLONE_FS。使用CLONE_NEWNS需要CAP_SYS_ADMIN功能。有关更多信息,请参见mount_namespaces(7)。
CLONE_NEWPID(since Linux 3.8)
该标志与clone(2)CLONE_NEWPID标志具有相同的作用。取消共享PID名称空间,以便调用进程为其子级创建一个新的PID名称空间,该名称空间不会与任何先前存在的进程共享。调用过程不会移到新的名称空间中。调用进程创建的第一个子进程将具有进程ID 1,并将在新名称空间中担当init(1)的角色。 CLONE_NEWPID也自动暗示CLONE_THREAD。使用CLONE_NEWPID需要CAP_SYS_ADMIN功能。有关更多信息,请参见pid_namespaces(7)。
CLONE_NEWTIME(since Linux 5.6)
取消共享时间名称空间,以便调用进程为其子级提供一个新的时间名称空间,该名称空间不会与任何先前存在的进程共享。调用过程不会移到新的名称空间中。使用CLONE_NEWTIME需要CAP_SYS_ADMIN功能。有关更多信息,请参见time_namespaces(7)。
CLONE_NEWUSER(since Linux 3.8)
该标志与clone(2)CLONE_NEWUSER标志具有相同的作用。取消共享用户名称空间,以便将调用进程移至新的用户名称空间,该名称空间不与任何先前存在的进程共享。就像由clone(2)使用CLONE_NEWUSER标志创建的子进程一样,调用者在新名称空间中获得了完整的功能集。
CLONE_NEWUSER要求调用进程未线程化;指定CLONE_NEWUSER会自动隐含CLONE_THREAD。从Linux 3.9开始,CLONE_NEWUSER也自动隐含CLONE_FS。 CLONE_NEWUSER要求在调用时将调用过程的用户ID和组ID映射到调用过程的用户名称空间中的用户ID和组ID。
有关用户名称空间的更多信息,请参见user_namespaces(7)。
CLONE_NEWUTS(since Linux 2.6.19)
该标志与clone(2)CLONE_NEWUTS标志具有相同的作用。取消共享UTS IPC名称空间,以便调用进程具有UTS名称空间的私有副本,该副本不会与任何其他进程共享。使用CLONE_NEWUTS需要CAP_SYS_ADMIN功能。
CLONE_SYSVSEM(since Linux 2.6.26)
该标志反转clone(2)CLONE_SYSVSEM标志的作用。取消共享系统V信号量调整(semadj)值,以便调用进程具有一个新的空semadj列表,该列表不与任何其他进程共享。如果这是最后一个引用该进程当前semadj列表的进程,则该列表中的调整将应用于相应的信号量,如semop(2)中所述。

另外,如果调用者是单线程的(即,它不与另一个进程或线程共享其地址空间),则可以在标志中指定CLONE_THREAD,CLONE_SIGHAND和CLONE_VM。在这种情况下,这些标志无效。 (还请注意,指定CLONE_THREAD自动表示CLONE_VM,指定CLONE_VM自动表示CLONE_SIGHAND。)如果进程是多线程的,则使用这些标志将导致错误。

如果将标志指定为零,则unshare()为无操作;否则为false。不会对调用过程的执行上下文进行任何更改。

返回值

成功后,返回零。失败时,将返回-1并将errno设置为指示错误。

错误说明

EINVAL
在标志中指定了无效的位。
EINVAL
在标志中指定了CLONE_THREAD,CLONE_SIGHAND或CLONE_VM,并且调用方是多线程的。
EINVAL
在标志中指定了CLONE_NEWIPC,但未使用CONFIG_SYSVIPC和CONFIG_IPC_NS选项配置内核。
EINVAL
在标志中指定了CLONE_NEWNET,但未使用CONFIG_NET_NS选项配置内核。
EINVAL
在标志中指定了CLONE_NEWPID,但未使用CONFIG_PID_NS选项配置内核。
EINVAL
在标志中指定了CLONE_NEWUSER,但是未使用CONFIG_USER_NS选项配置内核。
EINVAL
在标志中指定了CLONE_NEWUTS,但未使用CONFIG_UTS_NS选项配置内核。
EINVAL
在标志中指定了CLONE_NEWPID,但是该进程先前已使用CLONE_NEWPID标志调用了unshare()。
ENOMEM
无法分配足够的内存来复制需要取消共享的调用方上下文部分。
ENOSPC(since Linux 3.7)
CLONE_NEWPID是在标志中指定的,但将超出PID名称空间嵌套深度的限制;参见pid_namespaces(7)。
ENOSPC(since Linux 4.9; beforehand EUSERS)
CLONE_NEWUSER是在标志中指定的,并且该调用将导致超出嵌套用户名称空间数量的限制。参见user_namespaces(7)。
从Linux 3.11到Linux 4.8,在这种情况下诊断的错误是EUSERS。
ENOSPC(since Linux 4.9)
标志中的值之一指定了新用户名称空间的创建,但是这样做将导致超出/ proc / sys / user中相应文件定义的限制。有关更多详细信息,请参见namespaces(7)。
EPERM
调用过程没有此操作所需的特权。
EPERM
在标志中指定了CLONE_NEWUSER,但是调用者的有效用户ID或有效组ID在父名称空间中没有映射(请参阅user_namespaces(7))。
EPERM(since Linux 3.9)
在标记中指定了CLONE_NEWUSER,并且调用者位于chroot环境中(即,调用者的根目录与它所在的安装名称空间的根目录不匹配)。
EUSERS(from Linux 3.11 to Linux 4.8)
在标志中指定了CLONE_NEWUSER,并且将超出嵌套用户名称空间数量的限制。请参阅上面有关ENOSPC错误的讨论。

版本

unshare()系统调用已添加到内核2.6.16中的Linux中。

遵循规范

unshare()系统调用是特定于Linux的。

备注

并非所有使用克隆(2)创建新流程时可以共享的流程属性都可以使用unshare()取消共享。特别是,从内核3.8开始,unshare()不会实现使CLONE_SIGHAND,CLONE_THREAD或CLONE_VM的效果相反的标志。如果需要,将来可以添加此类功能。

示例

下面的程序提供了unshare(1)命令的简单实现,该命令取消共享一个或多个名称空间,并执行其命令行参数中提供的命令。这是使用此程序的示例,在新的安装命名空间中运行外壳,并验证原始外壳和新的外壳在单独的安装命名空间中:

$ readlink /proc/$$/ns/mnt
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash
# readlink /proc/$$/ns/mnt
mnt:[4026532325]

两个readlink(1)命令的不同输出表明,两个外壳程序位于不同的安装名称空间中。

Program source

/* unshare.c

   A simple implementation of the unshare(1) command: unshare
   namespaces and execute a command.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

/* A simple error-handling function: print an error message based
   on the value in aqerrnoaq and terminate the calling process */

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

static void
usage(char *pname)
{
    fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname);
    fprintf(stderr, "Options can be:\n");
    fprintf(stderr, "    -C   unshare cgroup namespace\n");
    fprintf(stderr, "    -i   unshare IPC namespace\n");
    fprintf(stderr, "    -m   unshare mount namespace\n");
    fprintf(stderr, "    -n   unshare network namespace\n");
    fprintf(stderr, "    -p   unshare PID namespace\n");
    fprintf(stderr, "    -t   unshare time namespace\n");
    fprintf(stderr, "    -u   unshare UTS namespace\n");
    fprintf(stderr, "    -U   unshare user namespace\n");
    exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
    int flags, opt;

    flags = 0;

    while ((opt = getopt(argc, argv, "CimnptuU")) != -1) {
        switch (opt) {
        case aqCaq: flags |= CLONE_NEWCGROUP;      break;
        case aqiaq: flags |= CLONE_NEWIPC;        break;
        case aqmaq: flags |= CLONE_NEWNS;         break;
        case aqnaq: flags |= CLONE_NEWNET;        break;
        case aqpaq: flags |= CLONE_NEWPID;        break;
        case aqtaq: flags |= CLONE_NEWTIME;        break;
        case aquaq: flags |= CLONE_NEWUTS;        break;
        case aqUaq: flags |= CLONE_NEWUSER;       break;
        default:  usage(argv[0]);
        }
    }

    if (optind >= argc)
        usage(argv[0]);

    if (unshare(flags) == -1)
        errExit("unshare");

    execvp(argv[optind], &argv[optind]);
    errExit("execvp");
}

另外参见

unshare(1),clone(2),fork(2),kcmp(2),setns(2),vfork(2),名称空间(7)

Linux内核源代码树中的Documentation / userspace-api / unshare.rst(或Linux 4.12之前的Documentation / unshare.txt)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/