GNU/Linux >> Znalost Linux >  >> Linux

Linux – Jak zrušit sdílení sítě pro aktuální proces?

Je možné spustit nový příkaz bez přístupu k síti jako uživatel bez root pomocí unshare -r -n , například:

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

Příkaz, který vyžaduje přístup k síti, předvídatelně selže.

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

Zajímalo by mě, zda je možné odebrat přístup k síti pro aktuální proces, případně zápisem do magického souboru v /sys nebo něco podobného.

Chtěl bych umět něco jako

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

Výňatek z strace -ing unshare -r -n ls zobrazuje unshare systémové volání

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

Což mi naznačuje, že zrušení sdílení přístupu k síti z aktuálního procesu je ve skutečnosti jediný způsob, jak dosáhnout zrušení sdílení (tj. nemůže být předán jako argument pro spawn nebo nějaký jeho ekvivalent). Také to naznačuje, že zrušení sdílení ze skriptu shellu by nefungovalo, pokud by shell nebyl speciálně rozšířen tak, aby odkryl obal kolem unshare .

Přijatá odpověď:

To lze provést pomocí gdb debugger a zda lze k běžícímu procesu připojit (nelze se připojit k programům, které mění svůj stav výpisu nebo mají setgid atd., pokud nejde o root).

Některé volitelné soubory mohou pomoci použít gdb jako ladicí symboly pro libc6 a několik začleněných souborů souvisejících s Linuxem pro pozdější získání skutečných hodnot několika symbolů (např. na Debianu:(možná) libc6-dbg , libc6-dev a linux-libc-dev balíčky), ale jakmile je „recept“ vyroben, pravděpodobně již nejsou potřeba.

Nejprve co víc než unshare() unshare -r dělá? Bez toho nový uživatel zůstane u nobody a nemůže ani psát jako jeho první uživatel:

$ 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

To bude použito později.

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

Na jiném terminálu:

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

Nyní zavoláme první funkci:

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

Dobře, možná existuje způsob, jak to gdb poznat, ale nejsem guru:

(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

U změněného procesu lze ověřit eth0 rozhraní zmizelo:

$ 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

Není cesty zpět:nový uživatelský jmenný prostor se nemůže změnit zpět na svůj původní jmenný prostor. Pokud proces běží s dostatečnými oprávněními (např. root bez ztracených schopností nebo SELinux), pak by to bylo možné (pouze pomocí unshare(CLONE_NEWNET) / setns(savedopenedfd) ).

Související:Jak nastavit výchozí nastavení plochy pro nové uživatele?

Samozřejmě je možné jej naskriptovat do souboru a změnit jakýkoli povolený běžící proces nebo nechat shell sám změnit z podprocesu gdb. Obsah removenetwork.gdb , zde platí pouze pro změnu procesu pomocí pid:gid ==1000:1000 :

AKTUALIZACE:přidán (přibližný) návratový typ pro systémová volání níže, to by mělo zabránit tomu, aby si některé verze gdb stěžovaly v prostředích bez vývojáře:

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

Příklad:

$ 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

AKTUALIZACE :pokud root vůbec není potřeba, jak se zdá u této otázky, pak není vůbec potřeba mapovat na root. Jednoduše nahraďte výskyty write($XX, "0 1000 1", 8) pomocí write($XX, "1000 1000 1", 11) (pro uid:gid ==1000:1000 případ). Doplňkové skupiny jsou stále nevyhnutelně ztraceny, ale uid/gid se nemění (je namapováno na sebe).


Linux
  1. Jak nastavit Linux Etherchannel Bonding pro síťové rozhraní HA

  2. Jak zakázat vytváření soketu pro proces Linux pro sandboxing?

  3. Jak nastavit ID procesu v Linuxu pro konkrétní program

  1. Jak zabít proces zombie na Linuxu

  2. 8 Linuxových příkazů pro efektivní řízení procesů

  3. 10 Linuxových příkazů pro diagnostiku sítě

  1. Jak omezit využití CPU procesu v Linuxu

  2. Jak nainstalovat vtop na Linux

  3. Linux – Blokovat síťový přístup procesu?