GNU/Linux >> Znalost Linux >  >> Debian

Linuxové jmenné prostory

Pozadí

Počínaje jádrem 2.6.24 Linux podporuje 6 různých typů jmenných prostorů. Jmenné prostory jsou užitečné při vytváření procesů, které jsou více izolované od zbytku systému, aniž by bylo nutné používat plnou nízkoúrovňovou virtualizační technologii.

  • CLONE_NEWIPC:Jmenné prostory IPC:SystemV IPC a fronty zpráv POSIX lze izolovat.
  • CLONE_NEWPID:Jmenné prostory PID:PID jsou izolované, což znamená, že virtuální PID uvnitř jmenného prostoru může být v konfliktu s PID mimo jmenný prostor. PID uvnitř jmenného prostoru budou mapovány na jiné PID mimo jmenný prostor. První PID uvnitř jmenného prostoru bude '1', která mimo jmenný prostor je přiřazena init
  • CLONE_NEWNET:Síťové jmenné prostory:Sítě (/proc/net, IP, rozhraní a trasy) jsou izolované. Služby lze provozovat na stejných portech v rámci jmenných prostorů a lze vytvořit „duplicitní“ virtuální rozhraní.
  • CLONE_NEWNS:Připojit jmenné prostory. Máme schopnost izolovat přípojné body tak, jak se jeví procesům. Pomocí mount jmenných prostorů můžeme dosáhnout podobné funkce jako chroot(), avšak s lepším zabezpečením.
  • CLONE_NEWUTS:jmenné prostory UTS. Primárním účelem tohoto jmenného prostoru je izolovat název hostitele a název NIS.
  • CLONE_NEWUSER:Uživatelské jmenné prostory. Zde se ID uživatelů a skupin liší uvnitř a vně jmenných prostorů a lze je duplikovat.

Podívejme se nejprve na strukturu programu v jazyce C, který je nutný k demonstraci jmenných prostorů procesů. Následující bylo testováno na Debianu 6 a 7. Nejprve musíme alokovat stránku paměti v zásobníku a nastavit ukazatel na konec této stránky paměti. K alokaci paměti zásobníku používáme alloca spíše než malloc, který by alokoval paměť na haldě.

void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);

Dále použijeme clone k vytvoření podřízeného procesu, předáme umístění našeho podřízeného zásobníku 'mem' a také požadované příznaky pro specifikaci nového jmenného prostoru. Jako funkci, která se má provést v podřízeném prostoru, specifikujeme 'callee':

mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);

Po zavolání clone pak čekáme na dokončení podřízeného procesu, než ukončíme nadřazený. Pokud ne, bude tok spouštění rodiče pokračovat a okamžitě se ukončí, čímž se vyčistí i podřízené:

while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
{
	continue;
}

Nakonec se vrátíme do shellu s výstupním kódem potomka:

if (WIFEXITED(r))
{
	return WEXITSTATUS(r);
}
return EXIT_FAILURE;

Nyní se podívejme na funkci volaného:

static int callee()
{
	int ret;
	mount("proc", "/proc", "proc", 0, "");
	setgid(u);
	setgroups(0, NULL);
	setuid(u);
	ret = execl("/bin/bash", "/bin/bash", NULL);
	return ret;
}

Zde připojíme souborový systém /proc a poté nastavíme uid (ID uživatele) a gid (ID skupiny) na hodnotu 'u' před vytvořením shellu /bin/bash. LXC je virtualizační nástroj na úrovni operačního systému využívající cgroups a jmenné prostory pro izolaci zdrojů. Pojďme to dát dohromady, nastavíme 'u' na 65534, což je uživatel "nobody" a skupina "nogroup" v Debianu:

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <grp.h>
#include <alloca.h>
#include <errno.h>
#include <sched.h>
static int callee();
const int u = 65534;
int main(int argc, char *argv[])
{
	int r;
	pid_t mypid;
	void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);
	mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);
	while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
	{
		continue;
	}
	if (WIFEXITED(r))
	{
		return WEXITSTATUS(r);
	}
	return EXIT_FAILURE;
}
static int callee()
{
	int ret;
	mount("proc", "/proc", "proc", 0, "");
	setgid(u);
	setgroups(0, NULL);
	setuid(u);
	ret = execl("/bin/bash", "/bin/bash", NULL);
	return ret;
}

Spuštění kódu vytvoří následující:

[email protected]:~/pen/tmp# gcc -O -o ns.c -Wall -Werror -ansi -c89 ns.c
[email protected]:~/pen/tmp# ./ns
[email protected]:~/pen/tmp$ id
uid=65534(nobody) gid=65534(nogroup)
[email protected]:~/pen/tmp$ ps auxw
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
nobody       1  0.0  0.0   4620  1816 pts/1    S    21:21   0:00 /bin/bash
nobody       5  0.0  0.0   2784  1064 pts/1    R+   21:21   0:00 ps auxw
[email protected]:~/pen/tmp$ 

Všimněte si, že UID a GID jsou nastaveny na hodnotu none a nogroup. Konkrétně si všimněte, že úplný výstup ps zobrazuje pouze dva běžící procesy a že jejich PID jsou 1 a 5. Nyní přejděme k používání ip netns pro práci se síťovými jmennými prostory. Nejprve si ověřte, že aktuálně neexistují žádné jmenné prostory:

[email protected]:~# ip netns list
Object "netns" is unknown, try "ip help".

V tomto případě buď ip potřebuje upgrade, nebo kernel. Za předpokladu, že máte jádro novější než 2.6.24, je to s největší pravděpodobností ip. Po upgradu by seznam ip netns standardně neměl vracet nic. Pojďme přidat nový jmenný prostor nazvaný 'ns1':

[email protected]:~# ip netns add ns1
[email protected]:~# ip netns list
ns1

Nejprve si uveďme seznam aktuálních rozhraní:

[email protected]:~# ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff

Nyní vytvořte nové virtuální rozhraní a přidejte jej do našeho nového jmenného prostoru. Virtuální rozhraní jsou vytvářena ve dvojicích a jsou vzájemně propojena – představte si virtuální křížený kabel:

[email protected]:~# ip link add veth0 type veth peer name veth1
[email protected]:~# ip link list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
3: veth1:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether d2:e9:52:18:19:ab brd ff:ff:ff:ff:ff:ff
4: veth0:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether f2:f7:5e:e2:22:ac brd ff:ff:ff:ff:ff:ff
ifconfig -a nyní také zobrazí přidání obou veth0 a veth1.

Skvělé, nyní přiřadit naše nová rozhraní do jmenného prostoru. Všimněte si, že ip netns exec se používá k provádění příkazů v rámci jmenného prostoru:

[email protected]:~# ip link set veth1 netns ns1
[email protected]:~# ip netns exec ns1 ip link list
1: lo:  mtu 65536 qdisc noop state DOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth1:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether d2:e9:52:18:19:ab brd ff:ff:ff:ff:ff:ff
ifconfig -a nyní zobrazí pouze veth0, protože veth1 je ve jmenném prostoru ns1.

Pokud bychom chtěli odstranit veth0/veth1:

ip netns exec ns1 ip link del veth1

Nyní můžeme přiřadit IP adresu 192.168.5.5/24 veth0 na našem hostiteli:

ifconfig veth0 192.168.5.5/24

A přiřadit veth1 192.168.5.10/24 v rámci ns1:

ip netns exec ns1 ifconfig veth1 192.168.5.10/24 up

Chcete-li spustit seznam ip addr na našem hostiteli i v našem jmenném prostoru:

[email protected]:~# ip addr list
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.122/24 brd 192.168.3.255 scope global eth0
    inet6 fe80::20c:29ff:fe65:259e/64 scope link 
       valid_lft forever preferred_lft forever
6: veth0:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 86:b2:c7:bd:c9:11 brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.5/24 brd 192.168.5.255 scope global veth0
    inet6 fe80::84b2:c7ff:febd:c911/64 scope link 
       valid_lft forever preferred_lft forever
[email protected]:~# ip netns exec ns1 ip addr list
1: lo:  mtu 65536 qdisc noop state DOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 12:bd:b6:76:a6:eb brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.10/24 brd 192.168.5.255 scope global veth1
    inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link 
       valid_lft forever preferred_lft forever

Zobrazení směrovacích tabulek uvnitř a vně jmenného prostoru:

[email protected]:~# ip route list
default via 192.168.3.1 dev eth0  proto static 
192.168.3.0/24 dev eth0  proto kernel  scope link  src 192.168.3.122 
192.168.5.0/24 dev veth0  proto kernel  scope link  src 192.168.5.5 
[email protected]:~# ip netns exec ns1 ip route list
192.168.5.0/24 dev veth1  proto kernel  scope link  src 192.168.5.10 

A konečně, k propojení našich fyzických a virtuálních rozhraní budeme potřebovat most. Pojďme přemostit eth0 a veth0 na hostiteli a pak pomocí DHCP získat IP v rámci jmenného prostoru ns1:

[email protected]:~# brctl addbr br0
[email protected]:~# brctl addif br0 eth0
[email protected]:~# brctl addif br0 veth0
[email protected]:~# ifconfig eth0 0.0.0.0
[email protected]:~# ifconfig veth0 0.0.0.0
[email protected]:~# dhclient br0
[email protected]:~# ip addr list br0
7: br0:  mtu 1500 qdisc noqueue state UP 
    link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.122/24 brd 192.168.3.255 scope global br0
    inet6 fe80::20c:29ff:fe65:259e/64 scope link 
       valid_lft forever preferred_lft forever

br0 má přiděleno IP 192.168.3.122/24. Nyní k jmennému prostoru:

[email protected]:~# ip netns exec ns1 dhclient veth1
[email protected]:~# ip netns exec ns1 ip addr list
1: lo:  mtu 65536 qdisc noop state DOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 12:bd:b6:76:a6:eb brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.248/24 brd 192.168.3.255 scope global veth1
    inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link 
       valid_lft forever preferred_lft forever

Vynikající! veth1 bylo přiděleno 192.168.3.248/24

IO Digital Sec
Linux konzultant


Debian
  1. 7 nejpoužívanějších jmenných prostorů Linuxu

  2. Jak provést Chroot s jmennými prostory Linuxu?

  3. Linux – Jak vypsat jmenné prostory v Linuxu?

  1. Demystifikace jmenných prostorů a kontejnerů v Linuxu

  2. MX Linux vs. Ubuntu

  3. Zobrazení/manipulace jmenných prostorů připojení v Linuxu

  1. Linux – Kernel:Podpora jmenných prostorů?

  2. Linuxový příkaz mv

  3. Linux du command