GNU/Linux >> Tutoriels Linux >  >> Linux

Linux - Comment annuler le partage du réseau pour le processus actuel ?

Il est possible d'exécuter une nouvelle commande sans accès au réseau en tant que non root en utilisant unshare -r -n , par exemple :

$ unshare -r -n ls
a.txt  b.txt

Une commande qui nécessite un accès au réseau échouera de manière prévisible.

$ unshare -r -n curl unix.stackexchange.com
curl: (6) Could not resolve host: unix.stackexchange.com

Je me demande s'il est possible de supprimer l'accès au réseau pour le processus en cours, potentiellement en écrivant dans un fichier magique dans /sys ou quelque chose de similaire.

J'aimerais pouvoir faire quelque chose comme

$ /bin/sh -c 'echo 1 > /sys/unsharethis; curl unix.stackexchange.com'

Un extrait de strace -ing unshare -r -n ls affiche le unshare appel système

open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4759040, ...}) = 0
mmap(NULL, 4759040, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7ec6968000
close(3)                                = 0
unshare(CLONE_NEWUSER|CLONE_NEWNET)     = 0
open("/proc/self/setgroups", O_WRONLY)  = 3
write(3, "deny", 4)                     = 4

Ce qui me suggère que le partage de l'accès au réseau du processus actuel est en fait le seul moyen de réaliser le partage (c'est-à-dire qu'il ne peut pas être passé en argument à spawn ou un équivalent). Cela suggère également que le partage d'un script shell ne fonctionnerait pas à moins que le shell n'ait été spécifiquement étendu pour exposer un wrapper autour de unshare .

Réponse acceptée :

Cela peut être fait, en quelque sorte, avec le gdb débogueur, et si le processus en cours d'exécution peut être attaché à (les programmes qui modifient leur état de vidage, ou sont setgid, etc. ne peuvent pas être attachés, sauf à partir de la racine).

Certains fichiers optionnels peuvent aider à utiliser gdb comme les symboles de débogage pour libc6, et quelques fichiers d'inclusion liés à Linux pour obtenir les valeurs réelles de quelques symboles plus tard (par exemple sur Debian :(éventuellement) libc6-dbg , libc6-dev et linux-libc-dev paquets), mais en fait une fois la "recette" faite, ils ne sont probablement plus nécessaires.

D'abord quoi de plus que unshare() unshare -r fait? Sans cela, le nouvel utilisateur reste chez nobody et ne peut même pas écrire en tant qu'utilisateur initial :

$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ strace unshare -r -n /bin/sleep 1 2>&1 |sed -n '/^unshare/,/^execve/p'
unshare(CLONE_NEWNET|CLONE_NEWUSER)     = 0
open("/proc/self/setgroups", O_WRONLY)  = 3
write(3, "deny", 4)                     = 4
close(3)                                = 0
open("/proc/self/uid_map", O_WRONLY)    = 3
write(3, "0 1000 1", 8)                 = 8
close(3)                                = 0
open("/proc/self/gid_map", O_WRONLY)    = 3
write(3, "0 1000 1", 8)                 = 8
close(3)                                = 0
execve("/bin/sleep", ["/bin/sleep", "1"], [/* 18 vars */]) = 0

Cela sera utilisé plus tard.

$ ip -4 -br a
lo               UNKNOWN        127.0.0.1/8 
[email protected]        UP             10.0.3.66/24 
$ ping -c1 10.0.3.1
PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.
64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.167 ms

--- 10.0.3.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

rtt min/avg/max/mdev = 0.167/0.167/0.167/0.000 ms
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ echo $$
338
$

Sur un autre terminal :

$ gdb --pid=338
Reading symbols from /bin/bash...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libtinfo.so.5...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libdl.so.2...Reading symbols from /usr/lib/debug/.build-id/b8/95f0831f623c5f23603401d4069f9f94c24761.debug...done.
done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug/.build-id/aa/889e26a70f98fa8d230d088f7cc5bf43573163.debug...done.
done.

[…]

(gdb)

Appelons maintenant la première fonction :

(gdb) call unshare(CLONE_NEWNET|CLONE_NEWUSER)
No symbol "CLONE_NEWNET" in current context.

Ok, il y a peut-être une méthode pour que gdb le sache, mais je ne suis pas un gourou :

(gdb) !
$ grep CLONE_NEW /usr/include/linux/sched.h # man 2 unshare
#define CLONE_NEWNS 0x00020000  /* New mount namespace group */
#define CLONE_NEWCGROUP     0x02000000  /* New cgroup namespace */
#define CLONE_NEWUTS        0x04000000  /* New utsname namespace */
#define CLONE_NEWIPC        0x08000000  /* New ipc namespace */
#define CLONE_NEWUSER       0x10000000  /* New user namespace */
#define CLONE_NEWPID        0x20000000  /* New pid namespace */
#define CLONE_NEWNET        0x40000000  /* New network namespace */
$ find /usr/include/ -name fcntl.h |xargs grep O_WRONLY # man 2 open
/usr/include/asm-generic/fcntl.h:#define O_WRONLY   00000001
$ exit
exit
(gdb) call unshare(0x50000000)
$1 = 0
(gdb) call open("/proc/self/setgroups", 1)
$2 = 3
(gdb) call write($2,"deny",4)
$3 = 4
(gdb) call close($2)
$4 = 0
(gdb) call open("/proc/self/uid_map", 1)
$5 = 3
(gdb) call write($5, "0 1000 1", 8)
$6 = 8
(gdb) call close($5)
$7 = 0
(gdb) call open("/proc/self/gid_map", 1)
$8 = 3
(gdb) call write($8, "0 1000 1", 8)
$9 = 8
(gdb) call close($8)
$10 = 0
(gdb) quit
A debugging session is active.

    Inferior 1 [process 338] will be detached.

Quit anyway? (y or n) y
Detaching from program: /bin/bash, process 338

Sur le processus modifié, on peut vérifier le eth0 l'interface a disparu :

$ ip -br a
lo               DOWN           127.0.0.1/8 
$ echo $$
338
$ id
uid=0(root) gid=0(root) groupes=0(root)
$ touch /
touch: setting times of '/': Permission denied
$ touch ~/test1
$ ls ~/test1
/home/user/test1
$ ping 10.0.3.1
connect: Network is unreachable

Il n'y a pas de retour en arrière :le nouvel espace de noms d'utilisateur ne peut pas revenir à son espace de noms initial. Si le processus s'exécute avec suffisamment de privilèges (par exemple root sans capacités perdues ni SELinux), cela serait alors possible (en utilisant uniquement unshare(CLONE_NEWNET) / setns(savedopenedfd) ).

En relation :Comment définir les paramètres par défaut du bureau pour les nouveaux utilisateurs ?

Bien sûr, il est possible de le scripter dans un fichier et de modifier tout processus en cours d'exécution autorisé, ou de faire en sorte que le shell se modifie lui-même à partir d'un sous-processus gdb. Contenu de removenetwork.gdb , valide ici uniquement pour modifier un processus avec pid:gid ==1000:1000 :

MISE À JOUR :ajout du type de retour (approximatif) pour les appels système ci-dessous, cela devrait éviter à certaines versions de gdb de se plaindre dans des environnements non-dev :

call (int)unshare(0x50000000)
call (int)open("/proc/self/setgroups", 1)
call (long)write($2,"deny",4)
call (int)close($2)
call (int)open("/proc/self/uid_map", 1)
call (long)write($5, "0 1000 1", 8)
call (int)close($5)
call (int)open("/proc/self/gid_map", 1)
call (long)write($8, "0 1000 1", 8)
call (int)close($8)
quit

Exemple :

$ sh -c 'id; gdb --pid=$$ < removenetwork.gdb >/dev/null 2>&1; id; curl unix.stackexchange.com'
uid=1000(user) gid=1000(user) groups=1000(user)
uid=0(root) gid=0(root) groups=0(root)
curl: (6) Could not resolve host: unix.stackexchange.com

MISE À JOUR :si la racine n'est pas du tout nécessaire, comme il apparaît pour cette question, il n'est pas du tout nécessaire de mapper à la racine. Remplacez simplement les occurrences de write($XX, "0 1000 1", 8) avec write($XX, "1000 1000 1", 11) (pour le uid:gid ==1000:1000 Cas). Les groupes supplémentaires sont toujours inévitablement perdus, mais l'uid/gid ne change pas (est mappé sur lui-même).


Linux
  1. Comment tuer un processus zombie sous Linux

  2. 8 commandes Linux pour une gestion efficace des processus

  3. 10 commandes Linux pour les diagnostics réseau

  4. Comment vérifier la taille du tas pour un processus sous Linux

  5. Comment définir l'ID de processus sous Linux pour un programme spécifique

Comment tuer les processus Zombie sous Linux

Comment partager une imprimante sur le réseau sous Linux

Comment trouver les interfaces réseau disponibles sous Linux

Comment tuer un processus sous Linux

Comment ajouter une route sous Linux

Comment définir un réseau externe pour les conteneurs dans les conteneurs Linux (LXC)