user_namespaces(7) Miscellaneous Information Manual user_namespaces(7) NOM user_namespaces -- Presentation des espaces de noms utilisateur sous Linux DESCRIPTION Pour une presentation generale des espaces de noms, consultez namespaces(7). Les espaces de noms utilisateur isolent les identifiants et attributs lies a la securite, en particulier les identifiants d'utilisateurs et de groupes (consultez credentials(7)), le repertoire racine, les clefs (consultez keyctl(2)) et les capacites (consultez capabilities(7)). Les identifiants d'utilisateur et de groupe d'un processus peuvent etre differents selon que l'on se trouve a l'interieur ou a l'exterieur d'un espace de noms utilisateur. Un processus peut notamment avoir un identifiant sans privilege particulier en dehors d'un espace de noms et avoir l'identifiant 0 a l'interieur d'un espace de noms. Autrement dit, le processus dispose de tous les privileges pour des operations effectuees dans l'espace de noms, tandis qu'il n'en a aucun pour les operations realisees en dehors de l'espace de noms utilisateur. Espaces de noms imbriques, appartenance aux espaces de noms Les espaces de noms utilisateur peuvent etre imbriques. Cela signifie que chaque espace de noms utilisateur -- a l'exception de l'espace de noms initial (<< root >>) -- a un espace de noms parent et peut avoir eventuellement un ou plusieurs espaces de noms utilisateur enfant. L'espace de noms utilisateur parent est l'espace de noms du processus qui a cree l'espace de noms utilisateur au moyen de unshare(2) ou de clone(2) invoque avec l'attribut CLONE_NEWUSER. Le noyau impose (a partir de Linux 3.11) une limite de 32 niveaux d'imbrication pour les espaces de noms utilisateur. Si un appel a unshare(2) ou a clone(2) provoque le depassement de cette limite, la commande echoue en renvoyant l'erreur EUSERS. Chaque processus est membre d'exactement un espace de noms utilisateur. Un processus cree par fork(2) ou par clone(2) sans l'attribut CLONE_NEWUSER est membre du meme espace de noms que son processus parent. Un processus mono-threade peut rejoindre un autre espace de noms en utilisant setns(2) s'il dispose de la capacite CAP_SYS_ADMIN dans cet espace de noms ; cette action lui octroie un ensemble de capacites dans cet espace de noms. Un appel a clone(2) ou a unshare(2) avec l'attribut CLONE_NEWUSER place le nouveau processus enfant (pour clone(2)) ou l'appelant (pour unshare(2)) dans le nouvel espace de noms utilisateur cree par l'appel. The NS_GET_PARENT ioctl(2) operation can be used to discover the parental relationship between user namespaces; see ioctl_nsfs(2). A task that changes one of its effective IDs will have its dumpability reset to the value in /proc/sys/fs/suid_dumpable. This may affect the ownership of proc files of child processes and may thus cause the parent to lack the permissions to write to mapping files of child processes running in a new user namespace. In such cases making the parent process dumpable, using PR_SET_DUMPABLE in a call to prctl(2), before creating a child process in a new user namespace may rectify this problem. See prctl(2) and proc(5) for details on how ownership is affected. Capacites Le processus enfant cree par clone(2) avec l'attribut CLONE_NEWUSER s'initialise avec un nouvel ensemble de capacites dans le nouvel espace de noms utilisateur. De meme, un processus qui cree un nouvel espace de noms au moyen de unshare(2) ou qui rejoint un espace de noms existant a l'aide de setns(2) recoit un ensemble de capacites dans cet espace de noms. D'un autre cote, le processus n'a aucune capacite dans le parent (dans le cas de clone(2)) ou dans le precedent espace de noms utilisateur (dans le cas de unshare(2) et setns(2)), meme si le nouvel espace de noms utilisateur est cree ou rejoint par l'utilisateur racine (c'est-a-dire un processus avec l'ID utilisateur 0 dans l'espace de noms racine). Remarquez qu'un appel a execve(2) declenche la reevaluation des capacites selon la methode habituelle (consultez capabilities(7)), de sorte que le processus perdra ses capacites, sauf si son identifiant utilisateur vaut 0 dans l'espace de noms ou si le fichier executable a un masque de capacites heritable non vide. Pour en savoir plus, consultez les commentaires sur le mappage entre utilisateurs et groupes ci-dessous. Un appel a clone(2) ou unshare(2) en utilisant l'attribut CLONE_NEWUSER ou un appel a setns(2) qui deplace l'appelant dans d'autres jeux d'espaces de noms utilisateur positionne les indicateurs << securebits >> (consultez capabilities(7)) a leurs valeurs par defaut (tous les indicateurs desactives) dans l'enfant (pour clone(2)) ou l'appelant (pour unshare(2) ou setns(2)). Remarquez que parce que l'appelant n'a plus de capacites dans son espace de noms utilisateur apres un appel a setns(2), il n'est pas possible a un processus de reinitialiser ses indicateurs << securebits >> tout en conservant son appartenance a un espace de noms utilisateur en utilisant une paire d'appels setns(2) pour se deplacer vers un autre espace de noms utilisateur et ensuite retourner vers son espace de noms utilisateur original. Les regles pour determiner si un processus a ou n'a pas de capacites dans un espace de noms utilisateur particulier sont comme suit : - Un processus dispose d'une capacite dans un espace de noms utilisateur s'il est membre de cet espace de noms et si cette capacite est activee dans son jeu de capacites. Un processus peut obtenir une nouvelle capacite dans son jeu de capacites de plusieurs facons. Il peut, par exemple, executer un programme set-user-ID ou un executable avec des capacites de fichier associees. Il peut egalement obtenir des capacites a l'aide de l'action de clone(2), unshare(2) ou setns(2) comme indique precedemment. - Si un processus dispose d'une capacite dans un espace de noms utilisateur, alors il a cette meme capacite dans tous les espaces de noms enfant (et les espaces descendants supprimes). - When a user namespace is created, the kernel records the effective user ID of the creating process as being the "owner" of the namespace. A process that resides in the parent of the user namespace and whose effective user ID matches the owner of the namespace has all capabilities in the namespace. By virtue of the previous rule, this means that the process has all capabilities in all further removed descendant user namespaces as well. The NS_GET_OWNER_UID ioctl(2) operation can be used to discover the user ID of the owner of the namespace; see ioctl_nsfs(2). Effet des capacites a l'interieur d'un espace de noms utilisateur Un processus qui possede des capacites dans un espace de noms utilisateur a la possibilite d'effectuer des operations (necessitant des privileges) seulement sur les ressources gerees par cet espace de noms. En d'autres mots, avoir une capacite dans un espace de noms permet a un processus de realiser des operations privilegiees sur des ressources gerees par des espaces de noms (non utilisateur) possedes par (associes avec) l'espace de noms utilisateur (consultez la sous-section suivante). D'un autre cote, il existe beaucoup d'operations privilegiees affectant les ressources qui ne sont associees a aucun type d'espace de noms, par exemple, modifier l'heure du systeme (c'est-a-dire le calendrier) (regi par CAP_SYS_TIME), charger un module du noyau (regi par CAP_SYS_MODULE) et creer un peripherique (regi par CAP_MKNOD). Seuls les processus avec privileges dans l'espace de noms initial peuvent realiser de telles operations. Avoir CAP_SYS_ADMIN dans un espace de noms utilisateur qui possede un espace de noms de montage de processus permet a ce processus de creer des remontages (bind mount) et de monter les types suivants de systeme de fichiers : - /proc/ (depuis Linux 3.8) - /sys (depuis Linux 3.8) - devpts (depuis Linux 3.9) - tmpfs(5) (depuis Linux 3.9) - ramfs (depuis Linux 3.9) - mqueue (depuis Linux 3.9) - bpf (depuis Linux 4.4) - overlayfs (depuis Linux 5.11) Holding CAP_SYS_ADMIN within the user namespace that owns a process's cgroup namespace allows (since Linux 4.6) that process to the mount the cgroup version 2 filesystem and cgroup version 1 named hierarchies (i.e., cgroup filesystems mounted with the "none,name=" option). Avoir CAP_SYS_ADMIN dans un espace de noms utilisateur qui possede un espace de noms PID de processus permet (depuis Linux 3.8) a ce processus de monter des systemes de fichiers /proc. Remarquez cependant que le montage de systemes de fichiers bases sur les blocs peut etre realise seulement par un processus ayant CAP_SYS_ADMIN dans l'espace de noms utilisateur initial. Liens entre les espaces de noms utilisateur et les autres espaces de noms A partir de Linux 3.8, les processus sans privileges peuvent creer des espaces de noms utilisateur et les autres espaces de noms peuvent etre crees avec simplement la capacite CAP_SYS_ADMIN dans l'espace de noms utilisateur de l'appelant. Lorsqu'un espace de noms autre qu'utilisateur est cree, il appartient a l'espace de noms utilisateur auquel appartenait a ce moment la le processus a l'origine de la creation de cet espace de noms. Les operations privilegiees sur des ressources regies par un espace de noms non utilisateur necessitent que le processus aient les capacites requises dans l'espace de noms utilisateur qui possede l'espace de noms non utilisateur. Si CLONE_NEWUSER est indique en complement de l'attribut CLONE_NEW* lors d'un appel simple a clone(2) ou a unshare(2), l'espace de noms utilisateur est garanti d'etre cree en premier. Cela donne des privileges a l'enfant (dans le cas de clone(2)) ou a l'appelant (dans le cas de unshare(2)) dans les espaces de noms subsistants crees par l'appel. Il est ainsi possible a un appelant sans privileges d'indiquer ce jeu d'attributs. Lorsqu'un nouvel espace de noms (autre qu'un espace de noms utilisateur) est cree a l'aide de clone(2) ou unshare(2), le noyau enregistre l'espace de noms utilisateur du processus createur comme le proprietaire du nouvel espace de noms. (Cette association ne peut pas etre changee). Lorsqu'un processus du nouvel espace de noms effectue ensuite une operation privilegiee sur une ressource globale isolee par l'espace de noms, les verifications de permissions sont realisees en fonction des capacites du processus dans l'espace de noms utilisateur que le noyau a associe au nouvel espace de noms. Par exemple, supposons qu'un processus essaie de modifier le nom d'hote (sethostname(2)), une ressource regie par l'espace de noms UTS. Dans ce cas le noyau determinera quel espace de noms utilisateur possede l'espace de noms UTS du processus et verifiera si le processus a la capacite requise (CAP_SYS_ADMIN) dans cet espace de noms utilisateur. The NS_GET_USERNS ioctl(2) operation can be used to discover the user namespace that owns a nonuser namespace; see ioctl_nsfs(2). Correspondance des identifiants d'utilisateur et de groupe : uid_map et gid_map Lorsqu'un espace de noms utilisateur est cree, il s'initialise sans etablir de mappage entre ses identifiants utilisateurs (identifiants de groupes) et ceux de l'espace de noms parent. Les fichiers /proc/pid/uid_map et /proc/pid/gid_map presentent (a partir de Linux 3.5) le mappage entre identifiants utilisateur et groupe a l'interieur de l'espace de noms utilisateur pour le processus pid. Ces fichiers peuvent etre consultes pour prendre connaissance des mappages dans un espace de noms utilisateur et peuvent etre modifies (une seule fois) pour definir les mappages. Les paragraphes suivants decrivent uid_map en details. gid_map est parfaitement analogue, chaque instance de << identifiant utilisateur >> etant remplacee par << identifiant groupe >>. Le fichier uid_map presente le mappage entre les identifiants utilisateur de l'espace de noms utilisateur du processus pid et ceux de l'espace de noms utilisateur du processus qui a ouvert uid_map (mais consultez la reserve concernant ce point exposee ci-dessous). En d'autres termes, des processus qui se trouvent dans differents espaces de noms verront des valeurs differentes lors de la lecture d'un fichier uid_map selon les mappages des identifiants utilisateur pour l'espace de noms utilisateur du processus qui effectue la lecture. Chaque ligne du fichier uid_map affiche un mappage un-pour-un d'un intervalle d'identifiants utilisateur contigus de deux espaces de noms utilisateur. Lorsqu'un espace de noms utilisateur vient d'etre cree, ce fichier est vide. Chaque ligne contient trois nombres delimites par des espaces. Les deux premiers nombres indiquent les premiers identifiants utilisateur de chacun des deux espaces de noms. Le troisieme nombre indique la longueur de l'intervalle de mappage. Plus precisement, les champs sont interpretes de la facon suivante : (1) Le debut de l'intervalle d'identifiants utilisateur dans l'espace de noms utilisateur du processus pid. (2) Le debut de l'intervalle d'identifiants utilisateur auquel mappe l'identifiant utilisateur indique dans le premier champ. Selon que le processus qui a ouvert le fichier uid_map et le processus pid sont ou non dans le meme espace de noms, le deuxieme champ est interprete de l'une des facons suivantes : (a) Si les deux processus sont dans differents espaces de noms utilisateur : le deuxieme champ est le debut de l'intervalle d'identifiants utilisateur dans l'espace de noms utilisateur du processus qui a ouvert uid_map. (b) Si les deux processus sont dans le meme espace de noms utilisateur : le second champ correspond au debut de la sequence d'identifiants utilisateur dans l'espace de noms utilisateur parent du processus pid. Cela permet au processus qui a ouvert uid_map (generalement, le processus ouvre /proc/self/uid_map) de voir le mappage des identifiants utilisateur dans l'espace de noms utilisateur du processus qui a cree cet espace de noms utilisateur. (3) La longueur de l'intervalle des identifiants utilisateur qui est mappe entre les deux espaces de noms utilisateur. Les appels systeme qui renvoient des identifiants utilisateur (des identifiant de groupes) -- comme par exemple, getuid(2), getgid(2), et les champs relatifs aux droits dans la structure renvoyee par stat(2) -- affichent la valeur de l'identifiant utilisateur (l'identifiant de groupe) mappe dans l'espace de noms utilisateur de l'appelant. Lorsqu'un processus accede a un fichier, ses identifiant utilisateur et groupe sont mappes dans l'espace de noms utilisateur initial pour pouvoir verifier les droits ou pour assigner des identifiants lors de la creation d'un fichier. Lorsqu'un processus obtient les identifiants utilisateur et groupe d'un fichier par la commande stat(2), les identifiants sont evalues dans le sens inverse, afin de renvoyer les valeurs relatives aux mappages des ID utilisateur et de groupe du processus. L'espace de noms utilisateur initial n'a pas d'espace de noms parent, mais pour conserver la coherence, le noyau lui attribue des fichiers de mappage d'identifiants utilisateur et groupe factices pour cet espace de noms. Si l'on consulte le fichier uid_map (ou gid_map de la meme facon) depuis une invite de commande dans l'espace de noms initial, on peut voir : $ cat /proc/$$/uid_map 0 0 4294967295 This mapping tells us that the range starting at user ID 0 in this namespace maps to a range starting at 0 in the (nonexistent) parent namespace, and the length of the range is the largest 32-bit unsigned integer. This leaves 4294967295 (the 32-bit signed -1 value) unmapped. This is deliberate: (uid_t) -1 is used in several interfaces (e.g., setreuid(2)) as a way to specify "no user ID". Leaving (uid_t) -1 unmapped and unusable guarantees that there will be no confusion when using these interfaces. Creation des mappages d'ID utilisateur et groupe : ecriture dans uid_map et gid_map Apres la creation d'un nouvel espace de noms utilisateur, le fichier uid_map de l'un des processus de l'espace de noms peut etre ouvert en ecriture une seule fois pour y consigner le mappage des identifiants utilisateur dans le nouvel espace de noms utilisateur. Toute tentative d'ecrire plus d'une fois dans un fichier uid_map se solde par un echec qui renvoie l'erreur EPERM. Des regles analogues s'appliquent aux fichiers gid_map. Les lignes inscrites dans uid_map (gid_map) doivent suivre les regles de validite suivantes : - Les trois champs doivent etre des nombres valables et le dernier champ doit etre strictement positif. - Les lignes doivent se terminer par un saut de ligne. - Il y a une limite (arbitraire) du nombre de lignes que peut contenir le fichier. Dans Linux 4.14 et precedents, la limite est (arbitrairement) de 5 lignes. Depuis Linux 4.15, la limite est de 340 lignes. En outre, le nombre d'octets inscrits dans le fichier doit etre inferieur a la taille d'une page du systeme, et l'ecriture doit etre realisee au debut du fichier (c'est-a-dire lseek(2) et pwrite(2) ne peuvent etre utilisees pour ecrire dans le fichier avec un decalage non nul). - L'intervalle d'identifiants utilisateur (ou de groupe) indique dans chaque ligne ne peut recouvrir les intervalles des autres lignes. Dans l'implementation initiale (Linux 3.8), cette regle etait assuree par une implementation plus sommaire qui comprenait une contrainte supplementaire : les deux premiers champs de chaque ligne devaient apparaitre en ordre croissant. Cela empechait cependant la creation de mappages valables. Ce probleme a ete regle dans Linux 3.9 et suivants, et toutes les combinaisons valables de mappages non recouvrantes sont desormais acceptees. - Au moins une ligne doit etre inscrite dans le fichier. Les operations d'ecritures qui ne respectent pas les regles enoncees precedemment echouent en renvoyant l'erreur EINVAL. Un processus ne peut ecrire dans le fichier /proc/pid/uid_map (/proc/pid/gid_map) qu'a la condition de respecter les contraintes suivantes : - Le processus realisant l'ecriture doit disposer de la capacite CAP_SETUID (CAP_SETGID) dans l'espace de noms utilisateur du processus pid. - Le processus realisant l'ecriture doit se trouver soit dans l'espace de noms utilisateur du processus pid, soit dans l'espace de noms utilisateur parent du processus pid. - Les identifiants utilisateur (ou groupe) mappes doivent, en retour, avoir un mappage dans l'espace de noms utilisateur parent. - Pour une mise a jour de /proc/pid/uid_map pour creer un mappage pour l'UID 0 dans l'espace de noms parent, une des propositions suivantes doit etre vraie : (a) si le processus ecrivain est dans l'espace de noms utilisateur parent, il doit disposer de la capacite CAP_SETUID ; (b) si le processus ecrivain est dans l'espace de noms enfant, alors le processus ayant cree l'espace de noms utilisateur doit avoir la capacite CAP_SETFCAP lors de la creation de l'espace de noms. Cette regle a ete mise en place depuis Linux 5.12. Elle supprime un bogue de securite precedent a cause duquel un processus d'UID 0 n'ayant pas la capacite CAP_SETFCAP, qui est necessaire pour creer un binaire avec les capacites de fichier d'un certain espace de noms (comme decrit dans capabilities(7)), pouvait neanmoins creer un tel binaire en effectuant les etapes suivantes : (1) Creer un nouvel espace de noms utilisateur avec le mappage d'identifiant (c'est-a-dire, UID 0 dans le nouvel espace de noms utilisateur correspond a l'UID 0 dans l'espace de noms parent), ainsi cet UID 0 dans les deux espaces de noms est equivalent au meme ID de superutilisateur. (2) Puisque le processus enfant a la capacite CAP_SETFCAP, il peut creer un binaire avec les capacites de fichier d'un certain espace de noms qui serait alors disponible dans l'espace de noms parent (parce que les ID du superutilisateur sont les memes dans les deux espaces de noms). - L'un des deux points suivants est verifie : (a) soit le processus realisant l'ecriture doit disposer de la capacite CAP_SETUID ( CAP_SETGID) dans l'espace de noms utilisateur parent. - Aucune autre restriction, le processus peut etablir des mappages vers les ID utilisateur (groupe) dans l'espace de noms parent. (b) Ou sinon toutes les restrictions suivantes s'appliquent : - Les donnees inscrites dans uid_map (gid_map) doivent consister en une seule ligne qui mappe l'identifiant utilisateur effectif (groupe) du processus ecrivant dans l'espace de noms utilisateur parent a un ID utilisateur (groupe) dans l'espace de noms utilisateur. - Le processus realisant l'ecriture doit avoir le meme ID utilisateur effectif que le processus ayant cree l'espace de noms utilisateur. - Dans le cas de gid_map, l'utilisation de l'appel systeme setgroups(2) doit etre d'abord interdit en ecrivant << deny >> dans le fichier /proc/pid/setgroups (voir ci-dessous) avant d'ecrire dans gid_map. Les ecritures violant ces regles echouent avec l'erreur EPERM. Mappages d'ID de projet : projid_map De la meme maniere que pour les mappages d'ID d'utilisateur et de groupe, il est possible de creer des mappages d'ID de projet pour un espace de noms utilisateur (les ID de projets sont utilises pour des quotas de disque, consulter setquota(8) et quotactl(2)). Les mappages d'ID de projet sont definis par des ecritures dans le fichier /proc/pid/projid_map (present depuis Linux 3.7). Les regles de validite pour ecrire dans le fichier /proc/pid/projid_map sont les memes que pour le fichier uid_map. Une violation de ces regles provoque l'echec de write(2) avec l'erreur EINVAL. Les regles de permission pour ecrire dans le fichier /proc/pid/projid_map sont les suivantes : - Le processus realisant l'ecriture doit se trouver soit dans l'espace de noms utilisateur du processus pid, soit dans l'espace de noms utilisateur parent du processus pid. - Les ID de projet mappes doivent, en retour, avoir un mappage dans l'espace de noms utilisateur parent. La violation de ces regles provoque l'echec de write(2) avec l'erreur EPERM. Interaction avec les appels systeme qui modifient les UID ou les GID Dans un espace de noms utilisateur ou aucun fichier uid_map n'a ete ecrit, les appels systeme qui modifient l'ID utilisateur echoueront. De la meme maniere, si le fichier gid_map n'a pas ete ecrit, les appels systeme modifiant les ID de groupe echoueront. Apres que les fichiers uid_map et gid_map aient ete ecrits, seules les valeurs mappees peuvent etre utilisees dans les appels systeme modifiant les ID utilisateur et groupe. Pour les ID utilisateur, les appels systeme concernes incluent setuid(2), setfsuid(2), setreuid(2) et setresuid(2). Pour les ID de groupe, les appels systeme concernes incluent setgid(2), setfsgid(2), setregid(2), setresgid(2) et setgroups(2). Ecrire << deny >> dans le fichier /proc/pid/setgroups avant d'ecrire dans /proc/pid/gid_map desactivera de maniere permanente setgroups(2) dans un espace de noms utilisateur et permettra d'ecrire dans /proc/pid/gid_map sans avoir la capacite CAP_SETGID dans l'espace de noms utilisateur parent. The /proc/pid/setgroups file Le fichier /proc/pid/setgroups affichera la chaine << allow >> si les processus dans l'espace de noms utilisateur qui contient le processus pid sont autorises a employer l'appel systeme setgroups(2). Il affichera << deny >> si setgroups(2) n'est pas autorise dans cet espace de noms utilisateur. Remarquez que quelle que soit la valeur dans le fichier /proc/pid/setgroups (et quelles que soient les capacites du processus), les appels a setgroups(2) ne sont en outre pas permis si /proc/pidgid_map n'a pas encore ete defini. Un processus privilegie (un avec la capacite CAP_SYS_ADMIN dans l'espace de noms) peut ecrire une des chaines << allow >> ou << deny >> dans ce fichier avant d'ecrire un mappage d'ID de groupe pour cet espace de noms utilisateur dans le fichier /proc/pid/gid_map. Ecrire la chaine << deny >> empeche tout processus dans l'espace de noms utilisateur d'employer setgroups(2). L'idee de ces restrictions decrites dans le paragraphe precedent est qu'il n'est permis d'ecrire dans /proc/pid/setgroups que sil'appel a setgroups(2) est desactive parce que /proc/pid/gid_map n'a pas ete defini. Cela garantit qu'un processus ne peut transiter d'un etat dans lequel setgroups(2) est autorise vers un etat dans lequel setgroups(2) est interdit. Un processus peut transiter seulement de setgroups(2) interdit vers setgroups(2) autorise. La valeur par defaut dans ce fichier dans l'espace de noms utilisateur initial est << allow >>. Une fois que /proc/pid/gid_map a ete ecrit (ce qui a pour effet d'activer setgroups(2) dans l'espace de noms utilisateur), il n'est plus possible de desactiver setgroups(2) en ecrivant << deny >> dans /proc/pid/setgroups (l'ecriture echoue avec l'erreur EPERM). Un espace de noms utilisateur enfant herite du reglage /proc/pid/setgroups de son parent. Si le fichier setgroups a la valeur << deny >>, alors l'appel systeme setgroups(2) ne peut pas par la suite etre reactive (en ecrivant << allow >> dans le fichier) dans cet espace de noms utilisateur (toute tentative echouera avec l'erreur EPERM). Cette restriction se propage vers les espaces de noms utilisateur enfant de cet espace de noms utilisateur. Le fichier /proc/pid/setgroups a ete ajoute dans Linux 3.19, mais a ete retroporte vers plusieurs series stables du noyau car il corrige un probleme de securite. Cela concernait les fichiers avec les permissions telles que << rwx---rwx >>. De tels fichiers accordent moins de permissions au << group >> qu'elles ne donnent a << other >>. Cela signifie qu'abandonner les groupes utilisant setgroups(2) peut permettre un acces au fichier du processus que celui-ci n'avait pas auparavant. Avant l'existence des espaces de noms utilisateur cela n'etait pas un probleme, puisque seul un processus privilegie (un avec la capacite CAP_SETGID) pouvait appeler setgroups(2). Cependant, avec l'introduction des espaces de noms utilisateur, il est devenu possible pour un processus non privilegie de creer un nouvel espace de noms dans lequel l'utilisateur a tous les privileges. Cela permet alors a des utilisateurs anciennement non privilegies d'abandonner les groupes et donc obtenir l'acces a des fichiers auxquels ils ne pouvaient pas acceder. Le fichier /proc/pid/setgroups a ete ajoute pour resoudre le probleme de securite en refusant a tout chemin pour un processus non privilegie d'abandonner les groupes avec setgroups(2). ID utilisateur et groupe non mappes Il existe differentes situations dans lesquelles un identifiant utilisateur (ou de groupe) non mappe peut etre expose dans un espace de noms utilisateur. Par exemple, le premier processus d'un nouvel espace de noms utilisateur peut appeler getuid() avant que le mappage des identifiants utilisateur ait ete defini pour l'espace de noms. Dans la plupart de ces cas, l'identifiant utilisateur non mappe est converti en un identifiant utilisateur (groupe) au-dela de la limite de debordement ; la valeur par defaut au dela de cette limite pour un identifiant utilisateur (ou groupe) est 65534. Consultez les descriptions de /proc/sys/kernel/overflowuid et de /proc/sys/kernel/overflowgid dans proc(5). Les situations dans lesquelles des identifiants non mappes sont transformes de cette facon comprennent les cas des appels systeme qui renvoient des identifiants utilisateur (getuid(2), getgid(2) et les appels similaires), les accreditations passees a l'aide d'un socket de domaine UNIX, les accreditations renvoyees par stat(2), waitid(2) et les autres operations IPC << ctl >> IPC_STAT de System V, les accreditations presentees par /proc/pid/status et les fichiers /proc/sysvipc/*, les accreditations renvoyees par le champ si_uid de siginfo_t recues avec un signal (consultez sigaction(2)), les accreditations ecrites dans le fichier du processus de tenue des comptes (consultez acct(5)) et les accreditations renvoyees avec des notifications de files de messages POSIX (consultez mq_notify(3)). Il est un cas notable ou des identifiants d'utilisateur et de groupe non mappes ne sont pas convertis en des valeurs d'ID correspondantes au-dela de la limite. Lors de la consultation d'un fichier uid_map ou gid_map dans lequel il n'y a pas de mappage pour le second champ, ce champ apparait comme 4294967295 (-1 represente comme un entier non signe). Accession aux fichiers Dans le but de determiner les permissions quand un processus non privilegie accede a un fichier, les accreditations du processus (UID, GID) et les accreditations du fichier sont en realite mappees vers ce qu'elles seraient dans l'espace de noms utilisateur initial et alors comparees pour determiner les permissions que le processus possede sur le fichier. La meme chose est valable pour les autres objets qui emploient les accreditations plus le modele d'accessibilite avec le masque de permission, tels que les objets IPC de System V. Operations sur les capacites relatives aux fichiers Certaines capacites permettent a un processus de contourner diverses restrictions imposees par le noyau lors d'operations sur des fichiers possedes par d'autres utilisateurs ou groupes. Ce sont CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER et CAP_FSETID. Dans un espace de noms utilisateur, ces capacites permettent a un processus de contourner les regles si le processus possede la capacite adequate sur le fichier, signifiant que : - le processus a la capacite effective adequate dans son espace de noms utilisateur; - les ID utilisateur et groupe du fichier ont tous les deux des mappages valables dans l'espace de noms utilisateur. La capacite CAP_FOWNER est traitee de maniere quelque peu exceptionnelle. Elle permet a un processus de contourner les regles correspondantes a condition qu'au moins l'ID utilisateur du fichier possede un mappage dans l'espace de noms utilisateur (c'est-a-dire que l'ID de groupe du fichier n'a nul besoin d'avoir un mappage valable). Programmes set-user-ID et set-group-ID Lorsqu'un processus appartenant a un espace de noms execute un programme set-user-ID (set-group-ID), l'identifiant utilisateur (groupe) effectif du processus dans l'espace de noms est change a n'importe quelle valeur mappee pour l'identifiant utilisateur (groupe) du fichier. Cependant, si l'identifiant utilisateur ou groupe n'a pas de mappage dans l'espace de noms, le bit set-user-ID (set-group-ID) est ignore silencieusement : le nouveau programme est execute, mais l'identifiant utilisateur (groupe) effectif n'est pas modifie. Cela reproduit la semantique d'execution d'un programme set-user-ID ou set-group-ID qui se trouve dans un systeme de fichiers monte avec l'indicateur MS_NOSUID, comme indique dans mount(2). Divers Lorsque les identifiants utilisateur et groupe d'un processus sont transmis a l'aide d'un socket de domaine UNIX a un processus d'un autre espace de noms (consultez la description de SCM_CREDENTIALS dans unix(7)), ils sont transformes en leur valeur correspondante suivant les mappages des identifiants utilisateur et groupe du processus receptionnaire. STANDARDS Linux. NOTES Au fil des ans, de nombreuses fonctionnalites ont ete ajoutees au noyau Linux mais reservees aux utilisateurs disposant de privileges du fait de la confusion qu'elles peuvent induire dans les applications set-user-ID-root. En general, il n'est pas dangereux d'autoriser un superutilisateur d'un espace de noms a utiliser ces fonctionnalites parce qu'il est impossible, dans un espace de noms utilisateur, d'obtenir plus de droits que ce que peut obtenir le superutilisateur d'un espace de noms utilisateur. Superutilisateur global Le terme de << superutilisateur global >> (global root) est parfois utilise comme un raccourci pour l'ID 0 dans l'espace de noms utilisateur initial. Disponibilite Le noyau doit avoir ete configure avec l'option CONFIG_USER_NS pour permettre l'utilisation des espaces de noms utilisateur. Ces espaces doivent egalement etre pris en charge par un ensemble de sous-systemes du noyau. Si un sous-systeme non pris en charge est active dans le noyau, il n'est pas possible de configurer la prise en charge des espaces de noms. Depuis Linux 3.8, la plupart des principaux sous-systemes prennent en charge les espaces de noms utilisateur, mais certains systemes de fichiers n'ont pas l'infrastructure necessaire pour mapper les identifiants utilisateur et groupe entre les espaces de noms utilisateur. Linux 3.9 a fourni l'infrastructure necessaire a la prise en charge de nombreux systemes de fichiers restants (Plan 9 (9P), Andrew File System (AFS), Ceph, CIFS, CODA, NFS et OCFS2). Linux 3.12 a apporte la prise en charge du dernier des principaux systemes de fichiers non encore gere, XFS. EXEMPLES Le programme suivant est concu pour permettre de s'exercer avec les espaces de noms utilisateur, comme avec d'autres espaces de noms. Il cree des espaces de noms tels que definis dans les options de la ligne de commande et execute une commande dans ces espaces de noms. Les commentaires et la fonction usage() dans le programme fournissent une explication detaillee du programme. La session shell suivante illustre son utilisation. Tout d'abord, regardons l'environnement d'execution : $ uname -rs # a partir de Linux 3.8 Linux 3.8.0 $ id -u # execute comme utilisateur sans privileges 1000 $ id -g 1000 Demarrons maintenant un nouveau shell dans les nouveaux espaces de noms utilisateur (-U), de montage (-m) et de PID (-p), avec l'identifiant utilisateur (-M) et groupe (-G) 1000 mappes a 0 dans l'espace de noms utilisateur : $ ./userns_child_exec -p -m -U -M '0 1000 1' -G '0 1000 1' bash Le shell a le PID 1 puisqu'il est le premier processus de l'espace de noms : bash$ echo $$ 1 Lorsque l'on monte un nouveau systeme de fichiers /proc et que l'on affiche tous les processus visibles dans le nouvel espace de noms PID, on constate que le shell peut voir tous les processus qui se trouvent a l'exterieur de l'espace de noms PID : bash$ mount -t proc proc /proc bash$ ps ax PID TTY STAT TIME COMMAND 1 pts/3 S 0:00 bash 22 pts/3 R+ 0:00 ps ax Dans l'espace de noms utilisateur, le shell a les identifiants utilisateur et groupe 0, ainsi qu'un ensemble complet de capacites autorisees et effectives : bash$ cat /proc/$$/status | egrep '^[UG]id' Uid: 0 0 0 0 Gid: 0 0 0 0 bash$ cat /proc/$$/status | egrep '^Cap(Prm|Inh|Eff)' CapInh: 0000000000000000 CapPrm: 0000001fffffffff CapEff: 0000001fffffffff Source du programme /* userns_child_exec.c Licensed under GNU General Public License v2 or later Create a child process that executes a shell command in new namespace(s); allow UID and GID mappings to be specified when creating a user namespace. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include struct child_args { char **argv; /* Command to be executed by child, with args */ int pipe_fd[2]; /* Pipe used to synchronize parent and child */ }; static int verbose; static void usage(char *pname) { fprintf(stderr, "Usage: %s [options] cmd [arg...]\n\n", pname); fprintf(stderr, "Create a child process that executes a shell " "command in a new user namespace,\n" "and possibly also other new namespace(s).\n\n"); fprintf(stderr, "Options can be:\n\n"); #define fpe(str) fprintf(stderr, " %s", str); fpe("-i New IPC namespace\n"); fpe("-m New mount namespace\n"); fpe("-n New network namespace\n"); fpe("-p New PID namespace\n"); fpe("-u New UTS namespace\n"); fpe("-U New user namespace\n"); fpe("-M uid_map Specify UID map for user namespace\n"); fpe("-G gid_map Specify GID map for user namespace\n"); fpe("-z Map user's UID and GID to 0 in user namespace\n"); fpe(" (equivalent to: -M '0 1' -G '0 1')\n"); fpe("-v Display verbose messages\n"); fpe("\n"); fpe("If -z, -M, or -G is specified, -U is required.\n"); fpe("It is not permitted to specify both -z and either -M or -G.\n"); fpe("\n"); fpe("Map strings for -M and -G consist of records of the form:\n"); fpe("\n"); fpe(" ID-inside-ns ID-outside-ns len\n"); fpe("\n"); fpe("A map string can contain multiple records, separated" " by commas;\n"); fpe("the commas are replaced by newlines before writing" " to map files.\n"); exit(EXIT_FAILURE); } /* Update the mapping file 'map_file', with the value provided in 'mapping', a string that defines a UID or GID mapping. A UID or GID mapping consists of one or more newline-delimited records of the form: ID_inside-ns ID-outside-ns length Requiring the user to supply a string that contains newlines is of course inconvenient for command-line use. Thus, we permit the use of commas to delimit records in this string, and replace them with newlines before writing the string to the file. */ static void update_map(char *mapping, char *map_file) { int fd; size_t map_len; /* Length of 'mapping' */ /* Replace commas in mapping string with newlines. */ map_len = strlen(mapping); for (size_t j = 0; j < map_len; j++) if (mapping[j] == ',') mapping[j] = '\n'; fd = open(map_file, O_RDWR); if (fd == -1) { fprintf(stderr, "ERROR: open %s: %s\n", map_file, strerror(errno)); exit(EXIT_FAILURE); } if (write(fd, mapping, map_len) != map_len) { fprintf(stderr, "ERROR: write %s: %s\n", map_file, strerror(errno)); exit(EXIT_FAILURE); } close(fd); } /* Linux 3.19 made a change in the handling of setgroups(2) and the 'gid_map' file to address a security issue. The issue allowed *unprivileged* users to employ user namespaces in order to drop groups. The upshot of the 3.19 changes is that in order to update the 'gid_maps' file, use of the setgroups() system call in this user namespace must first be disabled by writing "deny" to one of the /proc/PID/setgroups files for this namespace. That is the purpose of the following function. */ static void proc_setgroups_write(pid_t child_pid, char *str) { char setgroups_path[PATH_MAX]; int fd; snprintf(setgroups_path, PATH_MAX, "/proc/%jd/setgroups", (intmax_t) child_pid); fd = open(setgroups_path, O_RDWR); if (fd == -1) { /* We may be on a system that doesn't support /proc/PID/setgroups. In that case, the file won't exist, and the system won't impose the restrictions that Linux 3.19 added. That's fine: we don't need to do anything in order to permit 'gid_map' to be updated. However, if the error from open() was something other than the ENOENT error that is expected for that case, let the user know. */ if (errno != ENOENT) fprintf(stderr, "ERROR: open %s: %s\n", setgroups_path, strerror(errno)); return; } if (write(fd, str, strlen(str)) == -1) fprintf(stderr, "ERROR: write %s: %s\n", setgroups_path, strerror(errno)); close(fd); } static int /* Start function for cloned child */ childFunc(void *arg) { struct child_args *args = arg; char ch; /* Wait until the parent has updated the UID and GID mappings. See the comment in main(). We wait for end of file on a pipe that will be closed by the parent process once it has updated the mappings. */ close(args->pipe_fd[1]); /* Close our descriptor for the write end of the pipe so that we see EOF when parent closes its descriptor. */ if (read(args->pipe_fd[0], &ch, 1) != 0) { fprintf(stderr, "Failure in child: read from pipe returned != 0\n"); exit(EXIT_FAILURE); } close(args->pipe_fd[0]); /* Execute a shell command. */ printf("About to exec %s\n", args->argv[0]); execvp(args->argv[0], args->argv); err(EXIT_FAILURE, "execvp"); } #define STACK_SIZE (1024 * 1024) static char child_stack[STACK_SIZE]; /* Space for child's stack */ int main(int argc, char *argv[]) { int flags, opt, map_zero; pid_t child_pid; struct child_args args; char *uid_map, *gid_map; const int MAP_BUF_SIZE = 100; char map_buf[MAP_BUF_SIZE]; char map_path[PATH_MAX]; /* Parse command-line options. The initial '+' character in the final getopt() argument prevents GNU-style permutation of command-line options. That's useful, since sometimes the 'command' to be executed by this program itself has command-line options. We don't want getopt() to treat those as options to this program. */ flags = 0; verbose = 0; gid_map = NULL; uid_map = NULL; map_zero = 0; while ((opt = getopt(argc, argv, "+imnpuUM:G:zv")) != -1) { switch (opt) { 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 'u': flags |= CLONE_NEWUTS; break; case 'v': verbose = 1; break; case 'z': map_zero = 1; break; case 'M': uid_map = optarg; break; case 'G': gid_map = optarg; break; case 'U': flags |= CLONE_NEWUSER; break; default: usage(argv[0]); } } /* -M or -G without -U is nonsensical */ if (((uid_map != NULL || gid_map != NULL || map_zero) && !(flags & CLONE_NEWUSER)) || (map_zero && (uid_map != NULL || gid_map != NULL))) usage(argv[0]); args.argv = &argv[optind]; /* We use a pipe to synchronize the parent and child, in order to ensure that the parent sets the UID and GID maps before the child calls execve(). This ensures that the child maintains its capabilities during the execve() in the common case where we want to map the child's effective user ID to 0 in the new user namespace. Without this synchronization, the child would lose its capabilities if it performed an execve() with nonzero user IDs (see the capabilities(7) man page for details of the transformation of a process's capabilities during execve()). */ if (pipe(args.pipe_fd) == -1) err(EXIT_FAILURE, "pipe"); /* Create the child in new namespace(s). */ child_pid = clone(childFunc, child_stack + STACK_SIZE, flags | SIGCHLD, &args); if (child_pid == -1) err(EXIT_FAILURE, "clone"); /* Parent falls through to here. */ if (verbose) printf("%s: PID of child created by clone() is %jd\n", argv[0], (intmax_t) child_pid); /* Update the UID and GID maps in the child. */ if (uid_map != NULL || map_zero) { snprintf(map_path, PATH_MAX, "/proc/%jd/uid_map", (intmax_t) child_pid); if (map_zero) { snprintf(map_buf, MAP_BUF_SIZE, "0 %jd 1", (intmax_t) getuid()); uid_map = map_buf; } update_map(uid_map, map_path); } if (gid_map != NULL || map_zero) { proc_setgroups_write(child_pid, "deny"); snprintf(map_path, PATH_MAX, "/proc/%jd/gid_map", (intmax_t) child_pid); if (map_zero) { snprintf(map_buf, MAP_BUF_SIZE, "0 %ld 1", (intmax_t) getgid()); gid_map = map_buf; } update_map(gid_map, map_path); } /* Close the write end of the pipe, to signal to the child that we have updated the UID and GID maps. */ close(args.pipe_fd[1]); if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */ err(EXIT_FAILURE, "waitpid"); if (verbose) printf("%s: terminating\n", argv[0]); exit(EXIT_SUCCESS); } VOIR AUSSI newgidmap(1), newuidmap(1), clone(2), ptrace(2), setns(2), unshare(2), proc(5), subgid(5), subuid(5), capabilities(7), cgroup_namespaces(7), credentials(7), namespaces(7), pid_namespaces(7) Le fichier Documentation/admin-guide/namespaces/resource-control.rst des sources du noyau. TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot , Cedric Boutillier , Frederic Hantrais et Jean-Paul Guillonneau Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.9.1 15 juin 2024 user_namespaces(7)