Programmation système sous Linux : gestion des limites de ressources

Les systèmes d'exploitation de type UNIX offrent des mécanismes sophistiqués pour contrôler l'utilisation des ressources par les processus. Ces limitations sont cruciales pour prévenir les abus, comme les attaques par déni de service distribué (DDoS), où un attaquant pourrait épuiser les ressources d'un système.

Comprendre les Limites de Ressources

Une attaque cournate consiste à saturer les ressources d'un système. Par exemple, sur un système non protégé, un utilisateur pourrait créer un fichier de taille illimitée en utilisant des commandes comme dd.

# Tentative de création d'un fichier de 1 Go
dd if=/dev/urandom of=fichier_test count=1024 bs=1M

Sans garde-fous, un attaquant pourrait répéter des commandes similaires, consommant rapidement l'espace disque disponible. Pour contrer cela, les systèmes de type UNIX implémentent des limites de ressources par processus.

La commande ulimit permet d'inspecter et de modifier ces limites au niveau du shell. Par exemple, pour vérifier la limite de taille de fichier :

ulimit -f

Si la sortie est "unlimited", cela signifie que le système n'impose pas de limite logicielle directe, mais que la capacité physique du disque reste une contrainte réelle.

Il est possible de définir une limite spécifique. Par exemple, pour limiter la taille des fichiers à 2 Ko :

ulimit -f 2

Ce réglage se traduit par une limite de 2 * 1024 = 2048 octets. Toute tentative de créer un fichier plus grand échouera :

ulimit -f 2 # Définit la limite à 2 blocs (chaque bloc est généralement de 512 octets, mais dépend de la configuration du système et de la commande)
# En pratique, avec bs=1, cela limite à 2 octets.
dd if=/dev/urandom of=fichier_test count=2 bs=1
# Succès, 2 octets écrits

dd if=/dev/urandom of=fichier_test count=3 bs=1
# Erreur : File size limit exceeded (core dumped)

Il est important de noter que ces limites sont spécifiques à chaque processus. Une limite définie dans une session de shell n'affectera pas une autre session indépendante.

Types de Limites de Ressources

Les limites de ressources peuvent être classées comme suit :

Limite Option ulimit Valeur par défaut (variable) Unité Description
Taille max. core dump -c illimitée Ko Taille maximale des fichiers core dump.
Taille max. segment data -d illimitée Ko Taille maximale du segment de données du processus.
Priorité de planification -e 0 - Priorité de planification du processus (nice).
Taille max. fichier -f illimitée Ko Taille maximale des fichiers créés par le processus.
Signaux en attente -i variable - Nombre maximal de signaux pouvant être en attente.
Mémoire verrouillable -l variable Ko Quantité maximale de mémoire pouvant être verrouillée.
Taille max. mémoire -m illimitée Ko Taille maximale de la mémoire résidente du processus.
Fichiers ouverts max. -n 1024 - Nombre maximal de descripteurs de fichiers ouverts.
Taille max. pipe -p 8 blocs de 512 octets Taille maximale des tubes (pipes).
File d'attente msg POSIX -q variable octets Taille maximale des files d'attente de messages POSIX.
Priorité temps réel -r 0 - Priorité de planification temps réel.
Taille max. pile -s 8192 Ko Taille maximale de la pile du processus.
Temps CPU max. -t illimité secondes Temps CPU maximal utilisable par le processus.
Processus utilisateur max. -u variable - Nombre maximal de processus pouvant être créés.
Mémoire virtuelle max. -v illimitée Ko Taille maximale de l'espace d'adressage virtuel.
Verrous de ficihers max. -x illimité - Nombre maximal de verrous de fichiers détenus.

L'option ulimit -a affiche toutes les limites actuelles pour le shell courant. Les valeurs marquées comme "variable" dépendent des ressources système disponibles (RAM, etc.).

Limites Douces (Soft) et Dures (Hard)

Les systèmes de type UNIX distinguent deux types de limites :

  • Limites Dures (Hard Limits) : Elles représentent la valeur maximale absolue. Un processus ne peut pas dépasser cette limite. Seul un processus privilégié (come root) peut augmenter une limite dure.
  • Limites Douces (Soft Limits) : Elles sont un niveau d'avertissement. Lorsqu'une limite douce est dépassée, le noyau envoie un signal au processus (par exemple, SIGXFSZ pour la taille de fichier, SIGXCPU pour le temps CPU). Si le processus ne gère pas ce signal et continue de dépasser la limite, il peut éventuellement être terminé par SIGKILL. Une limite douce peut être augmentée par un processus jusqu'à la limite dure correspondante.

On peut visualiser ces limites avec :

ulimit -aS # Pour les limites douces
ulimit -aH # Pour les limites dures

Sur la plupart des systèmes Linux, les limites douces et dures ne diffèrent que pour le nombre de fichiers ouverts et la taille de la pile.

Modification des Limites

  • Utilisateurs non privilégiés : Peuvent augmenter les limites douces jusqu'à la limite dure correspondante. Ils peuvent diminuer les limites dures, mais une fois réduites, elles ne peuvent plus être augmentées au-delà de leur nouvelle valeur par un utilisateur non privilégié.
  • Utilisateurs privilégiés (root) : Peuvent modifier à la fois les limites douces et dures sans restriction.

Une exception notable est la limite sur les fichiers core dump (-c), qu'un utilisateur peut augmenter pour faciliter le débogage.

Pour modifier une limite qui nécessite des privilèges (comme la limite de fichiers ouverts), il faut souvent utiliser sudo en combinaison avec l'exécution du shell :

# Vérifier la limite actuelle
ulimit -n
# 1024

# Augmenter la limite à 2000 en utilisant bash avec sudo
sudo bash -c "ulimit -n 2000 && exec ulimit -n"
# Entrer le mot de passe sudo...
# Vérifier à nouveau la limite
ulimit -n
# 2000

Notez que ulimit est une commande shell intégrée, donc sudo ulimit seul ne fonctionnera pas comme attendu.

La limite de taille des pipes est gérée différemment et ne peut pas être modifiée avec ulimit. Elle est configurée via /proc/sys/fs/pipe-max-size et peut être ajustée programmatiquement avec fcntl(2) et les opérations F_GETPIPE_SZ / F_SETPIPE_SZ.

L'outil prlimit

L'outil prlimit est une alternative plus moderne à ulimit. Il fonctionne comme un binaire exécutable et offre plus de flexibilité, notamment pour définir des limites pour un processus existant ou pour lancer un nouveau processus avec des limites spécifiques. Il est disponible sur les noyaux Linux 2.6.36 et supérieurs.

Syntaxe de base :

prlimit [options] [--resource[=limites]] [--pid PID]
prlimit [options] [--resource[=limites]] commande [argument...]

Cas d'utilisation :

  1. Afficher les limites de son propre processus :
prlimit

  1. Afficher les limites d'un autre processus (PID) :
prlimit --pid=1234

  1. Modifier les limites d'un processus existant :
prlimit --pid=1234 --fsize=2048000 --stack=12582912

  1. Lancer un programme avec des limites spécifiques : Supposons un programme calcul_primes qui génère des nombres premiers. On peut le limiter en temps CPU :
prlimit --cpu=2 ./calcul_primes 8000000 -2

Si le programme dépasse la limite de 2 secondes de temps CPU, il sera terminé par le noyau.

Killed

L'indication "Killed" montre que le processus a été terminé par le système d'exploitation.

Les informations sur les limites de ressources d'un processus sont également accessibles via le système de fichiers /proc/<pid>/limits.

Interfaces de Programmation

Pour interagir avec les limites de ressources par programmation, les appels système suivants sont disponibles :

  • getrlimit() : Récupère les limites actuelles.
  • setrlimit() : Définit les limites.
  • prlimit() : Version plus récente et plus flexible, permettant de modifier les limites d'un processus spécifique sans avoir besoin des privilèges de ce dernier (si l'appelant a les permissions nécessaires), et de lire/écrire les deux types de limites (douces et dures) en une seule opération.

L'appel système prlimit() (disponible à partir du noyau Linux 2.6.36) est défini comme suit :

#include <sys/resource.h>
int prlimit(pid_t pid, int resource,
            const struct rlimit *new_limit, struct rlimit *old_limit);

  • pid : L'identifiant du processus cible. Si 0, il s'agit du processus appelant.
  • resource : La ressource à consulter ou modifier (par exemple, RLIMIT_FSIZE).
  • new_limit : Un pointeur vers une structure rlimit contenant les nouvelles valeurs (limites douces et dures). Peut être NULL si on ne souhaite pas modifier.
  • old_limit : Un pointeur vers une structure rlimit où seront stockées les anciennes valeurs. Peut être NULL si on ne souhaite pas récupérer les anciennes valeurs.

La structure rlimit est définie comme :

struct rlimit {
    rlim_t rlim_cur; /* Limite douce */
    rlim_t rlim_max; /* Limite dure (plafond pour rlim_cur) */
};

Les différentes ressources sont définies par des constantes comme RLIMIT_CORE, RLIMIT_FSIZE, RLIMIT_NOFILE, etc.

Ressource Constante Enum Unité Description
Taille max. core dump RLIMIT_CORE Ko Taille maximale des fichiers core dump.
Taille max. segment data RLIMIT_DATA Ko Taille maximale du segment de données du processus.
Priorité de planification RLIMIT_NICE - Priorité de planification du processus (nice).
Taille max. fichier RLIMIT_FSIZE Ko Taille maximale des fichiers créés par le processus.
Signaux en attente RLIMIT_SIGPENDING - Nombre maximal de signaux pouvant être en attente.
Mémoire verrouillable RLIMIT_MEMLOCK Ko Quantité maximale de mémoire pouvant être verrouillée.
Fichiers ouverts max. RLIMIT_NOFILE - Nombre maximal de descripteurs de fichiers ouverts.
File d'attente msg POSIX RLIMIT_MSGQUEUE octets Taille maximale des files d'attente de messages POSIX.
Priorité temps réel RLIMIT_RTTIME microsecondes Temps CPU maximal utilisable par le processus temps réel.
Taille max. pile RLIMIT_STACK Ko Taille maximale de la pile du processus.
Temps CPU max. RLIMIT_CPU secondes Temps CPU maximal utilisable par le processus.
Processus utilisateur max. RLIMIT_NPROC - Nombre maximal de processus pouvant être créés.
Mémoire virtuelle max. RLIMIT_AS Ko Taille maximale de l'espace d'adressage virtuel.
Verrous de fichiers max. RLIMIT_LOCKS - Nombre maximal de verrous de fichiers détenus.

Étiquettes: gestion des ressources ulimit prlimit programmation système limites de ressources

Publié le 4 juin à 22h53