Isso se resume ao que compõe um processo no Unix. Um processo pode vir a existir de duas maneiras. Por meio da função fork()
ou através de uma das funções exec()
em C.
fork()
fork()
basicamente faz apenas uma cópia do processo atual, mas atribui a ele um novo ID de processo (PID). É um filho do processo original. Você pode ver esse relacionamento na saída de ps
:
$ ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 5255 1964 1964 ? -1 Sl 500 0:39 gnome-terminal
5255 5259 1964 1964 ? -1 S 500 0:00 \_ gnome-pty-helper
5255 18422 18422 18422 pts/1 18422 Ss+ 500 0:01 \_ bash
5255 30473 30473 30473 pts/4 30473 Ss+ 500 0:00 \_ bash
30473 782 782 30473 pts/4 30473 Sl 500 1:14 | \_ evince s.pdf
Aqui você pode ver que gnome-terminal
é o processo pai (PID = 5255) e que bash
é filho (PID = 18422, PPID = 5255).
OBSERVAÇÃO: PPID = ID do processo pai.
Quando um processo se bifurca em seu pai, ele "herda" certas coisas, como cópias de todos os descritores de arquivos que o pai possui atualmente para arquivos abertos e os IDs de usuário e grupo do pai.
OBSERVAÇÃO: Os últimos 2 são o que identifica quais permissões de arquivo e grupo este processo terá ao acessar o sistema de arquivos.
Portanto, se um processo herdar seu ID de usuário e grupo de seu pai, por que tudo não é de propriedade de root ou de um único usuário? É aqui que entra o exec()
.
exec()
parte # 1
A família de funções exec()
, especificamente execve()
, "substitui" uma imagem de processo atual por uma nova imagem de processo. A terminologia "process image" é na verdade apenas um arquivo, ou seja, um executável no disco. Então é assim que um script bash pode executar um programa como /usr/bin/time
.
Então, e o ID do usuário e o ID do grupo? Bem, para entender que vamos primeiro discutir o conceito de "Persona".
Persona
A qualquer momento, cada processo tem um ID de usuário efetivo, um ID de grupo efetivo e um conjunto de IDs de grupo suplementares. Esses IDs determinam os privilégios do processo. Eles são chamados coletivamente de persona do processo , porque determinam "quem é" para fins de controle de acesso.
exec()
parte # 2
Então, além de poder trocar a "imagem do processo", exec()
também pode alterar o usuário & IDs de grupo dos originais "reais" para os "efetivos".
Um exemplo
Para esta demonstração, mostrarei o que acontece quando iniciamos em um shell como nosso UID / GID padrão e, em seguida, geramos um shell filho usando um dos meus GIDs suplementares, tornando-o o GID efetivo do shell filho.
Para realizar isso, usarei o comando unix newgrp
. newgrp
permite que você crie um novo shell passando-o ao grupo suplementar que gostaria de tornar meu GID efetivo.
Para começar:
$ id -a
uid=500(saml) gid=501(saml) groups=501(saml),502(vboxusers),503(jupiter)
Podemos ver que este shell está atualmente configurado com meu UID / GID padrão de saml
& %código%. Tocar em alguns arquivos mostra que esse também é o caso:
$ touch afile1
$ touch afile2
$ ls -l
total 0
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile1
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile2
Agora, transformamos nosso grupo suplementar em saml
no GID efetivo:
$ newgrp jupiter
$ id -a
uid=500(saml) gid=503(jupiter) groups=501(saml),502(vboxusers),503(jupiter)
Agora, se tocarmos em alguns arquivos:
$ touch afile3
$ touch afile4
$ ls -l
total 0
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile1
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile2
-rw-r--r-- 1 saml jupiter 0 May 21 23:49 afile3
-rw-r--r-- 1 saml jupiter 0 May 21 23:49 afile4
Vemos que o GID efetivo do shell é jupiter
, portanto, qualquer interação com o disco resultará na criação de arquivos com jupiter
em vez do meu grupo padrão normal de jupiter
.
Referências
- página do manual fork ()
- página do manual exec ()
- página de manual execve ()
- página de manual de credenciais
- página man do newgrp
- A biblioteca GNU C
- A biblioteca GNU C - 26.4 Criando um processo
- A Biblioteca GNU C - 26.5 Executando um arquivo
- GID, atual, primário, complementar, efetivo e IDs de grupo reais?