C-standardbibliotek (libc, -lc)
#define _GNU_SOURCE
#include <sched.h>
int unshare(int flag);
unshare() tillader at en proces (eller tråd)
adskiller dele af dens afviklingskontekst, der aktuelt deles med andre
processer (eller tråde). Dele af afviklingskonteksten, såsom
monteringsnavnerummet, er delt implicit når en ny proces oprettes via
fork(2) eller vfork(2), mens andre dele, såsom virtuel
hukommelse, kan deles ved eksplicit anmodning, når en proces eller
tråd oprettes via clone(2).
Hovedbrugen af unshare() er at tillade en proces at
kontrollere sin delte afviklingskontekst uden at oprette en ny proces.
Argumentet flag er en bit-maske, der angiver hvilke dele af
afviklingskonteksten, der ikke skal deles. Dette argument er angivet af
ORing together zero eller flere af de følgende konstanter:
- CLONE_FILES
- Vend effekten om for clone(2) CLONE_FILES-flaget. Fjern
deling for fildeskriptortabellen, så at den kaldende proces ikke
længere deler sine fildeskriptorer med enhver anden proces.
- CLONE_FS
- Vend effekten om for clone(2) CLONE_FS-flaget. Fjern deling
for filsystemattributter, så at den kaldende proces ikke
længere deler sin rodmappe (chroot(2)), nuværende
mappe (chdir(2)), eller umask-attributter (umask(2)) med
enhver anden proces.
- CLONE_NEWCGROUP
(siden Linux 4.6)
- Dette flag har den samme effekt som clone(2)
CLONE_NEWCGROUP-flaget. Fjern deling for cgroup-navnerummet. Brug
af CLONE_NEWCGROUP kræver funktionaliteten
CAP_SYS_ADMIN.
- CLONE_NEWIPC
(siden Linux 2.6.19)
- Dette flag har den samme effekt som clone(2)
CLONE_NEWIPC-flaget. Fjern deling af IPC-navnerummet, så at
den kaldende proces har en privat kopi af IPC-navnerummet, der ikke er
delt med nogen anden proces. Angivelse af dette flag forudsætter
automatisk også CLONE_SYSVSEM. Brug af CLONE_NEWIPC
kræver funktionaliteten CAP_SYS_ADMIN.
- CLONE_NEWNET
(siden Linux 2.6.24)
- Dette flag har den samme effekt som clone(2)
CLONE_NEWNET-flaget. Fjern deling for netværksnavnerummet,
så den kaldende proces flyttes til et nyt netværksnavnerum,
der ikke er delg med en eventuel tidligere proces. Brug af
CLONE_NEWNET kræver funktionaliteten
CAP_SYS_ADMIN.
- CLONE_NEWNS
- Dette flag har den samme effekt som clone(2)
CLONE_NEWNS-flaget. Fjern deling for monteringsnavnerummet,
så den kaldende proces har en privat kopi af sit navnerum, der ikke
deles med nogen anden proces. Angivelse af dette flag fortudsætter
automatisk også CLONE_FS. Brug af CLONE_NEWNS
kræver funktionaliteten CAP_SYS_ADMIN. For yderligere
information se mount_namespaces(7).
- CLONE_NEWPID
(siden Linux 3.8)
- Dette flag har den samme effekt som clone(2)
CLONE_NEWPID-flaget. Fjern deling for PID-navnerummet, så at
den kaldende proces har et nyt PID-navnerum for sine underprocesser, der
ikke deles med en eventuel tidligere proces. Den kaldende proces bliver
ikke flyttet ind i det nye navnerum. Den første underproces
oprettet af den kaldende proces vil have proces-id nr 1 og vil antage
rollen af init(1) i det nye navnerum. CLONE_NEWPID
forudsætter automatisk også CLONE_THREAD. Brug af
CLONE_NEWPID kræver funktionaliteten CAP_SYS_ADMIN.
For yderligere information, se pid_namespaces(7).
- CLONE_NEWTIME
(siden Linux 5.6)
- Fjern deling for tidsnavnerummet, så at den kaldende proces har et
nyt tidsnavnerum for sine underprocesser, der ikke deles med en eventuel
tidligere proces. Den kaldende proces flyttes ikke ind i det nye
navnerum. Brug af CLONE_NEWTIME kræver funktionaliteten
CAP_SYS_ADMIN. For yderligere information, se
time_namespaces(7).
- CLONE_NEWUSER
(siden Linux 3.8)
- Dette flag har den samme effekt som clone(2)
CLONE_NEWUSER-flaget. Fjern deling for brugernavnerummet, så
at den kaldende proces flyttes ind i et nyt brugernavnerum, der ikke deles
med en eventuel tidligere proces. Som med underprocessen oprettet af
clone(2) med CLONE_NEWUSER-flaget får kalderen et
fuldt sæt af funktionaliteter i det nye navnerum.
- CLONE_NEWUSER kræver at den kaldende proces ikke er
trådet; angivelse af CLONE_NEWUSER forudsætter
automatisk CLONE_THREAD. Da Linux 3.9, CLONE_NEWUSER
også automatisk forudsætter CLONE_FS.
CLONE_NEWUSER kræver at bruger-id'et og gruppe-id'et for den
kaldende proces oversættes til bruger-id'erne og gruppe-id'erne i
brugerens navnerum for den kaldende proces på tidspunktet for
kaldet.
- For yderligere information om brugernavnerum, se
user_namespaces(7).
- CLONE_NEWUTS
(siden Linux 2.6.19)
- Dette flag har den samme effekt som clone(2)
CLONE_NEWUTS-flaget. Fjern deling af UTS IPC-navnerummet, så
at den kaldende proces har en privat kopi af UTS-navnerummet, der ikke
deles med nogen anden proces. Brug af CLONE_NEWUTS kræver
funktionaliteten CAP_SYS_ADMIN.
- CLONE_SYSVSEM
(siden Linux 2.6.26)
- Dette flag vender effekten af clone(2) CLONE_SYSVSEM-flaget
om. Fjern deling for System V sempahore-justeringsværdier
(semadj), så at den kaldende proces har en ny tom
semadj-liste, der ikke deles med nogen anden proces. Hvis dette er
den sidste proces, der har en refernece til processens nuværende
semadj-liste, så anvendes justeringerne i den liste til de
tilsvarende semaforer, som beskrevet i semop(2).
Derudover kan CLONE_THREAD, CLONE_SIGHAND og
CLONE_VM angives i flag hvis kalderen er en enkelt tråd
(dvs. deler ikke sit adresserum med en anden proces eller tråd). I
dette tilfælde har disse flag ingen effekt. (Bemærk
også at angivelse af CLONE_THREAD automatisk
forudsætter CLONE_VM, og angivelse af CLONE_VM
automatisk forudsætter CLONE_SIGHAND). Hvis processen har
flere tråde så medfører brug af disse flag en fejl.
Hvis flag er angivet som nul, så er unshare()
en no-op; ingen ændringer laves til den kaldende proces
afviklingskontekst.
Ved succes returneres nul. Ved fejl returneres -1 og errno
er angivet for at indikere fejlen.
- EINVAL
- En ugyldig bit var angivet i flag.
- EINVAL
- CLONE_THREAD, CLONE_SIGHAND eller CLONE_VM var
angivet i flag, og kalderen er flertrådet.
- EINVAL
- CLONE_NEWIPC var angivet i flag, men kernen var ikke
konfigureret med tilvalgene CONFIG_SYSVIPC og
CONFIG_IPC_NS.
- EINVAL
- CLONE_NEWNET var angivet i flag, men kernen var ikke
konfigureret med tilvalget CONFIG_NET_NS.
- EINVAL
- CLONE_NEWPID var angivet i flag, men kernen var ikke
konfigureret med tilvalget CONFIG_PID_NS.
- EINVAL
- CLONE_NEWUSER var angivet i flag, men kernen var ikke
konfigureret med tilvalget CONFIG_USER_NS.
- EINVAL
- CLONE_NEWUTS var angivet i flag, men kernen var ikke
konfigureret med tilvalget CONFIG_UTS_NS.
- EINVAL
- CLONE_NEWPID var angivet i flag, men processen har tidligere
kaldt unshare() med flaget CLONE_NEWPID.
- ENOMEM
- Kan ikke allokere tilstrækkelig hukommelse til at kopiere dele af
kalderens kontekst, der ikke længere skal deles.
- ENOSPC (siden Linux
3.7)
- CLONE_NEWPID var angivet i flag, men begrænsningen på
indlejringsdybden for PID-navnerum ville være overskredet; se
pid_namespaces(7).
- ENOSPC (siden
Linux 4.9; tidligere EUSERS)
- CLONE_NEWUSER var angivet i flag, og kaldet ville
medføre at begrænsningen på antallet af indlejrede
brugernavnerum ville blive overskredt. Se user_namespaces(7).
- Fra Linux 3.11 til Linux 4.8, var fejlen diagnosticeret i dette
tilfælde EUSERS.
- ENOSPC (siden
Linux 4.9)
- En af værdierne i flag angav oprettelsen af et nyt
brugernavnerum, men dette ville have medført at
begrænsningen defineret af den tilsvarende fil i
/proc/sys/user ville blive overskredet. For yderligere information,
se namespaces(7).
- EPERM
- Den kaldende proces havde ikke de krævede privilegier for denne
operation.
- EPERM
- CLONE_NEWUSER var angivet i flag, men enten har det
effektive bruger-id eller det effektive gruppe-id for kalderen ikke en
oversættelse i overnavnerummet (se user_namespaces(7)).
- EPERM (siden
Linux 3.9)
- CLONE_NEWUSER var angivet i flag og kalderen er i et
chroot-miljø (dvs. kalderens rodmappe matcher ikke rodmappen for
monteringsnavnerummet hvor det befinder sig).
- EUSERS (fra Linux
3.11 til Linux 4.8)
- CLONE_NEWUSER var angivet i flag, og begrænsningen
på antallet af indlejrede brugernavnerum er for højt. Se
diskussionen for ENOSPC-fejlen ovenfor.
Ikke alle af processens attributter, der kan deles når en
ny proces oprettes via clone(2), kan få fjernet deling via
unshare(). Specielt fra og med kernen 3.8 implementerer
unshare() ikke flag, der vender effekten af CLONE_SIGHAND,
CLONE_THREAD eller CLONE_VM om. Sådan funktionalitet
kan blive tilføjet i fremtiden, hvis krævet.
Oprettelse af alle slags navnerume, undtagen brugernavnerum,
kræver funktionaliteten CAP_SYS_ADMIN. Da oprettelsen af et
brugernavnerum automatisk giver et fuld sæt af funktionalitet,
kræver oprettelse af både et brugernavnerum og andre typer af
navnerum i det samme unshare()-kald ikke
CAP_SYS_ADMIN-funktionalitet i det oprindelige navnerum.
Programmet nedenfor tilbyder en simpel implementering af
kommandoen unshare(1), der fjerner deling for et eller flere navnerum
og afvikler kommandoen angivet i sine kommandolinjeargumenter. Her er et
eksempel på brug af dette program, der afvikles i en skal i et nyt
monteringsnavnerum, og verificerer at den oprindelige skal og den nye skal
er i separate monteringsnavnerum:
$ readlink /proc/$$/ns/mnt;
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash;
# readlink /proc/$$/ns/mnt;
mnt:[4026532325]
De forskellige resultater for de to readlink(1)-kommandoer
viser, at de to skaller er i forskellige monteringsnavnerum.
/* unshare.c
En simpel implementering af kommandoen unshare(1): unshare
navnerum og afvikl en kommando.
*/
#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void
usage(char *pname)
{
fprintf(stderr, "Brug: %s [tilvalg] program [arg...]\n", pnavn);
fprintf(stderr, "Tilvalg kan være:\n");
fprintf(stderr, " -C unshare cgroup-navnerum\n");
fprintf(stderr, " -i unshare IPC-navnerum\n");
fprintf(stderr, " -m unshare mount-navnerum\n");
fprintf(stderr, " -n unshare network-navnerum\n");
fprintf(stderr, " -p unshare PID-navnerum\n");
fprintf(stderr, " -t unshare time-navnerum\n");
fprintf(stderr, " -u unshare UTS-navnerum\n");
fprintf(stderr, " -U unshare user-navnerum\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 'C': flags |= CLONE_NEWCGROUP; break;
case 'i': flags |= CLONE_NEWIPC; break;
case 'm': flags |= CLONE_NEWNS; break;
case 'n': flags |= CLONE_NEWNET; break;
case 'p': flags |= CLONE_NEWPID; break;
case 't': flags |= CLONE_NEWTIME; break;
case 'u': flags |= CLONE_NEWUTS; break;
case 'U': flags |= CLONE_NEWUSER; break;
default: usage(argv[0]);
}
}
if (optind >= argc)
usage(argv[0]);
if (unshare(flags) == -1)
err(EXIT_FAILURE, "unshare");
execvp(argv[optind], &argv[optind]);
err(EXIT_FAILURE, "execvp");
}