GNU/Linux >> Tutoriales Linux >  >> Linux

Linux:¿cómo dejar de compartir la red para el proceso actual?

Es posible ejecutar un nuevo comando sin acceso a la red como no root usando unshare -r -n , por ejemplo:

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

Un comando que requiere acceso a la red fallará como era de esperar.

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

Me pregunto si es posible eliminar el acceso a la red para el proceso actual, potencialmente escribiendo en un archivo mágico en /sys o algo similar.

Me gustaría poder hacer algo como

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

Un extracto de strace -ing unshare -r -n ls muestra el unshare llamada al sistema

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

Lo que me sugiere que dejar de compartir el acceso a la red del proceso actual es, de hecho, la única forma de lograr dejar de compartir (es decir, no se puede pasar como un argumento para spawn o algún equivalente de los mismos). También sugiere que dejar de compartir desde un script de shell no funcionaría a menos que el shell se hubiera extendido específicamente para exponer un contenedor alrededor de unshare .

Respuesta aceptada:

Esto se puede hacer, más o menos, con el gdb depurador, y si el proceso en ejecución se puede adjuntar (no se pueden adjuntar programas que alteran su estado de volcado, o son setgid, etc., a menos que sean raíz).

Algunos archivos opcionales pueden ayudar a usar gdb como símbolos de depuración para libc6, y algunos archivos de inclusión relacionados con Linux para obtener los valores reales de algunos símbolos más tarde (por ejemplo, en Debian:(posiblemente) libc6-dbg , libc6-dev y linux-libc-dev paquetes), pero en realidad una vez que se hace la "receta", probablemente ya no sean necesarios.

Primero qué más que unshare() unshare -r ¿está haciendo? Sin esto, el nuevo usuario se queda en nobody y ni siquiera puede escribir como su usuario inicial:

$ 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

Eso se usará más adelante.

$ 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
$

En otro 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)

Ahora llamemos a la primera función:

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

Ok, puede haber un método para que gdb lo sepa, pero no soy un gurú:

(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

En el proceso alterado, se puede verificar el eth0 interfaz desapareció:

$ 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

No hay vuelta atrás:el nuevo espacio de nombres de usuario no puede volver a su espacio de nombres inicial. Si el proceso se ejecuta con suficientes privilegios (p. ej., raíz sin capacidades perdidas ni SELinux), entonces sería posible (usando solo unshare(CLONE_NEWNET) / setns(savedopenedfd) ).

Relacionado:¿Cómo configurar los valores predeterminados de escritorio para nuevos usuarios?

Por supuesto, es posible crear una secuencia de comandos en un archivo y modificar cualquier proceso en ejecución permitido, o hacer que el shell se modifique a sí mismo a partir de un subproceso gdb. Contenido de removenetwork.gdb , válido aquí solo para alterar un proceso con pid:gid ==1000:1000 :

ACTUALIZACIÓN:se agregó el tipo de retorno (aproximado) para las llamadas al sistema a continuación, esto debería evitar que algunas versiones de gdb se quejen en entornos que no son de desarrollo:

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

Ejemplo:

$ 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

ACTUALIZAR :si no se necesita root en absoluto, como aparece en esta Pregunta, entonces no hay necesidad de mapear a root en absoluto. Simplemente reemplace las apariciones de write($XX, "0 1000 1", 8) con write($XX, "1000 1000 1", 11) (para el uid:gid ==1000:1000 caso). Los grupos complementarios aún se pierden inevitablemente, pero el uid/gid no cambia (se asigna a sí mismo).


Linux
  1. 10 comandos de Linux para diagnóstico de red

  2. Cómo limitar el uso de la CPU de un proceso en Linux

  3. Linux – ¿Bloquear el acceso a la red de un proceso?

  4. Cómo instalar y configurar Monit en Linux para el monitoreo de procesos

  5. Cómo verificar el tamaño del montón para un proceso en Linux

Cómo matar procesos Zombie en Linux

Cómo compartir la impresora en la red en Linux

Cómo encontrar interfaces de red disponibles en Linux

Cómo MATAR un proceso en Linux

Cómo agregar una ruta en Linux

Cómo configurar una red externa para contenedores en contenedores de Linux (LXC)