Difference between revisions of "Paper/fr"
From Linux-VServer
(interim saving) |
(topsort) |
||
(5 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{Languages|Paper}} | ||
+ | |||
==Abstract == | ==Abstract == | ||
Concept logiciel basé sur les ''Security Contextes'' permet la création d'une multitude de serveurs virtuels Privés (VPS) tournant simultanément sur un même serveur physique à pleine vitesse, en partageant efficacement les ressources matérielles. | Concept logiciel basé sur les ''Security Contextes'' permet la création d'une multitude de serveurs virtuels Privés (VPS) tournant simultanément sur un même serveur physique à pleine vitesse, en partageant efficacement les ressources matérielles. | ||
Line 585: | Line 587: | ||
Sinon, l'appel système sort, et l'entrée correspondante dans la table donne l'adresse du code ou se trouve l'appel système. | Sinon, l'appel système sort, et l'entrée correspondante dans la table donne l'adresse du code ou se trouve l'appel système. | ||
+ | |||
+ | |||
+ | |||
+ | == Implémentation == | ||
+ | Ce chapitre est plus particulierement reserve aux developpeurs noyau. Toutefois, les curieux trouveront avantage a tirer le rideau pour decouvrir les entrailles du systeme. | ||
+ | |||
+ | === Appel systeme=== | ||
+ | Pendant un certain temps, Linux-VServer a utilise different appels systeme pour accomplir les differents aspects de son travail. Tres vite, le nombre des commandes necessaires est devenu important, nous avons donc commence a donner des valeurs magiques aux appels pour choisir le comportement desire. | ||
+ | |||
+ | Enfin, il y a peu de temps, nous avons obtenu un numero reserve pour les appels systemes Linux-VServer, et malgre l'opinion de certains developpeurs, c'est globalement une bonne decision de garder un seul appel systeme. | ||
+ | |||
+ | Avoir plusieurs appels systeme peut faciliter les choses pour travailler avec les appels systemes sur plusieurs architectures; toutefois, cela n'a pas constitue un probleme majeur jusqu'ici, les donnees transitant depuis et vers le noyau etant, conformement au standard C99, fortement typees. | ||
+ | |||
+ | Quoi qu'il en soit, la mise en place d'un appel systeme passe par la creation d'un multiplexeur, qui va decider quelle commande doit etre executee, et quels arguments lui passer. A elle par la suite d'executer effectivement le travail demande. | ||
+ | extern asmlinkage long | ||
+ | sys_vserver(uint32_t cmd, uint32_t id, void __user *data) | ||
+ | L'appel systeme Linux-VServer prend trois arguments dans tous les cas: la commande (cmd), un nombre (id), et une structure de donnee en espace utilisateur d'une taille encore inconnue. | ||
+ | |||
+ | Pour faciliter le deboggage et la tenue a jour des informations de versionning, la chaine cmd est decomposee en trois parties: les 12 bits de poids faible contiennent le numero de version, puis 4 bits sont reserves. Les 16 bits de poids fort sont divises en 8 bits de commande et 6 pour la categorie, puis les 2 bits restant, reserves pour usage ulterieur. | ||
+ | |||
+ | Nous avons donc 64 Categories avec chacune 256 commandes, et 4096 revisions possible pour chaque commande, ce qui surpasse largement nos besoins presents et futurs. | ||
+ | |||
+ | Voici un apercu des categories deja definies, et leur valeur numerique associee: | ||
+ | |||
+ | Matrice des appels systeme V2.6 | ||
+ | |||
+ | |VERSION|CREATE |MODIFY |MIGRATE|CONTROL|EXPERIM| |SPECIAL|SPECIAL| | ||
+ | |STATS |DESTROY|ALTER |CHANGE |LIMIT |TEST | | | | | ||
+ | |INFO |SETUP | |MOVE | | | | | | | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | SYSTEM |VERSION|VSETUP |VHOST | | | | |DEVICES| | | ||
+ | HOST | 00| 01| 02| 03| 04| 05| | 06| 07| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | CPU | |VPROC |PROCALT|PROCMIG|PROCTRL| | |SCHED. | | | ||
+ | PROCESS| 08| 09| 10| 11| 12| 13| | 14| 15| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | MEMORY | | | | | | | |SWAP | | | ||
+ | | 16| 17| 18| 19| 20| 21| | 22| 23| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | NETWORK| |VNET |NETALT |NETMIG |NETCTL | | |SERIAL | | | ||
+ | | 24| 25| 26| 27| 28| 29| | 30| 31| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | DISK | | | | | | | |INODE | | | ||
+ | VFS | 32| 33| 34| 35| 36| 37| | 38| 39| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | OTHER | | | | | | | |VINFO | | | ||
+ | | 40| 41| 42| 43| 44| 45| | 46| 47| | ||
+ | =======+=======+=======+=======+=======+=======+=======+ +=======+=======+ | ||
+ | SPECIAL| | | | |FLAGS | | | | | | ||
+ | | 48| 49| 50| 51| 52| 53| | 54| 55| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | SPECIAL| | | | |RLIMIT |SYSCALL| | |COMPAT | | ||
+ | | 56| 57| 58| 59| 60|TEST 61| | 62| 63| | ||
+ | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ | ||
+ | |||
+ | La definition de ces commandes est simplifiee grace a certaines macros, comme par exemple interroger un drapeau ou lui attribuer une valeur: | ||
+ | #define VCMD_get_cflags VC_CMD(FLAGS, 1, 0) | ||
+ | #define VCMD_set_cflags VC_CMD(FLAGS, 2, 0) | ||
+ | |||
+ | extern int vc_get_cflags(uint32_t, void __user *); | ||
+ | extern int vc_set_cflags(uint32_t, void __user *); | ||
+ | |||
+ | Notez bien, ce n'est pas la commande elle meme qui est passee en parametre, mais un id et un pointeur vers une structure de donnee en espace utilisateur. | ||
+ | |||
+ | === Structures de Donnees Utilisees=== | ||
+ | Plusieurs types de structures sont utilisees par les differentes parties de l'implementation; seuls quelques exemples sont donnes ici, l'ensemble complet des structures utilisees se trouve dans le source. | ||
+ | ==== La Structure Data Context==== | ||
+ | La structure Data Context permet de gerer les contextes, leur destruction, ainsi que les futurs contextes hierarchiques. | ||
+ | |||
+ | Les sections reservees pour l'ordonanceur ou les limites sont definies dans des structures separees, comme le veut la logique, puis incorporees dans la structure principale. | ||
+ | struct vx_info { | ||
+ | struct list_head vx_list; /* linked list of contexts */ | ||
+ | xid_t vx_id; /* context id */ | ||
+ | atomic_t vx_refcount; /* refcount */ | ||
+ | struct vx_info *vx_parent; /* parent context */ | ||
+ | |||
+ | struct namespace *vx_namespace; /* private namespace */ | ||
+ | struct fs_struct *vx_fs; /* private namespace fs */ | ||
+ | uint64_t vx_flags; /* context flags */ | ||
+ | uint64_t vx_bcaps; /* bounding caps (system) */ | ||
+ | uint64_t vx_ccaps; /* context caps (vserver) */ | ||
+ | |||
+ | pid_t vx_initpid; /* PID of fake init process */ | ||
+ | |||
+ | struct _vx_limit limit; /* vserver limits */ | ||
+ | struct _vx_sched sched; /* vserver scheduler */ | ||
+ | struct _vx_cvirt cvirt; /* virtual/bias stuff */ | ||
+ | struct _vx_cacct cacct; /* context accounting */ | ||
+ | |||
+ | char vx_name[65]; /* vserver name */ | ||
+ | }; | ||
+ | |||
+ | |||
+ | Voici un exemple de la sous-structure Ordonanceur: | ||
+ | struct _vx_sched { | ||
+ | spinlock_t tokens_lock; /* lock for this structure */ | ||
+ | |||
+ | int fill_rate; /* Fill rate: add X tokens ... */ | ||
+ | int interval; /* Divisor: ... each Y jiffies */ | ||
+ | atomic_t tokens; /* current number of tokens */ | ||
+ | int tokens_min; /* Limit: minimum for unhold */ | ||
+ | int tokens_max; /* Limit: no more than N tokens */ | ||
+ | uint32_t jiffies; /* bias: integral multiple of Y */ | ||
+ | |||
+ | uint64_t ticks; /* token tick events */ | ||
+ | cpumask_t cpus_allowed; /* cpu mask for context */ | ||
+ | }; | ||
+ | |||
+ | L'idee principale derriere ces sous-structures est de faciliter leur maintenabilite, a l'aide, pour chacune d'elles, d'une fonction init et cleanup, d'ou une lecture facilitee et une maintenabilite accrue. | ||
+ | |||
+ | ==== The Scheduler Command Data==== | ||
+ | As an example for the data structure used to control a specific part of the context from user-space, here is a scheduler command and the utilized data structure to set the properties: | ||
+ | #define VCMD_set_sched VC_CMD(SCHED, 1, 2) | ||
+ | |||
+ | struct vcmd_set_sched_v2 { | ||
+ | int32_t fill_rate; /* Fill rate: add X tokens ... */ | ||
+ | int32_t interval; /* Divisor: ... each Y jiffies */ | ||
+ | int32_t tokens; /* current number of tokens */ | ||
+ | int32_t tokens_min; /* Limit: minimum for unhold */ | ||
+ | int32_t tokens_max; /* Limit: no more than N tokens */ | ||
+ | uint64_t cpu_mask; /* Mask: allowed cpus */ | ||
+ | }; | ||
+ | |||
+ | |||
+ | ==== Example Accounting: Sockets==== | ||
+ | Basically all the accounting and limit stuff are defined as macros or inline functions capable of handling the different resources, hiding the underlying implementation wherever possible. | ||
+ | #define vx_acc_sock(v,f,p,s) \ | ||
+ | __vx_acc_sock((v), (f), (p), (s), __FILE__, __LINE__) | ||
+ | |||
+ | static inline void __vx_acc_sock(struct vx_info *vxi, | ||
+ | int family, int pos, int size, char *file, int line) | ||
+ | { | ||
+ | if (vxi) { | ||
+ | int type = vx_sock_type(family); | ||
+ | |||
+ | atomic_inc(&vxi->cacct.sock[type][pos].count); | ||
+ | atomic_add(size, &vxi->cacct.sock[type][pos].total); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | #define vx_sock_recv(sk,s) \ | ||
+ | vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, (s)) | ||
+ | #define vx_sock_send(sk,s) \ | ||
+ | vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, (s)) | ||
+ | #define vx_sock_fail(sk,s) \ | ||
+ | vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, (s)) | ||
+ | |||
+ | And this general definition is then used where appropriate, for example in the __sock_sendmsg() function like this: | ||
+ | |||
+ | len = sock->ops->sendmsg(iocb, sock, msg, size); | ||
+ | if (sock->sk) { | ||
+ | if (len == size) | ||
+ | vx_sock_send(sock->sk, size); | ||
+ | else | ||
+ | vx_sock_fail(sock->sk, size); | ||
+ | } | ||
+ | |||
+ | ==== Example Limits: Virtual Memory==== | ||
+ | #define vx_pages_avail(m, p, r) \ | ||
+ | __vx_pages_avail((m)->mm_vx_info, (r), (p), __FILE__, __LINE__) | ||
+ | |||
+ | static inline int __vx_pages_avail(struct vx_info *vxi, | ||
+ | int res, int pages, char *file, int line) | ||
+ | { | ||
+ | if (!vxi) | ||
+ | return 1; | ||
+ | if (vxi->limit.rlim[res] == RLIM_INFINITY) | ||
+ | return 1; | ||
+ | if (atomic_read(&vxi->limit.res[res]) + | ||
+ | pages < vxi->limit.rlim[res]) | ||
+ | return 1; | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | #define vx_vmpages_avail(m,p) vx_pages_avail(m, p, RLIMIT_AS) | ||
+ | #define vx_vmlocked_avail(m,p) vx_pages_avail(m, p, RLIMIT_MEMLOCK) | ||
+ | #define vx_rsspages_avail(m,p) vx_pages_avail(m, p, RLIMIT_RSS) | ||
+ | |||
+ | And again the test against those limits at certain places, for example here in copy_process() | ||
+ | /* check vserver memory */ | ||
+ | if (p->mm && !(clone_flags & CLONE_VM)) { | ||
+ | if (vx_vmpages_avail(p->mm, p->mm->total_vm)) | ||
+ | vx_pages_add(p->mm->mm_vx_info, | ||
+ | RLIMIT_AS, p->mm->total_vm); | ||
+ | else | ||
+ | goto bad_fork_free; | ||
+ | } | ||
+ | |||
+ | ==== Example Virtualization: Uptime==== | ||
+ | void vx_vsi_uptime(struct timespec *uptime) | ||
+ | { | ||
+ | struct vx_info *vxi = current->vx_info; | ||
+ | |||
+ | set_normalized_timespec(uptime, | ||
+ | uptime->tv_sec - vxi->cvirt.bias_tp.tv_sec, | ||
+ | uptime->tv_nsec - vxi->cvirt.bias_tp.tv_nsec); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | if (vx_flags(VXF_VIRT_UPTIME, 0)) | ||
+ | vx_vsi_uptime(&uptime, &idle); | ||
+ | |||
+ | [[Category:Documentation/fr| ]] |
Latest revision as of 09:49, 12 November 2011
[edit] Abstract
Concept logiciel basé sur les Security Contextes permet la création d'une multitude de serveurs virtuels Privés (VPS) tournant simultanément sur un même serveur physique à pleine vitesse, en partageant efficacement les ressources matérielles. Un VPS offre un environnement quasiment identique à celui d'un serveur Linux conventionnel. Tous les services, comme ssh, mail, Web, bases de données, peuvent être lancés dans un tel VPS, sans aucune modification (ou, dans certains cas, des modifications mineures), exactement comme avec n'importe quel autre serveur réel.
Chaque serveur virtuel possède sa propre base utilisateurs et son mot de passe root. Il est isolé de tous les autres serveurs virtuels, sauf en ce qui concerne les ressources matérielles, qui sont partagées par tous les serveurs virtuels.
[edit] Introduction
Au fur et à mesure des années, les micro ordinateurs sont devenus suffisemment puissant pour utiliser la virtualisation comme méthode pour donner l'illusion d'avoir une multitude de petites machines virtuelles, chacune d'elle tournant avec une instance différente de n'importe quel système d'exploitation.
Il existe plusieurs types de Machines Virtuelles (VMs) dont les fonctionnalités sont similaires, mais qui diffèrent dans le degré d'abstraction et les méthodes utilisées pour la virtualisation.
La plupart d'entre elles "émulent" une ressource matérielle réelle ou fictive, qui, à son tour, fait usage de "vraies" ressources du système Hote (la machine qui fait tourner les VMs). Cette approche, utilisée par la plupart des émulations système (comme QEMU[U1], Bochs[U2], ... permet à l'émulateur d'éxécuter n'importe quel système d'exploitation, même pour une architecture différente (CPU et matérielle). Pas besoin de modifier le système d'exploitation Invité, puisqu'il n'est pas conscient de s'éxécuter sur autre chose qu'un vrai matériel.
Quelques émulations systèmes ont besoin d'un petit nombre de modifications ou de pilotes de périphériques spécifiques sur le système Hote ou le système Invité pour améliorer les performances, et minimiser le grignotage superflu de ressources système qui passe dans les systèmes de cache et de médiation entre le système Hote et le système Invité. Bien que cela améliore sensiblement l'efficacité de ces solutions, les ressources perdues sont toujours notables (par exemple dans UML[U3] et Xen[U4]).
Supposez par contre que les systèmes d'exploitation à lancer ne sont pas différents ... La plupart des applications qui tournent sur un serveur n'ont pas besoin d'acceder au matériel ou à du code au niveau noyau, et pourraient donc partager une machine avec les autres, si l'on pouvait les séparer et les isoler ...
[edit] Le Concept
A la base, un serveur Linux est constitué de trois blocs constitutifs: Le matériel, le Noyau, et les Applications. Le Matériel dépend habituellement du fournisseur ou de l'administrateur système, et, bien qu'ayant une grande influence sur les performances globales, ne peut pas être changé facilement, et diffère sensiblement d'une configuration à l'autre.
Un role de base du noyau consiste à créer une couche d'abstraction au dessus du matériel pour permettre aux processus (Applications) de travailler avec des ressources (Données) sans connaitre les détails du matériel qui se trouve en dessous. Idéalement, ces processus sont complètement agnostiques vis-à-vis du matériel, écrit dans un langage interprété, et ne nécessitant par conséquent aucun savoir faire spécifique au matériel.
Puisqu'un système possède assez de ressources pour faire tourner environ dix fois plus d'applications que nécessaire sur un serveur Linux traditionnel, pourquoi ne pas placer sur celui-ci une dizaine de serveurs, qui vont partager les ressources d'une manière efficace ?
La plupart des serveurs d'application (par exemple httpd) considère qu'il est la seule application à fournir un service particulier, et d'habitude, va donc supposer une organisation particulière au niveau du système de fichiers, et de l'environnement. Cela implique que deux services identiques tournant sur un même serveur physique, mais différent simplement au niveau de leur adresse IP, par exemple, doivent être coordonnées. Cela demande typiquement pas mal de boulot pour l'administrateur système, et cela peut conduire à un stabilité réduite du système et de la sécurité.
Le concept de base de la solution Linux-VServer est de séparer l'environnement en user space (espace utilisateur) en trois unités distinctes (appellées parfois VPS, ou Virtual Private Server), de telle manière que chaque VPS ressemblera à un vrai serveur vis-à-vis des processus qu'il contient.
Bien que différentes Distributions Linux utilisent des noyaux modifiées (parfois lourdement) pour assurer le support de telle ou telle fonctionnalité, ou matériel, la plupart des distributions Linux ne sont pas liées irrévocablement à un noyau linux particulier.
Linux-VServer utilise cela pour donner à plusieurs distributions, la possibilité de se lancer au dessus d'un seul noyau, partagé, sans accès direct au matériel, et partager les ressources d'une manière très efficace.
[edit] Infrastructure Existante
Les noyaux Linux récents fournissent déjà de nombreuses fonctions de sécurité qui sont utilisées par Linux-Vserver pour fonctionner, telles que le Système de Privileges Linux, les limites de ressource, les attributs de fichier et l'environnement chroot. Les sections suivantes vous donneront un court aperçu de chacune d'entre elles.
[edit] Le système de Privileges (Capabilities) Linux
En science informatique, un privilege est un jeton utilisé par un processus pour prouver qu'il est autorisé à faire une opération sur un objet. Le Système de privileges Linux est basé sur les "Privileges POSIX", un concept légèrement similaire, conçu pour diviser les privilèges root puissants en un ensemble de privilèges distincts.
[edit] Privileges POSIX
Un processus possède trois champs de bits appelés les privileges héritables (I - "Inheritable"), permises (P), et effectives (E). Chaque privilege est implémenté dans un bit de chacun de ces champs, bit qui est soit défini soit non-défini.
Quand un processus essaie de faire une opération privilégiée, le système d'exploitation va vérifier les bits appropriés dans l'ensemble effectif des processus (au lieu de vérifier si l'uid respectif du processus est 0 comme il le fait habituellement).
Par exemple, quand un processus essaie de modifier l'horloge, le noyau Linux va vérifier que ce processus a le bit CAP_SYS_TIME (actuellement le bit 25) parmi ses privileges effectives.
L'ensemble permis d'un processus indique les privileges que celui-ci peut utiliser. Le processus peut avoir des privileges définies dans l'ensemble permis qui ne sont pas dans l'ensemble effectif.
Ceci indique que le processus a temporairement désactivé ce privilege. Un processus n'est autorisé à définir un bit dans son ensemble effectif que si ce bit est disponible dans son ensemble permis.
La distinction entre privileges effectif et permis existe pour que les processus puissent réaliser des opérations qui nécessitent des privilèges.
Les privileges héritables sont les privileges du processus courant qui peuvent être hérités par un programme exécuté par ce dernier. L'ensemble permis d'un processus est masqué contre l'ensemble héritable pendant exec().
Rien de spécial ne se produit durant fork() ou clone().
Les processus fils ou les threads obtiennent une copie exacte des privileges du processus parent.
L'implémentation dans Linux s'arrête là, alors que les privileges POSIX[U5] requièrent l'ajout d'un ensemble de privileges aux fichiers, pour remplacer le flag SUID (au moins pour les exécutables).
[edit] Vue d'ensemble des privileges
La liste des privileges POSIX utilisées avec Linux est longue, et les 32 bits disponibles sont presques tous utilisés. Bien que la liste détaillée de ces privileges puisse être trouvée dans /usr/include/linux/capability.h sur la plupart des systèmes Linux, une vue d'ensemble des privileges importantes est donnée ici.
0 | CAP_CHOWN | change le propriétaire et le groupe du fichier |
5 | CAP_KILL | envoie un signal au processus avec un ID utilisateur différent, réel ou effectif |
6 | CAP_SETGID | permet le passage de setgid(2), setgroups(2), et de gids forgés sur les sockets |
7 | CAP_SETUID | permet le passage de set*uid(2) et d'uids forgés sur les sockets |
8 | CAP_SETPCAP | transfert/déplace tout privilege de l'ensemble permis vers/depuis n'importe quel pid |
9 | CAP_LINUX_IMMUTABLE | permet la modification des attributs de fichier S_IMMUTABLE et S_APPEND |
11 | CAP_NET_BROADCAST | permet la diffusion et l'écoute en multicast |
12 | CAP_NET_ADMIN | permet la configuration de l'interface, le pare-feux IP, le masquerading, l'accounting, le débugage de sockets, les tables de routage, la liaison sur n'importe quelle adresse, l'entrée dans le mode de promiscuité, le multicasting... |
13 | CAP_NET_RAW | permet l'utilisation des sockets RAW et PACKET |
16 | CAP_SYS_MODULE | ajoute et retire des modules noyau |
18 | CAP_SYS_CHROOT | permet chroot(2) |
19 | CAP_SYS_PTRACE | permet ptrace() sur n'importe quel processus |
21 | CAP_SYS_ADMIN | la liste serait trop longue, ceci permet en gros de faire tout ce qui n'est pas mentionné dans les autres privileges |
22 | CAP_SYS_BOOT | permet reboot(2) |
23 | CAP_SYS_NICE | permet l'élévation des privilèges et la modification de la priorité des autres processus, en modifiant l'ordonnanceur |
24 | CAP_SYS_RESOURCE | passe outre les limites de ressource, de quota, l'espace réservé sur un système de fichier... |
27 | CAP_MKNOD | permet les aspects privilégiés de mknod(2) |
Voir également les Exemples [E01],[E02], et [E03].
[edit] Limite des Ressources
Vous pouvez limiter les ressources de chaque processus en spécifiant une limite pour chaque ressource. A la manière des privileges Linux, il existe deux types de limites, l'une Douce, l'autre Dure.
La limite Douce est la valeur que le noyau imposera pour cette ressource à un processus. Un utilisateur non privilégié pourra régler la limite Douce n'importe où en dessous de la valeur Dure. Seul l'utilisateur root pourra re-hausser la limite Dure.
[edit] Apercu des Ressources Limit-ables
La liste des ressources qui peuvent être limitées se trouve dans le fichier /usr/include/asm/resource.h sur la plupart des systèmes Linux.
0 | RLIMIT_CPU | Temps CPU en secondes. un signal SIGXCPU est envoyé au processus qui a atteind la limite Douce, et un SIGKILL pour la limite Dure. |
4 | RLIMIT_CORE | Taille maximale d'un fichier core. |
5 | RLIMIT_RSS | Nombre de pages maximum qu'un processus peut utiliser (en RAM) |
6 | RLIMIT_NPROC | Nombre maximum de processus autorisés à l'utilisateur réel du processus appelant. |
7 | RLIMIT_NOFILE | Spécifie la valeur +1 pour le nombre maximum de descripteurs de fichiers ouvert par un processus. |
8 | RLIMIT_MEMLOCK | Nombre maximum de pages mémoire virtuelle autorisées à être vérouillées en RAM à l'aide des appels mlock() ou mlockall(). |
9 | RLIMIT_AS | Nombre maximum de pages de mémoire virtuelle disponible pour un processus. |
(Limite de l'espace d'adressage)
Voir aussi les Exemples [E11], et [E12].
[edit] Attributs de Fichiers
Auparavant, cette fonctionnalité n'était disponible qu'avec ext2, mais maintenant tous les systèmes de fichiers majeurs implémentent un ensemble d'Attributs de fichiers de base, qui permettent le paramétrage de certaines propriétés. Voici de nouveau un bref aperçu des possibilités des attributs, et leur signification.
s SECRM | Lorsqu'un fichier avec cet attribut est détruit, les blocs qui le composent sont mis à zéro et re-écrit sur le disque. |
u UNRM | Lorsqu'un fichier avec cet attribut est détruit, son contenu est sauvegardé. |
c COMPR | Un fichier marqué avec cet attribut est automatiquement compressé à l'écriture et décompressé à la lecture. (pas encore implémenté) |
i IMMUTABLE | Un fichier avec cet attribut ne pourra pas être modifié: Impossible de le renommer ou de le détruire, impossible de créer un lien vers ce fichier, ni d'écrire une donnée de plus vers ce fichier. |
a APPEND | Un fichier avec cet attribut ne pourra être ouvert qu'en mode ajout. |
d NODUMP | Si cet attribut de fichier est mis, le fichier n'est pas candidat à un backup via l'utilitaire "dump". |
S SYNC | Les mises à jour vers ce fichier se feront de manière synchrone. |
A NOATIME | Empêche la mise à jour de l'enregistrement atime lors d'un accès ou d'une modification de fichier. |
t NOTAIL | Un fichier avec l'attribut t n'aura pas de fragment bloc en fin de fichier fusionné avec un autre fichier. |
D DIRSYNC | Les modifications apportés à ce répertoire seront écrites de manière synchrones. |
Voir aussi les Exemples [E13] et [E14].
[edit] La Commande chroot(1)
chroot permet de lancer une commande en changeant le répertoire racine dans lequel il va s'éxécuter. Cela signifie que tout parcours du système de fichiers à partir de la racine '/' se fera à partir de la racine substituée et non pas à partir de la racine originelle.
Bien que le chroot Linux n'est pas très sécurisé, son utilisation augmente l'isolation des processus par rapport au système de fichier, et, à condition de l'utiliser correctement, peut être utilisé pour "emprisonner" un processus, un utilisateur unique, ou un démon (service).
Voir l'Exemple [E15]
[edit] Modifications Requises
Ce chapitre décrit les modifications à apporter au noyau pour implémenter un mécanisme comme Linux-VServer.
[edit] Séparation de Contextes
La séparation telle que décrite dans la partie 'Concepts' nécessite quelques modifications au noyau pour permettre la notion de Contexte.
Le but d'un tel "Contexte" est de cacher à un processus tout ce qui ne doit pas etre à sa portée, et empécher les interractions indésirables entre un processus appartenant à un contexte et un processus appartenant à un autre contexte.
Cette séparation nécessite l'extension d'un certain nombre de structures de données pour qu'elles prennent en compte les contextes et fassent la différentiation entre deux uids identiques mais utilisés dans deux serveurs virtuels différents.
De plus, nous avons besoin d'un contexte par defaut qui sera utilisé par le serveur hôte au démarrage, et pour éviter les problèmes liés à des suppositions érronées de certains outils en espace utilisateur (comme pstree) par exemple, l'idée comme quoi init existe toujours et a toujours l'uid 1.
Pour simplifier l'administration, le Contexte de l'Hôte n'est pas traité différemment d'un autre contexte, en tout cas du point de vue de l'isolation des processus.
Pour avoir un apercu global de tous les processus, un Spectateur spécial a été mis en place, qui est capable de capturer tous les processus d'un coup. Voir les Examples [E21],[E22] et [E23]
[edit] Séparation Réseau
Bien que les Contextes soient suffisant pour isoler un groupe de processus, un autre type d'isolation, ou plutot une limitation, est nécessaire pour confiner les processus dans un sous ensemble d'adresses réseau disponibles.
Plusieurs problèmes doivent être pris en compte dans ce sens: par exemple, les appels système bind sur IPADDR_ANY doivent être traités d'une manière bien particulière.
Actuellement, Linux-Vserver n'utilise pas les interfaces virtuelles (et ne les utilisera peut-être jamais), pour minimiser le cout supplémentaire qu'elles engendrent. De ce fait, l'attachement d'une socket et la transmission des packets ont été adaptés.
Voir Example [E24]
[edit] La Barrière Chroot
Un problème majeur avec le chroot() de Linux aujourd'hui tient au fait que cette information est volatile, et changera au prochain appel système de chroot().
Voici une façon simple pour sortir d'un environnement chrooté Créez tout d'abord un fichier, et retenez son descripteur. Puis chrootez dans un répertoire au même niveau ou un niveau au dessous de celui-ci. Cela a pour effet de faire descendre la racine' dans le système de fichiers. Ensuite, faites un appel à fchdir() sur le descripteur de fichiers pour sortir de cette nouvelle racine. Vous sortirez en même temps de l'ancienne racine, qui a été perdue suite au dernier appel système chroot().
Alors que des méthodes exotiques étaient utilisées dans les anciennes versions de Linux-Vserver pour fixer ce problème, les versions récentes utilisent un marquage spécial, connu sous le nom de Barrière Chroot, placé sur le parent de tous les VPS pour prévenir toute modification non autorisée et sortie du confinement.
[edit] Un plafond pour les Privileges
L'implémentation actuelle des privileges Linux ne prend pas en compte les privileges POSIX sur les systèmes de fichiers. Si cela était le cas, les executables setuid et setgid seraient sécurisés. Pour conserver donc une bonne sécurité malgré cette contrainte, nous avons défini un plafond pour tous les processus d'un même contexte, et un masque de privileges additionnel pour chaque contexte a été aussi ajouté pour limiter à ce seul masque les processus qui appartiennent à ce contexte.
La signification des privileges individuels (bits) pour ce masque est exactement identique à celui que permet l'ensemble des privileges.=== Isolation de Ressources ===
[edit] Isolation de Ressources
La plupart des ressources sont d'une certaine manière partagées à travers les différents contextes; certaines requièrent une isolation plus importante que les autres, soit pour éviter les problèmes de sécurité, ou pour permettre une meilleure comptabilité de l'usage des ressources;
Ces ressources sont:
- mémoire partagée, IPC
- PID et User ID
- Drapeau xid sur les fichiers
- ptys Unix
- sockets
[edit] Drapeau XID pour les Filesystem XID
Bien qu'elle puisse être totalement desactivée, cette modification est requise pour une meilleure robustesse au niveau du système de fichiers, et pour isoler les contextes. Le drapeau XID est aussi totalement indispensable pour implémenter le support pour les Limites Disques par Contexte et les Quotas par Contexte sur une partition partagée.
Ce concept d'ajouter un identifiant de contexte (xid) à chaque fichier pour créer une notion d'appartenance d'un fichier à un contexte parait simple ... Il n'en est rien, car l'implémentation actuelle n'est pas triviale. Elle nécessite soit une modification des représentations du système de fichier, soit des astuces au niveau applicatif.
Une approche non intrusive pour éviter toute modification du système de fichiers sous-jacent est d'utiliser les bits de poids forts de champs existants, comme ceux des UID ou GID pour stocker le XID additionnel.
Une fois que les informations de contexte sont disponibles au niveau de chaque inode, l'étape logique suivante est d'étendre la vérification d'accès au contexte en plus du reste.
Actuellement, tous les acces aux inodes sont vérifiés par rapport à leur contexte ID, à l'exception des contextes "Hôte" et "Spectateur".
Les fichiers non étiquettés dans le contexte hôte sont simplement traités comme appartenant au contexte courant, et cela est requis pour que l'Unification soit possible. Si un tel fichier est modifié à l'intérieur d'un contexte, elle changera en silence vers son noveau contexte, en changeant son XID.
Les méthodes suivantes de marquage sont utilisées:
- UID32/GID32 or EXTERNAL
- Ce format utilise l'espace inutilisé dans l'inode disque pour stocker les informations de contexte. Pour l'instant, c'est uniquement défini pour ext3/ext3, mais sera dans le futur aussi défini pour xfs, reiserfs, et jfs, dès que possible.
Avantage: Valeurs 32bit uid/gid complètes.
- UID32/GID16
- Ce format utilise la moitié haute du GID pour stocker les informations de contexte. Cela est fait de manière transparente, sauf si le format est changé sans conversion préalable.
Avantage: fonctionne avec tout système de fichiers équipé de UID / GID 32bits
Désavantage: le GID est réduit a 16 bits.
- UID24/GID24
- Ce format utilise le premier quart haut de l'UID et du GID pour stocker les informations de contexte, une fois encore, d'une manière transparente. Cela permet 16 millions de groupes et utilisateurs, ce qui devrait suffire pour la majorité des applications.
Avantage: fonctionne sur tout système de fichiers avec des UID/GID 32bits
Desavantage: les UID et GID sont réduits a 24 bits.
Voir Examples [E31] et [E32]
[edit] Modifications Supplémentaires
En plus du strict minimum, voici un certain nombre de modifications, non indispensables, mais qui se sont révélées très utiles au fil du temps.
[edit] Drapeaux par Contexte
Très tôt, le besoin d'activer ou désactiver une fonctionnalité séparement pour l'un ou l'autre des Vserver est apparue. Un champ de bits a donc été ajouté (taille=word).
Ce champ de bits comprend un bon nombre de drapeaux, un champ masque, qui indique les drapeaux disponibles, et un mécanisme de déclanchement spécial, pour activer un drapeau au démarrage, puis le désactiver en causant un évennement ou une action associée.
Voici la liste des drapeaux prévus et pour la plupart déjà implémentés. Ils sont disponibles dans la branche de développement de Linux-VServer:
0 | VXF_INFO_LOCK (historique, obsolète) | |
1 | VXF_INFO_SCHED (historique, obsolète) | schedule all processes in a context as if they where one. |
2 | VXF_INFO_NPROC (historique, obsolète) | limite le nombre de processus autorisés dans un contexte à la valeur NPROC. |
3 | VXF_INFO_PRIVATE (historique) | interdiction d'entrer dans ce contexte depuis l'extérieur. |
4 | VXF_INFO_INIT (historique) | show the init process with pid '1' |
5 | VXF_INFO_HIDE (historique, obsolète) | |
6 | VXF_INFO_ULIMIT (historique, obsolète) | |
7 | VXF_INFO_NSPACE (historique, obsolète) | |
8 | VXF_SCHED_HARD | activer l'ordonnancement "Hard CPU" |
9 | VXF_SCHED_PRIO | calculer les priorités de chaque processus à l'aide du "contexte token bucket". |
10 | VXF_SCHED_PAUSE | mettre tous les processus de ce contexte dans la file "hold", les empéchant d'être ordonnancés à nouveau. |
16 | VXF_VIRT_MEM | virtualize the memory information so that the VM and RSS limits are used for meminfo and friends |
17 | VXF_VIRT_UPTIME | virtualiser l'uptime, en commançant à la date de création du contexte. |
18 | VXF_VIRT_CPU | |
24 | VXF_HIDE_MOUNT | afficher les /proc/{pid}/mounts comme vides. |
25 | VXF_HIDE_NETIF | cache les interfaces réseau et addresses non autorisées dans ce contexte. |
Voir Exemple [XX]
[edit] Privileges par Contexte
Lorsque nous sommes arrivé au nombre maximum de privileges envisageables sans trop modifier le noyau, l'étape suivante a été, naturellement, d'ajouter un système de privileges par contexte.
Le mécanisme des privileges par contexte implémenté dans Linux-VServer permet un réglage fin des privileges Linux. Ils ne sont pas visibles aux processus d'un contexte donné, puisque de toute facon le processus n'aurait pas le droit de les vérifier ou de les modifier.
Généralement, il y a deux facons d'utiliser ces privileges : * Require one or a number of context capabilities to be set in addition to a given Linux capability, each one controlling a distinct part of the functionality. For example the CAP_NET_ADMIN could be split into RAW and PACKET sockets, so you could take away each of them separately by not providing the required context capability.
Consider the context capability sufficient for a specified functionality, even if the Linux Capability says something different. For example mount() requires CAP_SYS_ADMIN which adds a dozen other things we do not want, so we define a CCAP_MOUNT to allow mounts for certain contexts.
The difference between the Context Flags and the Context Caps is more an abstract logical separation than a functional one, because they are handled very similar. Again, a list of the Context Capabilities and their purpose:
0 | VXC_SET_UTSNAME | autoriser le contexte à changer le nom de serveur et le nom de domaine en utilisant l'appel système noyau approprié |
1 | VXC_SET_RLIMIT | allow the context to modify the resource limits (within the vserver limits). |
8 | VXC_RAW_ICMP | allow raw icmp packets in a secure way (this makes ping work from inside) |
16 | VXC_SECURE_MOUNT | permit secure mounts, which at the moment means that the nodev mount option is added. |
[edit] Comptabilité par Contexte
Plusieurs propriétés des contextes sont très utiles pour l'administrateur système, que ce soit pour garder un oeil sur les ressources, pour avoir une idée de ce que peut supporter le serveur, ou pour pouvoir facturer d'une manière ou d'une autre au client.
Deux types de propriétés peuvent être comptabilisées, celles dont la valeur courante représente l'état du système (par analogie, prenez la vitesse d'un véhicule), et celles dont la valeur augmente régulièrement avec le temps (comme le kilométrage).
La plupart des valeurs d'état sont limitables, et sont donc traitées d'une façon spécifique, comme cela est décrit dans la section qui suit.
Good candidates for Context Accounting are:
- Temps CPU utilisé
- Nombre de fork() effectués
- Nombre de messages Socket par Type
- Nombre de paquets Transmis et Recus
Voir Exemple [E41]
[edit] Limites par Contexte
La plupart des ressources système, que ce soit la consommation mémoire, le nombre de processus utilisés, le nombre de descripteurs de fichiers, la bande passante réseau, doivent pouvoir être limitées.
Les limites par contexte permettent, pour chaque valeur limitable, de définir trois types de limites: minimum, soft, et hard(maximum).
A l'heure actuelle, seule les limites hard sont supportées, et seulement une partie d'entre elles sont réellement activées. Voici une liste des limites par contexte actuelles et prévues:
- limites sur les processus
- limites sur l'ordonnanceur
- limites mémoire
- limites disques par contexte
- quotas user/groupe par contexte
De plus, les limites par contexte gardent trace des valeur maxima atteintes et du nombre de fois ou la limite a été atteinte (hit), pour donner un feedback utile a l'administrateur.
Voir Exemple [E42]
[edit] Virtualisation
One major difference between the Linux-VServer approach and Virtual Machines is that you do not have the virtualization part as a side-effect, so you have to do that by hand where it makes sense.
For example, a Virtual Machine does not need to think about uptime, because naturally the running OS was started somewhere in the past and will not have any problem to tell the time it thinks it began running.
A context can also store the time when it was created, but that will be different from the systems uptime, so in addition, there has to be some function, which adjusts the values passed from kernel to user-space depending on the context the process belongs to.
This is what for Linux-VServer is known as Virtualization (actually it's more faking some values passed to and from the kernel to make the processes think that they are on a different machine).
Currently modified for the purpose of Virtualization are:
- System Uptime
- Host and Domain Name
- Machine Type and Kernel Version
- Context Memory Availability
- Context Disk Space
Voir Exemple [E43]
[edit] Sécurité Renforcée
Le mécanisme de sécurité Proc-FS protège les entrées dynamiques du système de fichiers proc, de façon à ce que toutes les entrées ne soient pas vues dans tous les contextes.
Le système est constitué de trois drapeaux pour chaque entrée du Proc-FS: Admin, Watch, et Hide.
Le Drapeau Hide active ou désactive entierement une fonctionnalité, donc toute combinaison associée avec un drapeau Hide à 0 aura donc la signification visible.
Les drapeaux Admin et Watch déterminent ou l'entrée hidden (cachée) reste visible; par exemple, si les drapeaux Admin et Hidden sont mis, seul le Host Contexte (0) sera en mesure de voir cette entrée spécifique.
Voir Exemple [E44] et Voir Exemple [E45]
[edit] Kernel Helper
Dans certains cas, il peut être nécessaire de mettre en place un outil en espace utilisateur qui va agir en lieu et place du noyau, lorsque par exemple un processus demande une fonctionnalité disponible sur un serveur réel, mais non disponible dans un contexte.
Le meilleur exemple d'un tel cas est le "Reboot Helper", qui implémente l'appel système reboot(), invoqué depuis l'intérieur d'un contexte en lieu et place du noyau. L'appel sera éxécuté depuis le contexte hôte, qui lancera l'action adéquate, reboot ou un simple halt du contexte en question.
Bien que ce "helper" soit concu pour être flexible et gérer un certain nombre de choses de la même facon, il n'est pas utilisé pour l'instant à autre chose, et pourrait être remplacé dans le futur par une interface par evènement.
Voir Exemple [XX]
[edit] Fonctionnalités et documentation additionnelle
[edit] Unification
L'un des objectifs centraux de Linux-VServer est de réduire l'utilisation des ressources partout ou cela est possible. Une excellente idée a donc germé, celle de partager des fichiers à travers les différents contextes sans interférer avec les taches administratives classiques ou diminuer le niveau de sécurité.
Les fichiers communs à plusieurs contextes, peu sujet à être modifiés, comme les bibliothèques ou les binaires, peuvent être soudés via un lien dur sur un système de fichier partagé, réduisant d'autant le besoin en espace disque, cache d'inodes, et surtout, l'occupation mémoire, via l'utilisation des bibliothèques partagées.
Seul inconvénient, si nous ne prenons pas quelques mesures supplémentaires, un contexte malicieux sera en mesure, par accident ou volontairement, de détruire ou modifier un tel fichier partagé, ce qui aurait des conséquences directes sur les autres contextes. La première étape consiste à placer sur les fichiers partagés un drapeau Immutable (et enlever la caps qui permet de modifier un tel fichier). Il faut toutefois ajouter un attribut supplémentaire à ces fichiers partagés, pour permettre leur suppréssion, lors, par exemple, d'une mise à jour des bibliothèques dans un l'un des contextes.
Ces fichiers liés, immutables, que l'ont peut toutefois détruire, et appartenant à plus d'un contexte sont appelés unifiés, et l'action qui consiste à les rechercher et les préparer s'appelle Unification.
Choississez l'unification si vous souhaitez réduire votre usage de ressources. L'inconvénient évident est une administration moins facile. Un Serveur Linux s'installe typiquement sur 500Mo de disque, et 10 serveurs unifiés en consommeront donc seulement 700Mo, et moins de mémoire pour les caches.
Voir Exemple [XX]
[edit] Espaces de nom privés
Ajoutés récemment dans Linux-VServer, les espaces de noms privés utilisent la couche VFS du noyau linux et offrent une vue différente du système de fichier pour chaque contexte. Par rapport au schéma traditionnel, l'avantage principal apparait lorsqu'on modifie quelquechose dans un espace de nommage (par exemple, les points de montage); à cet instant, les autres contextes resteront intact, y compris biensur le contexte Hôte. Désavantage évident d'une telle approche; entrer dans un tel espace de noms privé n'est pas aussi simple que d'entrer dans un chroot. Toutefois, les choses pourraient changer dans les noyaux futurs, si cette fonctionnalité est par exemple intégrée directement à la fonction chroot().
[edit] Le système de fichier Proc-FS de Linux-VServer
A structured, dynamically generated subtree of the well-known Proc-FS - actually two of them - has been created to allow for inspecting the different values of Security and Network Contexts.
/proc/virtual .../info
/proc/virtual/<pid> .../info .../status .../sched .../cvirt .../cacct .../limit
[edit] Extensions Token Bucket
While the basic idea of Linux-VServer is a peaceful coexistence of all contexts, sharing the common resources in a respectful way, it is sometimes useful to control the resource distribution for resource hungry processes.
The basic principle of a Token Bucket is not very new. It is given here as an example for the Hard CPU Limit. The same principle also applies to scheduler priorities, network bandwidth limitation and resource control in general.
The Hard CPU Limit uses this mechanism in the following way: consider a bucket of a certain size S which is filled with a specified amount of tokens R every interval T, until the bucket is "full" - excess tokens are spilled. At each timer tick, a running process consumes exactly one token from the bucket, unless the bucket is empty, in which case the process is put on a hold queue until the bucket has been refilled with a minimum M of tokens. The process is then rescheduled.
A major advantage of a Token Bucket is that a certain amount of tokens can be accumulated in times of quiescence, which later can be used to burst when resources are required.
Where a per-process Token Bucket would allow for a CPU resource limitation of a single process, a Context Token Bucket allows to control the CPU usage of all confined processes.
Another approach, which is also implemented, is to use the current fill level of the bucket to adjust the process priority, thus reducing the priority of processes belonging to excessive contexts.
Voir Exemple [XX]
[edit] Limites Disque par Contexte
Pour faire usage de cette fonctionnalité, le support pour les fichiers étiquetés XID doit être présent. Grace aux limites par contexte, vous pouvez alors régler une limite différente pour chaque contexte d'une partition partagée.
Chaque block et inode d'un système de fichier est comptabilisé, dès lors qu'un hachage XID a été ajouté à ce système de fichier dans ce contexte donné. Those values, including current usage, maximum and reserved space, will be shown for filesystem queries, creating the illusion that the shared filesystem has a different usage and size, for each context.
[edit] Quota par Contexte
Similar to the Context Disk Limits, Per-Context Quota uses separate quota hashes for different Contexts on a shared filesystem. This is not required to allow for Linux-VServer quota on separate partitions.
[edit] Le périphérique "proxy" VRoot
Les opérations sur les Quotas (ioctls) nécessitent un accès aux périphériques de bloc. Ils ne sont donc pas disponible dans un VPS.
[edit] Stealth
Pour certaines applications, par exemple la préparation d'un "pot de miel" (honey-pot), ou d'une imitation particulièrement réaliste d'un vrai serveur à des fins éducatives, vous aurez peut-être besoin de confondre le contexte du serveur hôte (réel) et celui de votre pot de miel. Toutefois, certaines alternatives libres comme QEMU ou UML vous permettent de faire la même chose beaucoup mieux et avec moins d'efforts. Ce n'est donc pas une question centrale dans le développement de Linux-VServer.
[edit] Sécurité Linux-VServer
Nous savons maintenant que Linux-VServer implémente quelques principes de sécurité, et comment ils fonctionnent. Il faut tout de même dire quelques mots la dessus, puisqu'il ne suffit pas, bien évidemment, de considérer que Linux-VServer étant une architecture sécurisée, votre système sera sur automatiquement. Comme d'habitude, mieux vaut savoir *exactement* ce que vous faites.
[edit] Privileges Sécurisées
Actuellement, seules les privileges Linux suivantes sont considérés d'un usage sans risque dans un VPS. Si d'autres privileges sont nécessaires, ils ouvrent probablement des trous de sécurité.
- CAP_CHOWN
- CAP_DAC_OVERRIDE
- CAP_DAC_READ_SEARCH
- CAP_FOWNER
- CAP_FSETID
- CAP_KILL
- CAP_SETGID
- CAP_SETUID
- CAP_NET_BIND_SERVICE
- CAP_SYS_CHROOT
- CAP_SYS_PTRACE
- CAP_SYS_BOOT
- CAP_SYS_TTY_CONFIG
- CAP_LEASE
CAP_NET_RAW par exemple n'est pas considéré comme sur. Bien qu'il soit souvent utilisé pour donner le droit à la commande "ping" (dont le fonctionnement est cassé), il existe de bien meilleures alternatives comme la commande ping "poink[U7]", ou la cap VXC_RAW_ICMP.
[edit] La Barrière Chroot
Il faut vous assurer que le drapeau barrière est bien mis sur tout répertoire parent de chacun de vos VPS. Cela est indispensable pour prévenir quiconque de sortir du chroot et aller se balader dans le système de fichier de votre vserver hôte.
[edit] Fichiers de périphériques Sécurisés
Le répertoire /dev d'un VPS ne doit pas contenir plus de fichiers qu'indiqué ci-dessous, plus le répertoire pour les pts unix.
- c 1 7 full
- c 1 3 null
- c 5 2 ptmx
- c 1 8 random
- c 5 0 tty
- c 1 9 urandom
- c 1 5 zero
- d pts
Bien entendu, d'autres périphériques comme console, mem, kmem, et même des périphériques en mode block et/ou caractère peuvent être ajoutés, mais une certaine expertise sera nécessaire pour s'assurer que cela n'entraine aucun trou de sécurité.
[edit] Entrées Proc-FS Sécurisées
Aucun test n'a été fait sur la fiabilité et la sécurité des entrées dans le système de fichiers proc, mais quelques incidents ont été notés lorsqu'on utilise par exemple des entrées proc avec permission d'écriture, et non protégées par une CAP linux. Par exemple, /proc/sysrq-trigger est un fichier qui ne doit en aucun cas être accessible dans un VPS sans une excellente raison.
[edit] Champ d'Applications
Le but premier de ce projet est de permettre la création de serveurs virtuels partageant les ressources d'une même machine physique. Un Serveur Virtuel fonctionne comme un serveur Linux normal, et peut lancer des services traditionnels comme telnet, service de mail, service web, service SQL.
[edit] Séparation Administrative
Un provider intelligent peut donc vendre un serveur virtuel, qui, en utilisant moins de ressources que d'autres techniques de virtualisation, permet de lancer plus d'instances sur une même machine.
La liste des providers qui fournissent un tel service est assez longue, et on peut donc considérer que c'est l'application principale de vserver.
[edit] Séparation de Services
Pour séparer plusieurs services identiques ou de nature différente, qui auraient autrement des interférences entre eux, est une chose facile à mettre en oeuvre avec Vserver. Plusieurs raisons peuvent vous pousser à faire cela; un service mal écrit, ou simplement deux services qui ne savent pas co-exister pour de multiples raisons.
Même sur une machine à l'ancienne mode, placer un service très exposé ou non sécurisé car inconnu ou propriétaire dans une prison chroot peut améliorer grandement la sécurité et la maintenabilité.
[edit] Améliorer la Sécurité
Bien que l'idée de lancer plusieurs serveurs sur une seule machine soit en elle même très interessante, d'autres concepts sont encore plus interessants. Imaginez un serveur physique sur lequel tourne un seul vserver. Le but est d'isoler l'environnement principal de n'importe quel service, n'importe quel réseau. Vous démarrerez dans l'environnement principal, lancez très très peu de services, puis continuez dans le serveur virtuel.
Le service de l'environnement principal sera:
- Injoignable depuis le reseau.
- En mesure de logger tous les messages du virtual serveur, d'une manière sécurisée. Rien dans le serveur virtuel ne permet d'effacer les logs, ou de les modifier. Même un serveur virtuel cracké ne permet pas de changer les logs.
- En mesure de faire tourner un système de détection d'intrusion, qui espionnera l'état du serveur virtuel sans être accessible ou même détecté. Par exemple, vous pouvez installer et faire tourner tripwire depuis l'environnement principal, et impossible de modifier son fonctionnement ou de le tromper.
Une autre option consiste à mettre le firewall dans un serveur virtuel, puis étirer la DMZ sur un ensemble de VPS séparés. Moyennant une configuration bien faite, ce genre d'installation peut réduire substantiellement le nombre de machines requises, sans pour autant impacter les performances.
[edit] Maintenance Facilitée
Une fonctionnalité clef d'un serveur virtuel est son indépendance vis à vis du matériel. La plupart des problèmes matériels sont inconnus au fonctionnement d'un serveur virtuel.
Le serveur principal agit comme un système hôte, et s'occupe de tous les détails. Le serveur virtuel est simplement un client, et ignore tous les détails. De cette manière, le client peut être déplacé vers un autre serveur physique avec très peu de manipulations.
Par exemple, pour déplacer un serveur virtuel depuis un ordinateur physique vers un autre, il suffit de procéder aux étapes suivantes:
- stopper le serveur virtuel
- le copier sur l'autre machine
- copier sa configuration
- lancer le serveur virtuel sur la nouvelle machine
Pas de mise à jour des utilisateurs, pas de configuration matérielle, tant que les machines sont compatibles au niveau de leurs binaires.
[edit] Scenarios de Fail-Over
En repoussant les limites un peu plus loin, on peut utiliser des technologies de réplication pour conserver une copie identique à la minute près du système de fichier d'un serveur virtuel en fonctionnement. Cela peut servir à un basculement très rapide si le serveur en fonction tombe pour n'importe quelle raison.
Toutes les methodes connues sont utilisables dans ce but, en commancant par la réplication réseau comme rsync, ou drdb, en passant par NBD (les Network Devices), les disques partagés, ou un système de fichier distribué. Toutes ces méthodes sont utilisables pour réduire le temps d'indisponibilité d'un système et améliorer l'efficacité globale.
[edit] Pour test
Vous avez besoin de construire un logiciel pour plusieurs versions d'une distribution particulière. (Mandrake 8.2, 9.0, 9.1, 9.2, 10.0), ou bien même pour plusieurs distributions différentes.
Ce problème est résolu d'une manière très simple par Vserver. Avec pas mal d'espace disque, ces différentes distributions peuvent être installées et lancées en parallèle, simplifiant la tache de passer de l'une à l'autre.
Biensur, vous pouvez faire cela simplement avec chroot() et rien d'autre, mais Vserver offre une simulation bien plus réaliste.
[edit] Performance et Stabilité
[edit] Impact de Linux-VServer sur l'hôte
[edit] Overhead dans un Contexte
[edit] Taille du patch noyau
[edit] Matériels Non Intel i386
Linux-VServer est concu pour être indépendant de l'architecture au maximum du coup, seule une toute petite partie, la définition de l'appel système lui-même est spécifique à une architecture. Malgré cela, quelques architectures renfermen des copies de certains codes 'architecture independant', pour une raison ou pou une autre, et nécessitent par conséquent de légères modifications.
Les architectures suivantes sont supportées, et certaines d'entre elles ont même été testées:
- alpha
- ia32 / ia64 / xbox
- x86_64 (AMD64)
- mips / mips64
- hppa / hppa64
- ppc / ppc64
- sparc / sparc64
- s390
- uml
L'ajout d'une nouvelle architecture est relativement simple, même si de tests extensifs sont nécessaires pour valider le bon fonctionnement d toutes les fonctionnalités telle qu'attendu. (et biensur, du matériel ;).
[edit] Intro Noyau Linux
Bien que les fonctionnalités décrites plus haut sont codées dans le noyau, quelques outils sont nécessaires en espace utilisateur (userspace) pour les activer et les controler.
Ces outils en userspace communiquent généralement avec le noyau via des appels système (syscalls).
Le chapitre qui suit décrit les liens entre espace kernel et espace utilisateur, comment les appels système, méthode simple pour communiquer entre les processus et le noyau, fonctionnent.
[edit] Espace Noyau et Espace Utilisateur
Sous Linux et les systèmes d'exploitation similaires, l'espace noyau et l'espace utilisateur sont séparés, et l'espace d'adressage est divisé en deux parties. Dans L'espace noyau réside le code noyau, alors que les programmes utilisateur vivent dans l'espace utilisateur. Bien entendu, un programme ne peut écrire dans la mémoire noyau, ni dans la mémoire d'un autre processus.
Malheureusement, c'est aussi le cas pour le code du noyau. Le code kernel n'a pas le droit d'écrire dans l'espace utilisateur. Qu'est-ce que cela signifie ? Lorsqu'un driver de périphérique a besoin d'écrire ses octets destinés à un programme dans l'espace utilisateur, il ne peut pas le faire directement, mais doit passer par des fonctions noyau spécifiques à la place. De même, lorsque des paramètres sont passés au noyau par référence à une fonction kernel, la fonction kernel ne peut pas lire les paramètres directement. Elle doit utiliser d'autres fonctions noyau pour lire chaque octet des paramètres.
Bien entendu, il existe des fonctions écrites tout spécialement pour les transfer depuis et vers l'espace utilisateur.
copy_to_user(void *to, const void *from, long n); copy_from_user(void *to, const void *from, long n);
get_user() and put_user() Prendre ou placer l'octet, le mot, ou l'entier long depuis l'espace utilisateur ou vers celui-ci. C'est une macro, et elle se fie au type de ses arguments pour évaluer le nombre d'octets à transférer.
[edit] Appels système Linux
La plupart des appels libc s'appuient sur les appels système, la plus petite forme de fonction qu'un programme peut appeler.
Ces appels système sont implémentés dans le noyau lui-même, ou dans des modules, parties de code noyau chargeables dynamiquement.
Ils sont implémentés via un multiplexeur appelé avec un masque d'interruption précis. Sous Linux, ce masque d'interruption est int 0x80. Lorsque l'instruction 'int 0x80' est exécutée, le contrôle est donné au noyau (ou, plus précisément, à la fonction _system_call() ), et le démultipléxage proprement dit prend place.
Comment fonctionne la fonction _system_call() ?
Tout d'abord, tous les registres sont sauvegardés, et le contenu du registre %eax est comparé à la table des appels systèmes, qui recense tous les appels systèmes et leur adresse respective.
On peut acceder à cette table via la variable extern void *sys_call_table[] Il existe un nombre et une adresse mémoire données dans cette table pour chacun des appels système.
Ceux-ci sont référencés dans le fichier /usr/include/sys/syscall.h.
Ils sont de la forme SYS_nomappelsysteme. si l'appel système n'est pas implémenté, la cellule correspondante dans la table sys_call_table est à 0, et une erreur est retournée.
Sinon, l'appel système sort, et l'entrée correspondante dans la table donne l'adresse du code ou se trouve l'appel système.
[edit] Implémentation
Ce chapitre est plus particulierement reserve aux developpeurs noyau. Toutefois, les curieux trouveront avantage a tirer le rideau pour decouvrir les entrailles du systeme.
[edit] Appel systeme
Pendant un certain temps, Linux-VServer a utilise different appels systeme pour accomplir les differents aspects de son travail. Tres vite, le nombre des commandes necessaires est devenu important, nous avons donc commence a donner des valeurs magiques aux appels pour choisir le comportement desire.
Enfin, il y a peu de temps, nous avons obtenu un numero reserve pour les appels systemes Linux-VServer, et malgre l'opinion de certains developpeurs, c'est globalement une bonne decision de garder un seul appel systeme.
Avoir plusieurs appels systeme peut faciliter les choses pour travailler avec les appels systemes sur plusieurs architectures; toutefois, cela n'a pas constitue un probleme majeur jusqu'ici, les donnees transitant depuis et vers le noyau etant, conformement au standard C99, fortement typees.
Quoi qu'il en soit, la mise en place d'un appel systeme passe par la creation d'un multiplexeur, qui va decider quelle commande doit etre executee, et quels arguments lui passer. A elle par la suite d'executer effectivement le travail demande.
extern asmlinkage long sys_vserver(uint32_t cmd, uint32_t id, void __user *data)
L'appel systeme Linux-VServer prend trois arguments dans tous les cas: la commande (cmd), un nombre (id), et une structure de donnee en espace utilisateur d'une taille encore inconnue.
Pour faciliter le deboggage et la tenue a jour des informations de versionning, la chaine cmd est decomposee en trois parties: les 12 bits de poids faible contiennent le numero de version, puis 4 bits sont reserves. Les 16 bits de poids fort sont divises en 8 bits de commande et 6 pour la categorie, puis les 2 bits restant, reserves pour usage ulterieur.
Nous avons donc 64 Categories avec chacune 256 commandes, et 4096 revisions possible pour chaque commande, ce qui surpasse largement nos besoins presents et futurs.
Voici un apercu des categories deja definies, et leur valeur numerique associee:
Matrice des appels systeme V2.6
|VERSION|CREATE |MODIFY |MIGRATE|CONTROL|EXPERIM| |SPECIAL|SPECIAL| |STATS |DESTROY|ALTER |CHANGE |LIMIT |TEST | | | | |INFO |SETUP | |MOVE | | | | | | -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ SYSTEM |VERSION|VSETUP |VHOST | | | | |DEVICES| | HOST | 00| 01| 02| 03| 04| 05| | 06| 07| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ CPU | |VPROC |PROCALT|PROCMIG|PROCTRL| | |SCHED. | | PROCESS| 08| 09| 10| 11| 12| 13| | 14| 15| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ MEMORY | | | | | | | |SWAP | | | 16| 17| 18| 19| 20| 21| | 22| 23| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ NETWORK| |VNET |NETALT |NETMIG |NETCTL | | |SERIAL | | | 24| 25| 26| 27| 28| 29| | 30| 31| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ DISK | | | | | | | |INODE | | VFS | 32| 33| 34| 35| 36| 37| | 38| 39| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ OTHER | | | | | | | |VINFO | | | 40| 41| 42| 43| 44| 45| | 46| 47| =======+=======+=======+=======+=======+=======+=======+ +=======+=======+ SPECIAL| | | | |FLAGS | | | | | | 48| 49| 50| 51| 52| 53| | 54| 55| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ SPECIAL| | | | |RLIMIT |SYSCALL| | |COMPAT | | 56| 57| 58| 59| 60|TEST 61| | 62| 63| -------+-------+-------+-------+-------+-------+-------+ +-------+-------+
La definition de ces commandes est simplifiee grace a certaines macros, comme par exemple interroger un drapeau ou lui attribuer une valeur:
#define VCMD_get_cflags VC_CMD(FLAGS, 1, 0) #define VCMD_set_cflags VC_CMD(FLAGS, 2, 0) extern int vc_get_cflags(uint32_t, void __user *); extern int vc_set_cflags(uint32_t, void __user *);
Notez bien, ce n'est pas la commande elle meme qui est passee en parametre, mais un id et un pointeur vers une structure de donnee en espace utilisateur.
[edit] Structures de Donnees Utilisees
Plusieurs types de structures sont utilisees par les differentes parties de l'implementation; seuls quelques exemples sont donnes ici, l'ensemble complet des structures utilisees se trouve dans le source.
[edit] La Structure Data Context
La structure Data Context permet de gerer les contextes, leur destruction, ainsi que les futurs contextes hierarchiques.
Les sections reservees pour l'ordonanceur ou les limites sont definies dans des structures separees, comme le veut la logique, puis incorporees dans la structure principale.
struct vx_info { struct list_head vx_list; /* linked list of contexts */ xid_t vx_id; /* context id */ atomic_t vx_refcount; /* refcount */ struct vx_info *vx_parent; /* parent context */ struct namespace *vx_namespace; /* private namespace */ struct fs_struct *vx_fs; /* private namespace fs */ uint64_t vx_flags; /* context flags */ uint64_t vx_bcaps; /* bounding caps (system) */ uint64_t vx_ccaps; /* context caps (vserver) */ pid_t vx_initpid; /* PID of fake init process */ struct _vx_limit limit; /* vserver limits */ struct _vx_sched sched; /* vserver scheduler */ struct _vx_cvirt cvirt; /* virtual/bias stuff */ struct _vx_cacct cacct; /* context accounting */ char vx_name[65]; /* vserver name */ };
Voici un exemple de la sous-structure Ordonanceur:
struct _vx_sched { spinlock_t tokens_lock; /* lock for this structure */ int fill_rate; /* Fill rate: add X tokens ... */ int interval; /* Divisor: ... each Y jiffies */ atomic_t tokens; /* current number of tokens */ int tokens_min; /* Limit: minimum for unhold */ int tokens_max; /* Limit: no more than N tokens */ uint32_t jiffies; /* bias: integral multiple of Y */ uint64_t ticks; /* token tick events */ cpumask_t cpus_allowed; /* cpu mask for context */ };
L'idee principale derriere ces sous-structures est de faciliter leur maintenabilite, a l'aide, pour chacune d'elles, d'une fonction init et cleanup, d'ou une lecture facilitee et une maintenabilite accrue.
[edit] The Scheduler Command Data
As an example for the data structure used to control a specific part of the context from user-space, here is a scheduler command and the utilized data structure to set the properties:
#define VCMD_set_sched VC_CMD(SCHED, 1, 2)
struct vcmd_set_sched_v2 { int32_t fill_rate; /* Fill rate: add X tokens ... */ int32_t interval; /* Divisor: ... each Y jiffies */ int32_t tokens; /* current number of tokens */ int32_t tokens_min; /* Limit: minimum for unhold */ int32_t tokens_max; /* Limit: no more than N tokens */ uint64_t cpu_mask; /* Mask: allowed cpus */ };
[edit] Example Accounting: Sockets
Basically all the accounting and limit stuff are defined as macros or inline functions capable of handling the different resources, hiding the underlying implementation wherever possible.
#define vx_acc_sock(v,f,p,s) \ __vx_acc_sock((v), (f), (p), (s), __FILE__, __LINE__)
static inline void __vx_acc_sock(struct vx_info *vxi, int family, int pos, int size, char *file, int line) { if (vxi) { int type = vx_sock_type(family);
atomic_inc(&vxi->cacct.sock[type][pos].count); atomic_add(size, &vxi->cacct.sock[type][pos].total); } } #define vx_sock_recv(sk,s) \ vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, (s)) #define vx_sock_send(sk,s) \ vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, (s)) #define vx_sock_fail(sk,s) \ vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, (s))
And this general definition is then used where appropriate, for example in the __sock_sendmsg() function like this:
len = sock->ops->sendmsg(iocb, sock, msg, size); if (sock->sk) { if (len == size) vx_sock_send(sock->sk, size); else vx_sock_fail(sock->sk, size); }
[edit] Example Limits: Virtual Memory
#define vx_pages_avail(m, p, r) \ __vx_pages_avail((m)->mm_vx_info, (r), (p), __FILE__, __LINE__) static inline int __vx_pages_avail(struct vx_info *vxi, int res, int pages, char *file, int line) { if (!vxi) return 1; if (vxi->limit.rlim[res] == RLIM_INFINITY) return 1; if (atomic_read(&vxi->limit.res[res]) + pages < vxi->limit.rlim[res]) return 1; return 0; } #define vx_vmpages_avail(m,p) vx_pages_avail(m, p, RLIMIT_AS) #define vx_vmlocked_avail(m,p) vx_pages_avail(m, p, RLIMIT_MEMLOCK) #define vx_rsspages_avail(m,p) vx_pages_avail(m, p, RLIMIT_RSS)
And again the test against those limits at certain places, for example here in copy_process()
/* check vserver memory */ if (p->mm && !(clone_flags & CLONE_VM)) { if (vx_vmpages_avail(p->mm, p->mm->total_vm)) vx_pages_add(p->mm->mm_vx_info, RLIMIT_AS, p->mm->total_vm); else goto bad_fork_free; }
[edit] Example Virtualization: Uptime
void vx_vsi_uptime(struct timespec *uptime) { struct vx_info *vxi = current->vx_info; set_normalized_timespec(uptime, uptime->tv_sec - vxi->cvirt.bias_tp.tv_sec, uptime->tv_nsec - vxi->cvirt.bias_tp.tv_nsec); return; } if (vx_flags(VXF_VIRT_UPTIME, 0)) vx_vsi_uptime(&uptime, &idle);