Skip to content

Linux Attitude

Le libre est un état d'esprit

Scotch

Nouveautés ext4 

Jan 20 Par peck

Niveau :      
Résumé : stats

Howdy ho !

Savez-vous ce qu'il y a de nouveau dans ext4 ?

Tout le monde sait à peu près qu'il y a moyen de stocker plus de fichiers et des fichiers plus gros que dans ext3. Bon c'est gentil, mais quand on ne s'appelle pas google ou la NSA, stocker des fichiers de plus de 2To n'est pas vraiment notre priorité.

De plus l'usage des extents, qui permet ce genre de choses, a l'avantage de réduire la fragmentation. Bien.

Passons à des choses plus sympathiques, savez-vous que ext4 peut stocker la liste des blocs inutilisés ? Ça n'a l'air de rien, mais du coup la durée de fsck n'est plus proportionnelle à la taille du volume, mais à la quantité de données stockées ! Enfin une bonne nouvelle.

Ext4 supporte la méthode discard, c'est à dire l'indication au block device que certains blocs ne sont plus utilisés. Cette fonctionnalité est indispensable pour conserver les performances des SSD sur le long terme.

Parlons des dates maintenant. Le format de stockage des dates a changé, ce qui veut dire deux choses : on est maintenant Y2038 safe et on peut maintenant stocker des dates précises à la nanoseconde.

De plus il est possible de stocker une date supplémentaire : la date de création (crtime). Cette information était un gros manque pour les habitués du système de Microsoft. En effet, il est trop facile et fréquent de toucher aux fichiers et par là même mettre à jour les dates du fichier. La date de création elle est immuable et permet de savoir quand est apparu un fichier.

Des nouveaux timestamps !

Ceux-ci dépendent d'une nouvelle fonctionnalité d'ext4 : les inodes de 256 octets. On ne peut donc avoir les timestamps à la nanoseconde et la date de création que sur des systèmes de fichiers fraîchement créés et pas sur des systèmes upgradés depuis ext3 s'ils avaient été créés avec la taille par défaut.

Pour pouvoir les stocker, il faut passer l'option -I 256 à la création du système de fichier.

$ mkfs.ext4 -I 256 /dev/sdXY

Et pour les utiliser ?
Sachant qu'il s'agit de fonctionnalités d'un système de fichiers, il faut passer par le VFS pour les utiliser. Le problème c'est que le VFS n'avait pas prévu ce cas. Il y a donc de nombreuses modifications à faire avant de les voir arriver dans ls : modifier le VFS pour avoir une fonction permettant de récupérer ces données, modifier l'appel système stat, modifier la libc, modifier ls et ses amis pour qu'ils affichent l'information.

C'est trop bête, nous avons l'information sur le disque et nous n'y avons pas accès. Heureusement, si on est root, un disque ça se lit, il suffit juste de savoir où est l'info et d'aller la chercher.

Lire la date de création d'un fichier

Je rappelle que les autres dates directement disponibles avec stat sont : atime (dernier accès), mtime (dernière modification du contenu) et ctime (dernière modification de métadonnées).

On récupère l'inode du fichier

$ stat -c%i fichier

On récupère la partition sur laquelle est stockée le fichier

$ df fichier | awk 'NR==1 {next} {print $1; exit}'

Et enfin on lit les infos directement sur le disque avec debugfs (il faut être root)

$ debugfs -R "stat <$inode>" /dev/sdaX

Ce qui agrégé en une ligne de commande donne pour le fichier $file :

$ file=/bin/ls; debugfs -R "stat <$(stat -c%i "$file")>" $(df "$file" | awk 'NR==1 {next} {print $1; exit}')  | grep time

Niveau :      
Résumé : hdparm -z /dev/used_device

Comment repartitionner un disque contenant une partition indispensable (par exemple /) sans rebooter ?

Si l'intégralité de votre disque est en LVM, cet article ne vous concerne pas puisque vous pouvez simplement redimensionner vos volumes LVM. Mais supposons que vous ayez au moins une "partition" que vous voulez redimensionner.

Posons une limite : il ne vous sera pas possible de toucher à une partition en cours d'utilisation et de prendre en compte cette modification sans rebooter ou la désactiver temporairement.

Une partition est dite utilisée si elle est montée ou activée en tant que swap, utilisée dans un MD lancé ou présente comme PV (physical volume) dans un VG (volume group) actif.

C'est Parti

Maintenant nous avons un disque dont une partition au moins est utilisée, et une autre (celle qu'on veut redimensionner ou déplacer) ne l'est pas.

Modifions la table des partitions avec fdisk (cfdisk ou parted feront l'affaire). Attention, pour toute autre opération qu'une création ou un changement du secteur de fin (déplacement), fdisk ne suffira pas.

Lorsque vous quittez l'outil et que vous écrivez sur le disque, celui-ci tente de relire la table des partitions. Puisqu'une des partitions est en cours d'utilisation, il vous indique qu'il n'a pas pu le faire.

Si vous pouvez libérer la partition temporairement, alors il suffit d'utiliser la commande suivante pour que sa table des partitions soit relue :

$ hdparm -z /dev/sdX

Supposons que vous ne puissiez pas libérer la partition. La solution est simplement d'utiliser un loopback ! Pour cela, récupérez l'offset à utiliser depuis la table de partition :

$ fdisk -lu /dev/sda | grep sda2
> /dev/sda2         1026048   286515199   142744576   83  Linux

Ici l'offset de début est 1026048*512 et celui de fin 286515199*512. Il n'y a plus qu'à créer le loopback. Attention pour la taille la formule est "secteur de fin - secteur de début + 1" car ces secteurs sont inclus :

# unités : octet
$ losetup -o $(($start*512)) --sizelimit $((($end-$start+1)*512)) -f --show /dev/sda 
# un message d'erreur apparait, mais il peut être ignoré

Et voilà, vous pouvez maintenant faire un resize2fs sur le device de loopback et/ou un mount directement !

PS :
On pourrait croire qu'on peut faire mieux avec device mapper et dmsetup. Mais en fait ce n'est pas possible car device mapper considère que le disque complet est en cours d'utilisation si une de ses partitions est utilisée.

Signer ses logs 

Nov 2 Par peck

Niveau :      
Résumé : syslog | openssl dgst

Vous êtes vous déjà posé la question de la sécurisation de vos logs ? Sont-ils accessibles ? modifiables ? Peut-on détecter une falsification ?

Comment faire pour que les logs ne soient pas altérés par une personne de peu de principes ? Je vous propose une solution qui n'est pas une solution miracle, mais c'est une solution qui sera une brique de plus dans votre défense en profondeur.

Nous allons signer cryptographiquement les logs pour que tout altération devienne visible comme le nez au milieu de la figure.

Signature et validation des logs

Je vous au préparé pour cela deux programmes (lien en fin d'article), l'un pour signer les logs, l'autre pour les valider. Bien sûr, on ne va pas signer les fichiers de logs directement, ça laisserait tout le temps à un attaquant de les modifier avant la signature. Nous allons plutôt nous insérer dans le système syslog pour disposer des lignes au fur et à mesure. Mais nous n'allons pas non plus signer toutes les lignes, ce serait trop lourd. Nous allons plutôt signer des blocs de lignes, par exemple une signature toutes les 100 lignes, sans oublier un timeout pour éviter que 99 lignes restent en mémoire trop longtemps..

Enfin une des fonctionnalités importante de ces outil est le chaînage. Le chaînage est le fait d'utiliser la signature du bloc précédent comme faisant partie du bloc suivant. Ceci garanti qu'il ne peut y avoir suppression ou ajout d'un bloc eu milieu d'une chaîne de blocs. Et tant qu'on y est nous pouvons aussi chaîner les fichiers pour obtenir le même résultat au niveau fichier.

Au final toute modification, ajout ou suppression de ligne entraine l'invalidation de la signature. Toute modification, ajout ou suppression de bloc ou de fichier de log entraine l'invalidation de la signature.

Voici donc un exemple d'usage sous forme de pipe :

$ openssl genrsa -out key.pem 1024 # il nous fait une clé de signature
$ echo "Log important" | signlogger -k key.pem -f logfile

Notez que c'est utilisable avec syslog puisque celui-ci vous permet d'utiliser un pipe à la place d'un fichier. Je ne détaille pas cela ici car cela dépend du sylog que vous utilisez (syslogd, syslog-ng, rsyslog ...).

Et pour vérifier que votre fichier de log n'a pas été modifié ?

$ openssl rsa -in key.pem -pubout > pubkey.pem # on récupère la version publique de la clé
$ signvalidator -k pubkey.pem -f logfile

Si vous voulez utilisez cet outil avant logger ou avant l'envoi à un serveur centralisé, il faudra modifier signvalidator pour qu'il ignore les éléments ajoutés par syslog dans la vérification de la signature (date, pid, ...).

Usage

Dans la vraie vie quand on parle de sécurité, il faut se demander de quoi on veut se prémunir.

Signer les logs a pour but d'éviter qu'on puisse modifier les logs a posteriori, puisqu'on n'empêche personne de transformer les logs avant qu'ils ne soient envoyés à syslog. Mais toute personne qui a accès en écriture aux logs a posteriori, a les mêmes droits que le processus qui écrit les logs. Il a donc accès au système de signature.

Mais alors qu'a-t-on gagné ?

Tout d'abord, un difficulté légèrement accrue pour un attaquant, c'est pas grand chose, mais ça peut toujours servir. Ensuite, il nous suffit maintenant de séparer les droits du système de chiffrement de ceux du système d'écriture pour enfin détecter la modification par une personne possédant les droits d'écriture.

Pour cela vous avez plusieurs moyens à votre disposition :

  • utiliser des pipes et des des utilisateurs séparés pour la signature et pour l'écriture
  • utiliser l'attribut append only des fichiers de log pour interdire toute modification du fichier a posteriori (sauf par root qui peut retirer l'attribut)
  • utiliser un medium read only pour écrire les logs
  • utiliser un HSM pour interdire la réutilisation de la clé
  • déporter les logs vers un serveur syslog

Ou toute combinaison de ceux-ci.

Vous remarquerez que ces techniques ont déjà pour but d'empêcher la modification des logs a posteriori. La signature n'apporte qu'une preuve supplémentaire.

Mais prenez l'exemple du serveur syslog centralisé. On ne peut plus modifier les logs depuis le client, mais on le peut toujours depuis le serveur. La signature, si elle est effectuée côté client permet d'apporter une garantie supplémentaire puisqu'il faut cette fois un accès coté client ET côté serveur pour effecture la modification.

Si on y ajoute l'append only, il faut être root, si on y ajoute le HSM, il faut disposer d'une carte à puce ou d'un mot de passe, si on y ajoute un media read only, il faut disposer d'un accès physique pour le modifier. Et chacun de ces éléments peut être géré par une personne différente pour rendre impossible toute modification par une unique personne malintentionnée.

A vous de choisir votre niveau de sécurité !

En détail

Je vous colle ici l'usage complet des commandes (c'est du perl pour ceux qui veulent savoir)

$ signlogger --help
Usage:
    signlogger [options]

      Options
            --key|-k keyfile         Use private key for signing (PEM encoded)
            --file|-f file           Log to file instead of stdout
            --lastsig|-l line        Use line as last signature (used for chaining)
            --initfile|-i file       Use last line of file as last signature (used for chaining)
            --blocksize|-b lines     Insert signature each "lines" count (default 50)
            --timestamp|-t seconds   Insert signature each "seconds" seconds (default 30mn)
            --help|-h                This help

$ signvalidator --help
Usage:
    signvalidator [options]

      Options
            --key|-k keyfile        Use public key for validation (PEM encoded)
            --file|-f file          Read file instead of stdin
            --lastsig|-l line       Use line as last signature (used for chaining)
            --initfile|-i file      Use last line of file as last signature (used for chaining)
            --help|-h               This help

Et pour les télécharger :

Log de l’historique 

Sep 12 Par peck

Niveau :      
Résumé : trap DEBUG ; PROMPT_COMMAND

Voici comment loguer l'activité d'un utilisateur.

Mais tout d'abord, commençons par apprendre comment envoyer une ligne dans syslog. C'est simple, il suffit d'appeler logger avec les options qui vous intéressent (toutes optionnelles) et un message :

$ logger -i -p local5.info -t bash "$(tty): Bonjour syslog"

On enregistre le pid (option -i) pour permettre la corrélation avec d'autres lignes de logs.

On utilise la facility local5 qui est une sorte de tag utilisé par syslog pour savoir dans quelle catégorie mettre les logs. Les facilities servent essentiellement à faire des règles de tri des logs (par exemple il y a une facility authpriv pour tout ce qui est authentification). Il y a 8 facilities disponible pour les administrateur qui voudraient utiliser des valeurs qui ne sont pas standard. J'ai choisi local5.

On utilise le niveau de log info qui est quelque chose de standard parmi les systèmes de logs en général et permet de filtrer facilement.

On en profite pour loguer le tty en cours pour permettre une corrélation avec la commande last (on ne sait jamais).

Nous avons aussi besoin de la commande capable de nous donner la dernière commande tapée :

# lister la dernière commande sans son numéro
$ fc -ln -1

Il n'y a plus qu'à mettre l'une de ces lignes dans le fichier /etc/profile qui est lu par bash au lancement de sessions interactives :

# envoyer la commande dans syslog pour chaque commande AVANT exécution
$ trap 'logger -i -p local5.info -t bash "$USER $(tty): $(fc -ln -1)"' DEBUG

# envoyer la commande dans syslog pour chaque commande APRES exécution
$ PROMPT_COMMAND='logger -i -p local5.info -t bash "$USER $(tty): $(history 1)"'
# fc ne marche pas correctement dans PROMPT_COMMAND

Pourquoi

Enregistrer cette info peut être utile puisque les logs ne sont pas modifiables par un utilisateur simple. Et si vous avez un serveur syslog centralisé, ils ne le sont même pas par root depuis la machine d'origine.

Mais ceci ne doit pas vous faire oublier eux choses.

Tout d'abord le shell est un processus lancé par l'utilisateur, ce qui veut dire que l'enregistrement de cette information est nécessairement soumis à la bonne volonté de l'utilisateur. Un utilisateur peut supprimer le trap ou remplacer le PROMPT_COMMAND. Et supposons que vous trouviez un moyen pour l'en empêcher, l'utilisateur peut toujours tuer son propre shell, lui faire faire un exec vers un autre shell n'ayant pas de logs, tracer son shell pour modifier son activité etc.

Ensuite il faut être bien conscient de ce qu'on enregistre. On enregistre l'activité interactive d'un shell. Ceci exclue les transferts de fichiers (scp,...), les exécutions automatiques (cron, ...), les exécutions via un code (vi script; ./script). Et si on regarde bien ce dernier cas, on comprend qu'à moins de loguer tous les appels systèmes avec tous leurs paramètres, il est impossible de garantir qu'un utilisateur malveillant n'a pas exécuté une commande.

En conclusion ce système n'est pas là pour garantir l'enregistrement de toute activité d'un utilisateur plus ou moins malveillant, mais ça peut être une piste de recherche parmi d'autres lorsqu'un problème survient (qui a supprimé ma libc ?).

Réparer une debian 

Sep 1 Par peck

Niveau :      
Résumé : debsums ; dpkg -S ; apt-get install --reinstall

Si vous avez bidouillé une debian en installant un logiciel sans passer par dpkg par exemple, ou si quelqu'un vous a fait une mauvaise blague et qu'il y a des problèmes dans les logiciels installés, alors il y a un moyen pour vérifier si le problème vient d'un fichier modifié :

$ apt-get install debsums
$ debsums -c

Debsums est un outil debian qui fait un hash de tous les fichiers installés par des paquets debian et le compare au hash provenant du paquet original. L'option -c permet de lister tous les fichiers qui posent problème. Cela ne vous prémunit pas des attaquants qui pourraient aussi modifier la base des paquets, mais c'est utile pour toute manipulation plus ou moins volontaire du système.

Une fois la liste des fichiers modifiés récupérée, il nous reste à trouver dans quel paquet se trouvait le fichier en question :

$ dpkg -S /bin/ls # nous indique que ls est dans le paquet coreutils

Et maintenant passons à l'étape réparation :

# retélécharge et réinstalle tous les binaires d'un paquet déjà installé
$ apt-get install --reinstall lepaquet

Et pour ceux qui voudraient faire une réinstallation complète de leur distribution :

$ dpkg --get-selections | grep install | awk '{print $1}' | xargs  apt-get install --reinstall --yes

Mais comme dit le commentaire ci-dessous cela ne marche que si vous ne faite pas de pinning et si votre distribution est à jour. La commande suivante permet de ne pas changer les versions des paquets :

$ dpkg -l | grep ^ii | awk ‘{print $2″="$3}’ | xargs apt-get install -reinstall -s -t release-cible

Les dates de fichier 

Aug 22 Par peck

Niveau :      
Résumé : atime, ctime, mtime, crtime

Je constate que je n'ai jamais fait d'article sur les dates de fichier, c'est bien dommage car on me pose souvent la question. Voila qui va régler ce malentendu.

ctime et mtime

Unix depuis très longtemps ne stocke pas la date de création d'un fichier (contrairement à windows). A la place il stocke 3 dates au format timestamp unix. Les plus difficiles à comprendre sont mtime et ctime. Mais en réalité c'est simple, il suffit d'apprendre leur nom :

  • mtime : modification time, date de dwœernière modification du contenu du fichier
  • ctime : change time, date de dernier changement des métadonnées du fichier (par exemple le propriétaire)

Rien que pour vous, j'ai un moyen antimnémotechnique : M comme Contenu et C comme Métadonnée. Je ne sais pas vous, mais moi ça marche.

Attention, la modification du contenu d'un fichier modifie sa date de modification, qui est une métadonnée ... Elle modifie donc aussi sa date de changement. En conséquence de quoi on a toujours ctime >= mtime.

atime

Historiquement unix a eu l'idée originale de stocker la date de dernier accès à un fichier, le atime (access time). Ça a l'air cool, mais en réalité c'est une fausse bonne idée car elle interfère avec la notion fondamentale de lecture. En effet, pour mettre à jour le atime, chaque lecture impliquera une écriture.

Plus le temps passe plus le atime est problématique. Ça a commencé avec les sites web qui avaient des problèmes de performance à cause de la mise à jour du atime lors de la lecture des fichiers. On a alors inventé la possibilité de désactiver le atime au montage (option noatime).

Puis ça continue avec le SSD, écrire le atime implique une écriture toute petite à chaque lecture de fichier, ce qui implique la modification d'un inode et donc d'un block disque. Et avec le fonctionnement du SSD cela implique la lecture et la réécriture d'un gros bloc de données, donc des problèmes de performances. Puisque le atime reste utilisé par quelques applications (aussi rares soient-elles), on a inventé l'option relatime, qui ne met a jour le atime que s'il était égal ou antérieur au ctime. Ça permet de détecter une lecture depuis la dernière modification tout en faisant sauter un grand nombre de mises à jour du atime (mais pas toutes).

Le problème suivant intervient avec les snapshots, lorsqu'on utilise des snapshots de disques (à travers LVM ou à travers un serveur de VM), on se retrouve à mettre à jour le disque de snapshot et donc occuper de l'espace disque rien qu'en le lisant. Le summum étant atteint avec btrfs. Si vous faites un snapshot avec btrfs il ne vous prendra quasiment aucune place sur le disque. Si vous faites un find sur ce snapshot, la mise à jour du atime va quasiment remplir l'espace disque du snapshot d'une copie complète des données originales.

Conclusion, oubliez le atime ...

crtime

Comme je vous l'ai dit, windows stocke la date de création, c'est donc tout naturellement que les linuxiens ont voulu la même fonctionnalité. C'est enfin chose faite avec ext4. En effet, ext4 a profité de l'agrandissement de la taille des inode (de 128 à 256) pour stocker plus d'informations, celles-ci incluent la date à la nanoseconde près et la date de création.

Cool, mais comment fait-on ?

Malheureusement, les outils habituels n'ont pas encore été mis à jour pour récupérer cette information. Il nous faut donc le faire à la main :

# d'abord on récupère le numéro d'inode du fichier
$ stat --format "%i" /chemin/vers/le/fichier
# puis on récupère la date de création
$ debugfs -R 'stat <123456>' /dev/partition | grep crtime

Notez que ça ne marche que sur des partitions ayant des inodes de 256 octets, ce qui exclue les systèmes de fichiers mis à jour depuis ext2 et ceux venant d'un ext3 avec des inodes de 128 octets.

56 pages