Dd if = / dev / urandom of = / dev / mem est-il sûr?
10
Qu'est-ce que cela fait exactement? Je ne comprends pas comment vous pouvez accéder à la mémoire de base avec ça ... ça semble un peu bizarre. Est-ce sûr?
Quel est ce "coffre-fort" dont vous parlez? Sûr par rapport à quoi?
waltinator
Que voulez-vous réaliser avec cette commande?
jochen
Réponses:
23
N'essayez pas ca a la maison! Cela peut planter votre système et si vous n'avez vraiment pas de chance, cela pourrait endommager un périphérique ou rendre votre ordinateur non amorçable.
En fait, sur la plupart des plates-formes, il échoue simplement avec une erreur, mais cela dépend de l'architecture matérielle. Il n'y a certainement aucune garantie que cela est inoffensif, sauf si vous exécutez la commande en tant qu'utilisateur non privilégié. Avec un utilisateur non privilégié, la commande est parfaitement inoffensive car vous ne pouvez pas l'ouvrir /dev/mem.
Lorsque vous exécutez une commande en tant que root, vous êtes censé savoir ce que vous faites. Le noyau vous empêchera parfois de faire quelque chose de dangereux, mais pas toujours. /dev/memest l'une de ces choses potentiellement dangereuses où vous êtes vraiment censé savoir ce que vous faites.
Je vais vous expliquer comment fonctionne une écriture /dev/memsur Linux. Le principe général serait le même sur d'autres Unices, mais des choses comme les options du noyau sont complètement différentes.
Que se passe-t-il lorsqu'un processus lit ou écrit dans un fichier de périphérique dépend du noyau. Un accès à un fichier de périphérique exécute du code dans le pilote qui gère ce fichier de périphérique. Par exemple, écrire pour /dev/memappeler la fonction write_memdansdrivers/char/mem.c . Cette fonction prend 4 arguments: une structure de données qui représente le fichier ouvert, un pointeur sur les données à écrire, le nombre d'octets à écrire et la position actuelle dans le fichier.
Notez que vous n'irez jusque-là que si l'appelant était autorisé à ouvrir le fichier en premier lieu. Les fichiers de périphérique obéissent normalement aux autorisations de fichier. Les autorisations normales de /dev/memsont crw-r-----détenues par root:kmem, donc si vous essayez de l'ouvrir pour l'écriture sans être root, vous obtiendrez simplement «permission refusée» (EACCESS). Mais si vous êtes root (ou si root a changé les permissions de ce fichier), l'ouverture passe et vous pouvez alors tenter une écriture.
Le code de la write_memfonction fait quelques vérifications d'intégrité, mais ces vérifications ne suffisent pas pour se protéger contre tout ce qui est mauvais. La première chose qu'il fait est de convertir la position actuelle du fichier *pposen une adresse physique. Si cela échoue (en pratique, parce que vous êtes sur une plate-forme avec des adresses physiques 32 bits mais des décalages de fichiers 64 bits et que le décalage de fichier est supérieur à 2 ^ 32), l'écriture échoue avec EFBIG (fichier trop volumineux). La vérification suivante consiste à savoir si la plage d'adresses physiques à écrire est valide sur cette architecture de processeur particulière, et une défaillance entraîne EFAULT (mauvaise adresse).
Ensuite, sur Sparc et m68k, toute partie de l'écriture dans la toute première page physique est ignorée en silence.
Nous avons maintenant atteint la boucle principale qui itère sur les données dans des blocs qui peuvent tenir dans une seule page MMU .
/dev/memaccède à la mémoire physique, pas à la mémoire virtuelle, mais les instructions du processeur pour charger et stocker des données dans la mémoire utilisent des adresses virtuelles, de sorte que le code doit organiser pour mapper la mémoire physique à une adresse virtuelle. Sous Linux, selon l'architecture du processeur et la configuration du noyau, ce mappage existe de façon permanente ou doit être fait à la volée; c'est le travail de xlate_dev_mem_ptr(et unxlate_dev_mem_ptrannule tout ce qui xlate_dev_mem_ptrfait). Ensuite, la fonction copy_from_userlit à partir du tampon qui a été transmis à lawriteappel système et écrit simplement à l'adresse virtuelle où la mémoire physique est actuellement mappée. Le code émet des instructions de stockage de mémoire normales, et ce que cela signifie dépend du matériel.
Avant de discuter de ce qu'une écriture à une adresse physique fait, je vais discuter d'une vérification qui se produit avant cette écriture. A l'intérieur de la boucle, la fonction page_is_allowedbloque l'accès à certaines adresses si l'option de configuration du noyau CONFIG_STRICT_DEVMEMest activée (ce qui est le cas par défaut): seules les adresses autorisées par devmem_is_allowedpeuvent être atteintes /dev/mem, pour d'autres l'écriture échoue avec EPERM (opération non autorisée). La description de cette option indique:
Si cette option est activée et IO_STRICT_DEVMEM = n, le fichier / dev / mem autorise uniquement l'accès de l'espace utilisateur à l'espace PCI et au code BIOS et aux régions de données. C'est suffisant pour dosemu et X et tous les utilisateurs courants de / dev / mem.
C'est une description très centrée sur x86. En fait, de manière plus générique, CONFIG_STRICT_DEVMEMbloque l'accès aux adresses de mémoire physique qui sont mappées à la RAM, mais autorise l'accès aux adresses qui ne mappent pas à la RAM. Les détails des plages d'adresses physiques autorisées dépendent de l'architecture du processeur, mais tous excluent la RAM où sont stockées les données du noyau et des processus terrestres de l'utilisateur. L'option supplémentaire CONFIG_IO_STRICT_DEVMEM(désactivée à partir d'Ubuntu 18.04) bloque les accès aux adresses physiques revendiquées par un pilote.
Adresses de la mémoire physique mappées à la RAM . Il existe donc des adresses de mémoire physique qui ne sont pas mappées à la RAM? Oui. C'est la discussion que j'ai promise ci-dessus sur ce que signifie écrire à une adresse.
Une instruction de stockage en mémoire n'écrit pas nécessairement dans la RAM. Le processeur décompose l'adresse et décide vers quel périphérique envoyer le magasin. (Quand je dis «le processeur», j'englobe les contrôleurs périphériques qui peuvent ne pas provenir du même fabricant.) La RAM n'est qu'un de ces périphériques. La manière dont la répartition est effectuée dépend beaucoup de l'architecture du processeur, mais les principes fondamentaux sont plus ou moins les mêmes sur toutes les architectures. Le processeur décompose essentiellement les bits supérieurs de l'adresse et les recherche dans certaines tables qui sont remplies en fonction des informations codées en dur, des informations obtenues en sondant certains bus et des informations configurées par le logiciel. Beaucoup de mise en cache et de mise en mémoire tampon peuvent être impliqués, mais en un mot, après cette décomposition,bus et ensuite c'est au périphérique de s'en occuper. (Ou le résultat de la recherche de table pourrait être qu'il n'y a pas de périphérique à cette adresse, auquel cas le processeur entre dans un état d' interruption où il exécute du code dans le noyau qui se traduit normalement par un SIGBUS pour le processus appelant.)
Un magasin à une adresse mappée à la RAM ne «fait» rien d'autre que d'écraser la valeur précédemment stockée à cette adresse, avec la promesse qu'un chargement ultérieur à la même adresse restituera la dernière valeur stockée. Mais même la RAM a quelques adresses qui ne se comportent pas de cette façon: elle a quelques registres qui peuvent contrôler des choses comme le taux de rafraîchissement et la tension.
En général, une lecture ou une écriture dans un registre matériel fait tout ce que le matériel est programmé pour faire. La plupart des accès au matériel fonctionnent de cette façon: le logiciel (normalement le code du noyau) accède à une certaine adresse physique, cela atteint le bus qui connecte le processeur au périphérique, et le périphérique fait son travail. Certains processeurs (en particulier x86) ont également des instructions CPU distinctes qui provoquent des lectures / écritures sur des périphériques distincts de la charge de la mémoire et du stockage, mais même sur x86, de nombreux périphériques sont accessibles via le chargement / stockage.
La commande dd if=/dev/urandom of=/dev/memécrit des données aléatoires sur le périphérique mappé à l'adresse 0 (et aux adresses suivantes, tant que les écritures réussissent). Dans la pratique, je m'attends à ce que sur de nombreuses architectures, l'adresse physique 0 ne dispose d'aucun périphérique mappé ou de RAM, et donc la toute première tentative d'écriture échoue. Mais s'il y a un périphérique mappé à l'adresse 0, ou si vous changez la commande pour écrire dans une adresse différente, vous déclencherez quelque chose d'imprévisible dans le périphérique. Avec des données aléatoires à des adresses croissantes, il est peu probable de faire quelque chose d'intéressant, mais en principe, cela pourrait éteindre l'ordinateur (il y a probablement une adresse qui le fait en fait), écraser certains paramètres du BIOS qui rendent impossible le démarrage, ou même frapper certains buggy périphérique d'une manière qui l'endommage.
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
Je vous remercie! C'est ce que je cherchais! J'étais juste confus si / dev / mem autorise l'accès en mémoire à des choses comme les périphériques et les choses liées au matériel!
Coder14
Un périphérique ne peut pas être mappé à l'adresse physique 0 sur un PC x86; cette configuration ne démarrerait jamais.
Joshua
Ce n'est pas vrai
Yvain
1
Bien sûr, vous pouvez endommager le noyau mais pas le bios
Yvain
1
@Yvain Qu'est - ce qui n'est pas vrai? Et en fait, vous ne pouvez pas endommager le noyau s'il CONFIG_STRICT_DEVMEMest activé.
Gilles 'SO- arrête d'être méchant'
12
Il est sûr, si vous avez correctement configuré le noyau (sûr car cela ne fonctionnera pas)
/ dev / mem est un fichier de périphérique de caractères qui est une image de la mémoire principale de l'ordinateur. Il peut être utilisé, par exemple, pour examiner (et même corriger) le système.
Donc, en théorie, cela dd if=/dev/urandom of=/dev/memdevrait remplacer tout l'espace d'adressage de la mémoire physique que vous avez installée, et puisque le noyau et d'autres programmes s'exécutent à partir de la mémoire, cela devrait effectivement planter le système. En pratique, il y a des limites. De la même page de manuel:
Depuis Linux 2.6.26, et selon l'architecture, l'option de configuration du noyau CONFIG_STRICT_DEVMEM limite les zones accessibles via ce fichier.
En essayant cela sur la machine virtuelle Ubuntu 18.04, cela renvoie une erreur dd: writing to '/dev/mem': Operation not permittedmême avec sudoet malgré les autorisations pour root crw-r-----. Depuis Ubuntu Wiki :
/ dev / mem protection
Certaines applications (Xorg) nécessitent un accès direct à la mémoire physique depuis l'espace utilisateur. Le fichier spécial / dev / mem existe pour fournir cet accès. Dans le passé, il était possible d'afficher et de modifier la mémoire du noyau à partir de ce fichier si un attaquant avait un accès root. L'option de noyau CONFIG_STRICT_DEVMEM a été introduite pour bloquer l'accès à la mémoire hors périphérique (initialement nommé CONFIG_NONPROMISC_DEVMEM).
Donc techniquement, non, ce n'est pas sûr (car cela planterait le système) et si l'option du noyau CONFIG_STRICT_DEVMEMest désactivée, c'est une faille de sécurité, mais d'après ce que je vois jusqu'à présent, la commande ne s'exécuterait pas si cette option était activée. Selon le doublon intersite , un redémarrage résoudra tous les problèmes, mais bien sûr, les données dans la RAM à ce moment-là seraient perdues et non vidées sur le disque (le cas échéant).
Il existe une méthode suggérée pour le doublon lié plus tôt, busybox devmemdonc si vous êtes déterminé à jouer avec la RAM, il peut y avoir un moyen après tout.
«C'est sûr» Non, ce n'est certainement pas le cas. Même avec CONFIG_STRICT_DEVMEM, vous pouvez accéder aux régions de mémoire où un périphérique est mappé, ce qui est tout l'intérêt d'avoir /dev/mem. Si vous écrivez des éléments aléatoires sur des périphériques, tout peut arriver. Vous obtenez «opération non autorisée» si vous essayez d'accéder à une adresse qui n'est pas mappée, et la commande démarre à l'adresse 0. L'adresse 0 correspond à quelque chose de mauvais dépend de l'architecture matérielle. Pour autant que je sache, il pourrait ne jamais correspondre à quoi que ce soit sur un PC, mais ce n'est pas sûr en général.
Gilles 'SO- arrête d'être méchant'
1
@Gilles Sur x86 (pas sûr de x86-64), les 1 premiers Ko de RAM (adresses 0x0 à 0x3ff) contiennent les vecteurs d'interruption; quatre octets d'adresse par vecteur. Si vous réussissez à écraser ceux avec des déchets aléatoires, toutes sortes de choses intéressantes sont susceptibles de se produire très bientôt. Très probablement, vous vous retrouverez avec une faute double ou triple et le système plantera, mais il n'y a aucune garantie ...
un CVn le
@aCVn Il y a certainement quelque chose de mappé ( head -c 1024 </dev/mem | od -tx1), mais je ne sais pas si ceux-ci sont utilisés lorsque le processeur n'est pas en mode réel (mode 8088). Je ne pense pas qu'ils puissent être utilisés en mode 64 bits: après tout, les vecteurs d'interruption 8088 n'ont que 32 bits pour l'adresse. Et d'ailleurs, cela est accessible avec CONFIG_STRICT_DEVMEMset, donc je suppose que Linux ne l'utilise pas.
Gilles 'SO- arrête d'être méchant'
@Gilles: La page 0 sur x86 est réservée à v86, bootloader, etc; c'est la table des vecteurs d'interruption en mode réel. En mode protégé, l'IVT est ailleurs (un registre de machine indique où).
Réponses:
N'essayez pas ca a la maison! Cela peut planter votre système et si vous n'avez vraiment pas de chance, cela pourrait endommager un périphérique ou rendre votre ordinateur non amorçable.
En fait, sur la plupart des plates-formes, il échoue simplement avec une erreur, mais cela dépend de l'architecture matérielle. Il n'y a certainement aucune garantie que cela est inoffensif, sauf si vous exécutez la commande en tant qu'utilisateur non privilégié. Avec un utilisateur non privilégié, la commande est parfaitement inoffensive car vous ne pouvez pas l'ouvrir
/dev/mem
.Lorsque vous exécutez une commande en tant que root, vous êtes censé savoir ce que vous faites. Le noyau vous empêchera parfois de faire quelque chose de dangereux, mais pas toujours.
/dev/mem
est l'une de ces choses potentiellement dangereuses où vous êtes vraiment censé savoir ce que vous faites.Je vais vous expliquer comment fonctionne une écriture
/dev/mem
sur Linux. Le principe général serait le même sur d'autres Unices, mais des choses comme les options du noyau sont complètement différentes.Que se passe-t-il lorsqu'un processus lit ou écrit dans un fichier de périphérique dépend du noyau. Un accès à un fichier de périphérique exécute du code dans le pilote qui gère ce fichier de périphérique. Par exemple, écrire pour
/dev/mem
appeler la fonctionwrite_mem
dansdrivers/char/mem.c
. Cette fonction prend 4 arguments: une structure de données qui représente le fichier ouvert, un pointeur sur les données à écrire, le nombre d'octets à écrire et la position actuelle dans le fichier.Notez que vous n'irez jusque-là que si l'appelant était autorisé à ouvrir le fichier en premier lieu. Les fichiers de périphérique obéissent normalement aux autorisations de fichier. Les autorisations normales de
/dev/mem
sontcrw-r-----
détenues parroot:kmem
, donc si vous essayez de l'ouvrir pour l'écriture sans être root, vous obtiendrez simplement «permission refusée» (EACCESS). Mais si vous êtes root (ou si root a changé les permissions de ce fichier), l'ouverture passe et vous pouvez alors tenter une écriture.Le code de la
write_mem
fonction fait quelques vérifications d'intégrité, mais ces vérifications ne suffisent pas pour se protéger contre tout ce qui est mauvais. La première chose qu'il fait est de convertir la position actuelle du fichier*ppos
en une adresse physique. Si cela échoue (en pratique, parce que vous êtes sur une plate-forme avec des adresses physiques 32 bits mais des décalages de fichiers 64 bits et que le décalage de fichier est supérieur à 2 ^ 32), l'écriture échoue avec EFBIG (fichier trop volumineux). La vérification suivante consiste à savoir si la plage d'adresses physiques à écrire est valide sur cette architecture de processeur particulière, et une défaillance entraîne EFAULT (mauvaise adresse).Ensuite, sur Sparc et m68k, toute partie de l'écriture dans la toute première page physique est ignorée en silence.
Nous avons maintenant atteint la boucle principale qui itère sur les données dans des blocs qui peuvent tenir dans une seule page MMU .
/dev/mem
accède à la mémoire physique, pas à la mémoire virtuelle, mais les instructions du processeur pour charger et stocker des données dans la mémoire utilisent des adresses virtuelles, de sorte que le code doit organiser pour mapper la mémoire physique à une adresse virtuelle. Sous Linux, selon l'architecture du processeur et la configuration du noyau, ce mappage existe de façon permanente ou doit être fait à la volée; c'est le travail dexlate_dev_mem_ptr
(etunxlate_dev_mem_ptr
annule tout ce quixlate_dev_mem_ptr
fait). Ensuite, la fonctioncopy_from_user
lit à partir du tampon qui a été transmis à lawrite
appel système et écrit simplement à l'adresse virtuelle où la mémoire physique est actuellement mappée. Le code émet des instructions de stockage de mémoire normales, et ce que cela signifie dépend du matériel.Avant de discuter de ce qu'une écriture à une adresse physique fait, je vais discuter d'une vérification qui se produit avant cette écriture. A l'intérieur de la boucle, la fonction
page_is_allowed
bloque l'accès à certaines adresses si l'option de configuration du noyauCONFIG_STRICT_DEVMEM
est activée (ce qui est le cas par défaut): seules les adresses autorisées pardevmem_is_allowed
peuvent être atteintes/dev/mem
, pour d'autres l'écriture échoue avec EPERM (opération non autorisée). La description de cette option indique:C'est une description très centrée sur x86. En fait, de manière plus générique,
CONFIG_STRICT_DEVMEM
bloque l'accès aux adresses de mémoire physique qui sont mappées à la RAM, mais autorise l'accès aux adresses qui ne mappent pas à la RAM. Les détails des plages d'adresses physiques autorisées dépendent de l'architecture du processeur, mais tous excluent la RAM où sont stockées les données du noyau et des processus terrestres de l'utilisateur. L'option supplémentaireCONFIG_IO_STRICT_DEVMEM
(désactivée à partir d'Ubuntu 18.04) bloque les accès aux adresses physiques revendiquées par un pilote.Adresses de la mémoire physique mappées à la RAM . Il existe donc des adresses de mémoire physique qui ne sont pas mappées à la RAM? Oui. C'est la discussion que j'ai promise ci-dessus sur ce que signifie écrire à une adresse.
Une instruction de stockage en mémoire n'écrit pas nécessairement dans la RAM. Le processeur décompose l'adresse et décide vers quel périphérique envoyer le magasin. (Quand je dis «le processeur», j'englobe les contrôleurs périphériques qui peuvent ne pas provenir du même fabricant.) La RAM n'est qu'un de ces périphériques. La manière dont la répartition est effectuée dépend beaucoup de l'architecture du processeur, mais les principes fondamentaux sont plus ou moins les mêmes sur toutes les architectures. Le processeur décompose essentiellement les bits supérieurs de l'adresse et les recherche dans certaines tables qui sont remplies en fonction des informations codées en dur, des informations obtenues en sondant certains bus et des informations configurées par le logiciel. Beaucoup de mise en cache et de mise en mémoire tampon peuvent être impliqués, mais en un mot, après cette décomposition,bus et ensuite c'est au périphérique de s'en occuper. (Ou le résultat de la recherche de table pourrait être qu'il n'y a pas de périphérique à cette adresse, auquel cas le processeur entre dans un état d' interruption où il exécute du code dans le noyau qui se traduit normalement par un SIGBUS pour le processus appelant.)
Un magasin à une adresse mappée à la RAM ne «fait» rien d'autre que d'écraser la valeur précédemment stockée à cette adresse, avec la promesse qu'un chargement ultérieur à la même adresse restituera la dernière valeur stockée. Mais même la RAM a quelques adresses qui ne se comportent pas de cette façon: elle a quelques registres qui peuvent contrôler des choses comme le taux de rafraîchissement et la tension.
En général, une lecture ou une écriture dans un registre matériel fait tout ce que le matériel est programmé pour faire. La plupart des accès au matériel fonctionnent de cette façon: le logiciel (normalement le code du noyau) accède à une certaine adresse physique, cela atteint le bus qui connecte le processeur au périphérique, et le périphérique fait son travail. Certains processeurs (en particulier x86) ont également des instructions CPU distinctes qui provoquent des lectures / écritures sur des périphériques distincts de la charge de la mémoire et du stockage, mais même sur x86, de nombreux périphériques sont accessibles via le chargement / stockage.
La commande
dd if=/dev/urandom of=/dev/mem
écrit des données aléatoires sur le périphérique mappé à l'adresse 0 (et aux adresses suivantes, tant que les écritures réussissent). Dans la pratique, je m'attends à ce que sur de nombreuses architectures, l'adresse physique 0 ne dispose d'aucun périphérique mappé ou de RAM, et donc la toute première tentative d'écriture échoue. Mais s'il y a un périphérique mappé à l'adresse 0, ou si vous changez la commande pour écrire dans une adresse différente, vous déclencherez quelque chose d'imprévisible dans le périphérique. Avec des données aléatoires à des adresses croissantes, il est peu probable de faire quelque chose d'intéressant, mais en principe, cela pourrait éteindre l'ordinateur (il y a probablement une adresse qui le fait en fait), écraser certains paramètres du BIOS qui rendent impossible le démarrage, ou même frapper certains buggy périphérique d'une manière qui l'endommage.la source
CONFIG_STRICT_DEVMEM
est activé.Il est sûr, si vous avez correctement configuré le noyau (sûr car cela ne fonctionnera pas)
Par page de manuel mem (4) :
Donc, en théorie, cela
dd if=/dev/urandom of=/dev/mem
devrait remplacer tout l'espace d'adressage de la mémoire physique que vous avez installée, et puisque le noyau et d'autres programmes s'exécutent à partir de la mémoire, cela devrait effectivement planter le système. En pratique, il y a des limites. De la même page de manuel:En essayant cela sur la machine virtuelle Ubuntu 18.04, cela renvoie une erreur
dd: writing to '/dev/mem': Operation not permitted
même avecsudo
et malgré les autorisations pour rootcrw-r-----
. Depuis Ubuntu Wiki :Donc techniquement, non, ce n'est pas sûr (car cela planterait le système) et si l'option du noyau
CONFIG_STRICT_DEVMEM
est désactivée, c'est une faille de sécurité, mais d'après ce que je vois jusqu'à présent, la commande ne s'exécuterait pas si cette option était activée. Selon le doublon intersite , un redémarrage résoudra tous les problèmes, mais bien sûr, les données dans la RAM à ce moment-là seraient perdues et non vidées sur le disque (le cas échéant).Il existe une méthode suggérée pour le doublon lié plus tôt,
busybox devmem
donc si vous êtes déterminé à jouer avec la RAM, il peut y avoir un moyen après tout.la source
CONFIG_STRICT_DEVMEM
, vous pouvez accéder aux régions de mémoire où un périphérique est mappé, ce qui est tout l'intérêt d'avoir/dev/mem
. Si vous écrivez des éléments aléatoires sur des périphériques, tout peut arriver. Vous obtenez «opération non autorisée» si vous essayez d'accéder à une adresse qui n'est pas mappée, et la commande démarre à l'adresse 0. L'adresse 0 correspond à quelque chose de mauvais dépend de l'architecture matérielle. Pour autant que je sache, il pourrait ne jamais correspondre à quoi que ce soit sur un PC, mais ce n'est pas sûr en général.head -c 1024 </dev/mem | od -tx1
), mais je ne sais pas si ceux-ci sont utilisés lorsque le processeur n'est pas en mode réel (mode 8088). Je ne pense pas qu'ils puissent être utilisés en mode 64 bits: après tout, les vecteurs d'interruption 8088 n'ont que 32 bits pour l'adresse. Et d'ailleurs, cela est accessible avecCONFIG_STRICT_DEVMEM
set, donc je suppose que Linux ne l'utilise pas.