Vue d'ensemble de l'architecture de l'espace utilisateur

Manux a sa propre architecture de l'espace utilisateur, qui ne ressemble ? aucune autre. Essayons de la d?crire.

Organisation sur le disque dur

Tout d'abord, ?tudions la disposition des fichiers sur le disque dur. Pour comparaison, voici l'aspect de la racine d'une distribution Linux classique :

ecolbus@linux:~$ ls -F /
bin/    etc/             lib/         opt/   sbin/     tmp/      vmlinuz.old@
boot/   home/            lost+found/  proc/  selinux/  usr/
cdrom/  initrd.img@      media/       root/  srv/      var/
dev/    initrd.img.old@  mnt/         run/   sys/      vmlinuz@

Montons ? pr?sent la partition racine d'un syst?me Manux, et voyons ce qu'elle contient :

root@linux:~# mount /mnt/manux-ro 
root@linux:~# ls -F /mnt/manux-ro/
lost+found/  packages/

Comme vous vous en rendez sans doute compte, ce n'est pas exactement ainsi que la racine d'un syst?me UNIX classique est sens?e appara?tre.

D?crivons rapidement ces ?l?ments. "lost+found" est un r?pertoire li? au syst?me de fichiers qui doit se trouver dans sa racine. "packages", qui correspondra effectivement ? "/packages" lorsque le syst?me fonctionnera, est le r?pertoire qui contient tous ses paquetages; toutefois, sous Manux, tous les fichiers font partie d'un paquetage. Donc, oui, "/packages" contient l'ensemble du syst?me d'exploitation. Enfin, "/" lui-m?me est un r?pertoire sp?cial, toujours inatteignable (sauf si vous d?cidez de monter la partition ailleurs), qui sert ? certains algorithmes du syst?me de fichiers virtuel (module noyau : sfv).

Bien. ? pr?sent, qu'y a-t-il dans "/packages" ?

root@linux:~# ls -F /mnt/manux-ro/packages/
core/  local/  std/

Ici, nous n'avons que 3 r?pertoires, parce que nous sommes dans la version 0.0.1. Chacun correspond ? une distribution, ou un distributeur (par exemple, si le roi Arthur d?cidait d'empaqueter et de distribuer son logiciel de recherche de Graal, il irait dans "/packages/table_ronde"), ? l'exception de "local", qui contient les paquetages sp?cifiques aux utilisateurs de la machine, comme leurs r?pertoires personnels.

En ce qui concerne les deux autres, "core" contient le coeur du syst?me d'exploitation, tandis que "std" contient la distribution initiale, avec des composants si communs (comme la glibc ou bash) qu'ils seront vraisemblablement r?utilis?s sans modifications par d'autres distributions.

Organisation des paquetages

Mais qu'y a-t-il dans ces r?pertoires? Essayons quelques commandes.

root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3
alias/  etc/  misc/  userdirs/  vim/
root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim
lnc/  lncb/  meta/  root/  userdirs

L?, les choses commencent ? devenir int?ressantes. Notons tout d'abord que tous les paquetages sont situ?s dans des arborescences organis?es de la m?me fa?on dans /packages : "distrib/version_distrib/logiciel/version_logiciel/portion_logiciel". A cet emplacement se trouvent deux r?pertoires obligatoires, "root" et "meta", respectivement le contenu et les m?tadonn?es du paquetage, ainsi que deux r?pertoires optionnels, "lncb" et "lnc", qui sont li?s ? la fa?on de lancer les ?ventuels ex?cutables du paquetage. Accessoirement, nous notons un curieux fichier nomm? "userdirs" :

root@linux:~# stat /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/userdirs
  Fichier : "/mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/userdirs"
   Taille : 4096        Blocs : 8          ES blocs : 4096   fichier ?trange
Device : 807h/2055d     Inode : 195906      Liens : 2
Acc?s : (0777/?rwxrwxrwx)  UID : (    0/    root)   GID : (    0/    root)
Acc?s : 2013-07-06 15:34:38.000000000 +0200
Modi. : 2013-07-06 15:34:38.000000000 +0200
Chgt  : 2013-07-06 15:34:38.000000000 +0200
Cr??  : - 

Il s'agit en fait d'un lien mat?riel vers un r?pertoire, mais nous verrons cela plus loin.

Quel est l'aspect des choses dans "root"? Voyons, voyons :

root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/root/
etc/  lib/  tmp/  usr/

Ah, ben ?a, ?a ressemble ? une racine standard!

Sous Manux, tous les programmes de l'espace utilisateur sont chroot?s, et leurs paquetages leurs servent de racines. Cela dit, mentionnons imm?diatement que ce r?pertoire n'a ce contenu que parce que nous observons un syst?me d?j? install?. Dans le r?pertoire "root", ce paquetage ne fournit en fait que le contenu de /usr/bin :

root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/root/usr/bin/
vim*

(Bon, pour ?tre exact, il fournit aussi un fichier vide /etc/ld.so.cache, mais c'est sans importance.)

Qu'en est-il de "meta"?

root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/meta/
crypto/  deps  files  identity  install*  origins  userdirs

Il s'agit des donn?es requises par le syst?me de paquetages, dont la description sera le sujet d'un autre document.

Lanceurs

Et "lncb" et "lnc"?

root@linux:~# ls -l /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/lnc{b,}
/mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/lnc:
total 16
-rwxr-xr-t 2 root root 12784 juil.  6 15:34 vim

/mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/lncb:
total 4
-rw-r--r-- 1 root root 390 janv.  1  1970 vim.lncb

Comme pr?c?demment mentionn?, ces r?pertoires sont li?s aux exacutables, donc dans le paquetage de vim, il n'est pas surprenant de ne trouver que des fichiers li?s ? vim. Le r?pertoire "lncb" contient un fichier fourni par le paquetage sp?cifiant comment lancer vim ("lnc" signifie "lanceur", le "b" indique le format binaire non-ex?cutable), tandis que "lnc" contient les v?ritables lanceurs cr??s ? partir des fichiers lncb durant l'installation du paquetage. (Pourquoi faire si compliqu?, demandez-vous? Et bien, nous devons g?rer le cas o? l'empaqueteur est en fait hostile. Le format lncb est tr?s limit?, mais il garantit que les lanceurs cr??s ? partir de lui demeureront inoffensifs).

Mais int?ressons-nous au fichier "lnc/vim". Il s'agit d'un ex?cutable :

root@linux:~# file /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/lnc/vim 
/mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim/lnc/vim: sticky ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped

Mais il est bien plus petit que le vrai ex?cutable de vim. De plus, il est li? statiquement, il a deux liens mat?riels, et son bit sticky est activ?. Qu'est-ce que cela signifie?

Comme nous l'avons dit, la t?che de ce fichier est de lancer vim lorsqu'il est appel?. Dans la mesure o? tous les processus sont chroot?s, si l'utilisateur appelle vim, son shell va devoir appeler ce lanceur depuis son chroot. C'est possible parce que ce lanceur est li? mat?riellement dans la racine de l'utilisateur - d'o? le second lien mat?riel. Si d'autres applications avaient une d?pendance sur vim, ou s'il y avait plus d'utilisateurs sur cette machine, il y aurait plus de liens mat?riels, mais ce n'est pas le cas.

Mais il y a un probl?me : quelle biblioth?que C est disponible dans le chroot de l'appelant? R?ponse : nous ne pouvons pas le savoir ? l'avance, aucune n'est garantie, et en plus, le paquetage appelant pourrait ?tre hostile, donc il n'est pas possible de d?pendre de ses biblioth?ques. C'est pourquoi tous les lanceurs sont li?s statiquement.

Finalement, comment ce binaire est-il sens? trouver le vrai binaire de vim lorsqu'il est appel? depuis un chroot externe arbitraire? C'est ici que le bit sticky entre en jeu.

Le bit sticky

La signification du bit sticky sur des fichiers r?guliers n'est pas sp?cifi?e, et en pratique, il n'est pas utilis?; j'ai donc d?cid? de le r?utiliser dans mon syst?me de fichiers. Dans ext2l, le bit sticky sur un fichier r?gulier informe l'utilisateur que ce fichier a un lien racine, un nouveau type de lien, semblable ? un lien mat?riel, qui associe asymm?triquement un fichier r?gulier ? un r?pertoire. Seul un processus ex?cutant ce fichier r?gulier peut en faire usage, et lorsqu'il le fait, son chroot change, et le r?pertoire vis? devient sa nouvelle racine (et son nouveau r?pertoire courant). Dans le cas habituel, le r?pertoire vis? est le "/root" du paquetage, mais il se trouve que vim est une exception - nous verrons pourquoi plus tard. Pour l'instant, voyons ce qui se passe lorsque quelqu'un appelle un programme plus standard, /bin/cat :

  1. L'application (dans ce cas l'interpr?teur de commandes de l'utilisateur) appelle classiquement fork(2) et cherche cat dans son PATH; elle le trouve dans /bin/cat ;
  2. L'application appelle execve(2) sur l'ex?cutable trouv? dans /bin/cat; sans savoir qu'il ne s'agit en r?alit? que du lanceur de cat;
  3. Le lanceur effectue quelques analyses, puis appelle xchroot(2) avec le t?moin XCHROOT_USE_ROOTLINK;
  4. Le noyau honore l'appel et d?place ce processus depuis le chroot de l'appelant jusque dans le r?pertoire "/root" dans le paquetage de cat (? la fois comme nouvelle racine et comme r?pertoire courant, car xchroot(2) implique un chdir(2));
  5. Le lanceur appelle execve(2) sur le vrai binaire de cat.

Ainsi, gr?ce au lien racine, une application est parvenue ? en appeler une autre sans qu'aucune n'aie jamais eu acc?s au chroot de l'autre.

Les userdirs

Ne finissons pas cette discussion sans exmpliquer la sp?cificit? de vim. Ce qui s?pare vim de cat, techniquement, c'est que vim comporte des fichiers de configuration (~/.vim*). Les g?rer requiert une proc?dure bien plus complexe.

Tout d'abord, pr?cisons le terme. Un userdir est un r?pertoire contenant des fichiers sp?cifiques ? une combinaison {utilisateur, version d'une application}. Les syst?mes d'exploitation classiques stockent ces informations dans le r?pertoire personnel de l'utilisateur, mais cette approche simple ne fonctionnerait pas sous Manux, dans la mesure o? les programmes n'ont pas acc?s ? ce r?pertoire. D'o? la n?cessit? d'un emplacement sp?cial.

Observons ? nouveau nos commandes initiales :

root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3
alias/  etc/  misc/  userdirs/  vim/
root@linux:~# ls -F /mnt/manux-ro/packages/std/0.0.1/vim/7.3/vim
lnc/  lncb/  meta/  root/  userdirs

Ah, oui, voil? l'userdir. Mais pourquoi y en a-t-il deux?

Souvenez-vous que la premi?re commande n'a fait que lister les paquetages pr?sents dans /packages/std/0.0.1/vim/7.3 . Donc le premier est un paquetage ind?pendant - sa raison d'?tre est de permettre ? l'empaqueteur de fournir une configuration par d?faut, et de stocker ces userdirs.

Et le second? Souvenez-vous de ce qui a ?t? dit ? son sujet plus haut : il s'agit d'un lien mat?riel vers un r?pertoire, plus pr?cis?ment vers le r?pertoire "root" du premier.

Pourquoi faire si compliqu?, demandez-vous? Et bien, tout d'abord, rien ne sp?cifie que vim 7.3 est tenu d'employer les userdirs de vim 7.3 - si la configuration ?tait rest?e compatible, et si un tel paquetage existait, il pourrait utiliser les userdirs de vim 7.2 (la fa?on dont le userdir est trouv? rel?ve du syst?me de paquetage). Donc, le premier n'est pas r?ellement utilisable.

De plus, il se trouve que, lorsqu'un logiciel a des userdirs, ses lanceurs ont un lien racine pointant vers le p?re imm?diat de leur r?pertoire "/root". Mais ? pr?sent, les explications th?oriques deviennent un peu compliqu?es, donc voyons en pratique les op?rations qui ont lieu lorsque quelqu'un lance vim :

  1. L'application (dans ce cas l'interpr?teur de commandes de l'utilisateur) appelle classiquement fork(2) et cherche vim dans son PATH; elle le trouve dans /usr/bin/vim ;
  2. L'application appelle execve(2) sur l'ex?cutable trouv? dans /usr/bin/vim; sans savoir qu'il ne s'agit en r?alit? que du lanceur de vim;
  3. Le lanceur effectue quelques analyses, puis appelle xchroot(2) avec le t?moin XCHROOT_USE_ROOTLINK;
  4. Le noyau honore l'appel et d?place ce processus depuis le chroot de l'appelant jusque dans le r?pertoire "/" du paquetage de vim (c'est-?-dire dans /packages/std/0.0.1/vim/7.3/vim, au lieu de /packages/std/0.0.1/vim/7.3/vim/root si vim avait ?t? un programme classique);
  5. Le lanceur appelle getuid(2), pour identifier son utilisateur;
  6. Ensuite, il cherche le r?pertoire /userdirs/ ;
  7. S'il n'existe pas, le lanceur appelle fork(2), puis ex?cute /userdirs/bin/mkuserdir, pour le construire; ? son tour, mkuserdir copie le mod?le stock? dans /userdirs/0;
  8. Apr?s quoi, le lanceur modifie son environment de sorte que la variable HOME pointe ce r?pertoire, et effectue des analyses additionnelles;
  9. Puis, il appelle xchroot(2) sans XCHROOT_USE_ROOTLINK, et avec une nouvelle racine dans /root;
  10. Et, finalement, il appelle execve(2) sur le vrai binaire de vim.

De la sorte, la variable d'environnement HOME a ?t? modifi?e afin que vim y trouve les fichiers de configuration de l'utilisateur sans pouvoir acc?der ? la configuration d'autres personnes. Ce choix architectural implique que la variable HOME peut changer sans que l'utilisateur n'en aie le contr?le; c'est un prix ? payer pour la s?curit? du syst?me d'exploitation.

La partition trois-points

Ha! Vous pensiez r?ellement que nous avions fini? Regardez bien les exemples pr?c?dents, vous ne remarquez pas qu'il reste un probl?me?

J'explique. Si l'utilisateur d?cide de lancer "cat", tout ira bien, en effet. Mais que se passera-t-il s'il tape "cat mon_fichier.txt"?

Oui, regardez attentivement. Le lanceur va se chrooter, puis appeler cat, qui va chercher un fichier nomm? "mon_fichier.txt" dans son r?pertoire... Mais il a ?t? chroot? (et sous Manux, xchroot(2) implique chdir(2)), donc le fichier ne s'y trouvera pas. Comment est-ce sens? fonctionner?

Je vais l'expliquer, mais une remarque avant tout : cela ne peut pas ?tre montr? sur un syst?me Manux arr?t?. D?marrons-le donc, tapons notre login/mot de passe, et jetons un oeil ? notre r?pertoire personnel.

ecolbus@manux:~$ pwd
/.../home/ecolbus

Ah! Il y a quelque chose de nouveau, ici! Ce n'est pas /home/ecolbus, mais /.../home/ecolbus . Bon, essayons d'autres commandes...

ecolbus@manux:~$ touch file
ecolbus@manux:~$ ls -l file
-rw-r--r-- 1 ecolbus ecolbus 0 20 juil. 01:33 file
ecolbus@manux:~$ ls -l /.../home/ecolbus/file
-rw-r--r-- 1 ecolbus ecolbus 0 20 juil. 01:33 /.../home/ecolbus/file

Jusqu'? pr?sent, tout va bien...

ecolbus@manux:~$ ls -l /bin/cat
-rwxr-xr-t 4 sys sys 5264 13 juil. 15:05 /.../??/cat

Euh, quoi? Le nom du fichier a chang??

Oui, il a chang?. ? pr?sent, place aux explications.

/... est un syst?me de fichiers sp?cial, sans existence r?elle, comme /proc (son module noyau est p3p). A la diff?rence de /proc, /... peut toujours ?tre atteint, quel que soit le chroot. De plus, son contenu d?pend du processus qui le regarde, et le fait de savoir s'il est visible ou non dans / n'est pas sp?cifi? (actuellement, il ne l'est jamais).

Ce syst?me de fichiers ne peut contenir que des r?pertoires (et des liens symboliques), mais il est possible de lui demander d'?tablir des associations entre ses entr?es de r?pertoire et des fichiers "r?els" (voyez xchroot(2)). Par exemple, on peut lui demander "fais correspondre /.../abcd/efgh ? mon fichier /etc/hostname", et le nouveau chroot contiendra une entr?e /.../abcd/efgh correspondant au pr?c?dent /etc/hostname.

Le rapport avec notre affaire? Et bien, comme je l'ai dit, il y a un probl?me si quelqu'un tente de taper "cat mon_fichier.txt". Vous vous souvenez lorsque j'ai dit que le lanceur "effectuait diverses analyses"? C'est l? son autre fonction : il analyse la ligne de commande, s?parant ce qui est un fichier de ce qui n'en est pas un, et passe tous les fichiers n?cessaires dans le chroot de la nouvelle commande, dans son r?pertoire /... .

(Pour des raisons techniques, cela doit avoir lieu dans le m?me appel-syst?me que le chroot, c'est donc ? nouveau le travail de xchroot(2). Cette fois, au lieu des t?moins, ce sont les entr?es qui sont utilis?es.)

Bon, c'est tr?s joli, mais lorsqu'il a d?termin? quels ?taient les fichiers ? passer, comment le lanceur choisit-il leurs futurs chemin dans /... ?

R?ponse : ? chaque fois qu'il peut conserver l'ancien chemin, il le fait; lorsqu'il ne le peut pas ou qu'il n'en est pas certain, il choisit un chemin se terminant par le m?me nom que le pr?c?dent et dont il est certain qu'il n'entrera pas en collision avec un autre.

(Je n'entrerai pas ici dans le d?tail des techniques employ?es pour garantir cette unitit? (bien que ce soit peut-?tre l'algorithme le plus int?ressant du syst?me d'exploitation, une diagonalisation de Cantor sur 7 bits par octets, voyez le code source si cela vous int?resse); mais mentionnons une ?vidence : il ne peut pas y avoir de /... dans la racine du paquetage originel (les noms de fichiers points-seuls sont r?serv?s dans ext2l), donc nous sommes s?rs que tout ce que lanceur a ? faire, c'est d'?viter toute collision entre les chemins qu'il cr?e.)

C'est pour cela que le r?pertoire personnel de l'utilisateur a ?t? d?lib?r?ment plac? dans /... : de la sorte, nous sommes certain que tous ses fichiers peuvent ?tre pass?s ? n'importe quel programme sans avoir ? r??crire leur chemin. L'utilisateur les voir d?j? dans /... , donc le lanceur n'a qu'? garder ces noms.

De fa?on plus d?taill?e, voici ce qui se produit lorsqu'un utilisateur tape "cat mon_fichier.txt" :

  1. L'application (dans ce cas l'interpr?teur de commandes de l'utilisateur) appelle classiquement fork(2) et cherche cat dans son PATH; elle le trouve dans /bin/cat ;
  2. L'application appelle execve(2) sur l'ex?cutable trouv? dans /bin/cat; sans savoir qu'il ne s'agit en r?alit? que du lanceur de cat;
  3. Le lanceur analyse la ligne de commande, et realise que mon_fichier.txt correspond ? un fichier;
  4. Il regarde ensuite le r?pertoire courant, et remarque que c'est /.../home/username, clairement dans /... ; il en d?duit qu'il peut sans danger passer le fichier sous le nom /.../home/username/mon_fichier.txt ;
  5. Il construit l'entr?e de xchroot requise pour cela, puis appelle xchroot(2) avec le t?moin XCHROOT_USE_ROOTLINK;
  6. Le noyau honore l'appel et d?place ce processus depuis le chroot de l'appelant jusque dans le r?pertoire "/root" dans le paquetage de cat, simultan?ment, il cr?e une s?rie d'entr?es dans le /... de ce processus, nomm?es /.../home, /.../home/username, et /.../home/username/mon_fichier.txt, cette derni?re associ?e au pr?c?dent fichier mon_fichier.txt;
  7. Le lanceur d?place son r?pertoire courant dans la copie du pr?c?dent r?pertoire courant, ? savoir /.../home/username;
  8. Le lanceur appelle execve(2) sur le vrai binaire de cat;
  9. cat analyse sa ligne de commande, remarque qu'il est sens? ouvrir le fichier mon_fichier.txt dans le r?pertoire courant, tente de le faire, y parvient, et effectue sa t?che.

Fichiers hors de /...

Mais qu'en est-il des fichiers situ?s hors de /... ? Et bien, cette commande nous en a fourni un bon exemple :

ecolbus@manux:~$ ls -l /bin/cat
-rwxr-xr-t 4 sys sys 5264 13 juil. 15:05 /.../??/cat

Dans ce cas, J'ai demand? ? /bin/ls d'op?rer sur /bin/cat, qui est situ? dans ma racine, pas dans mon /... . Le lanceur de ls a rep?r? le probl?me, mais n'avait qu'une seule option : choisir un nouveau chemin de fichier, situ? dans /... , de sorte que /bin/ls puisse l'acc?der depuis son chroot. Son algorithme lui a donn? un nom compos? de deux caract?res illisibles (que ls a remplac?s par des '?'), et, apr?s l'appel ? xchroot(2), le lanceur a modifi? la ligne de commande de ls afin qu'il op?re sur le nouveau chemin, et non sur l'ancien.

Il se trouve que "ls" est l'une des rares commandes qui nous permette d'observer ce m?canisme. Cela signifie aussi que Manux se comporte de fa?on l?g?rement diff?rente des syst?mes d'exploitation traditionnels, et que des incompatibilit?s peuvent en r?sulter. C'est un fait ind?niable, mais ce n'est qu'une cons?quence de sa s?curit? - une autre partie du prix ? payer pour l'obtenir.

Conclusion

Ceci conclut notre revue d'ensemble de l'architecture de l'espace utilisateur Manux. On pourrait encore dire bien des choses ? son sujet, mais il s'agit de principalement de connaissances arcanes (comme la fa?on dont start_session fonctionne, ou la m?thode d'auto-installation du syst?me), qui sont ? la fois nettement moins utiles et simplement bas?es sur les principes expos?s ici. Parvenus ? ce point, si vous d?sirez approfondir vos connaissances ? son sujet, la meilleure m?thode est encore de l'essayer.

Index de la documentation
Page principale