IDs de Processo
Processos no Linux estão associados a vários IDs que determinam suas identidades e privilégios:
- ID de Usuário Real (UID Real) / ID de Grupo Real: Representa o usuário e grupo que iniciaram o processo.
- ID de Usuário Efetivo (UID Efetivo) / ID de Grupo Efetivo: Usado pelo sistema operacional para verificar permissões de acesso a arquivos. Geralmente coincide com os IDs reais, mas pode mudar para conceder privilégios temporários.
- ID de Usuário Salvo (Saved UID) / ID de Grupo Salvo (Saved GID): Cópias dos UIDs efetivos, mantidos após a execução de um programa via chamadas
exec. A disponibilidade desses IDs salvos depende da implementação do sistema (verificável com\_POSIX\_SAVED\_IDS).
A diferença entre UIDs reais e efetivos é crucial para operações privilegiadas. Por exemplo, o comando passwd permite que usuários comuns modifiquem suas senhas, embora o arquivo /etc/passwd seja protegido e só possa ser escrito pelo root. Isso é possível porque o programa passwd é executado com um UID efetivo de root, permitindo a modificação do arquivo.
Bit de Set-User-ID (SUID) em Arquivos
O bit SUID é um atributo de arquivo que, quando definido em um arquivo executável, faz com que o UID efetivo do processo que executa o arquivo seja definido para o UID do proprietário do arquivo. Isso é visível na listagem de arquivos como 's' em vez de 'x' para o proprietário.
$ ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 30768 Feb 22 2012 /usr/bin/passwd
Exemplo demonstrando a mudança do UID efetivo:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
printf("UID Real = %d\n", getuid());
printf("UID Efetivo = %d\n", geteuid());
return 0;
}
Execução sem SUID (UID real e efetivo iguais):
user@host$ ./my_program
UID Real = 1000
UID Efetivo = 1000
Após configurar SUID para o proprietário root e executar como usuário comum:
user@host$ su
Password:
root# chown root my_program
root# chmod u+s my_program
root# ll my_program
-rwsr-xr-x 1 root user 9809 2016-12-21 22:20 my_program
root# exit
user@host$ ./my_program
UID Real = 1000
UID Efetivo = 0
Propriedade de Novos Arquivos e Diretórios
Ao criar um novo arquivo:
- O UID do novo arquivo é definido como o UID efetivo do processo criador.
- O GID do novo arquivo pode ser:
- O GID efetivo do processo criador.
- O GID do diretório onde o arquivo está sendo criado.
Novos diretórios seguem as mesmas regras de propriedade.
Funções chmod e fchmod
Essas funções permitem modificar as permissões de acesso de arquivos existentes.
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode); // filedes é o descritor de arquivo
O retorno é 0 em caso de sucesso e -1 em caso de erro.
Para alterar as permissões de um arquivo, o UID efetivo do procseso deve corresponder ao proprietário do arquivo, ou o processo deve ter privilégios de root.
O parâmetro mode é construído usando operadores bitwise OR com as seguintes constantes (definidas em <sys>):
S_ISUID: Bit Set-User-IDS_ISGID: Bit Set-Group-IDS_ISVTX: Sticky BitS_IRWXU: Permissões de leitura, escrita e execução para o proprietárioS_IRUSR: Permissão de leitura para o proprietárioS_IWUSR: Permissão de escrita para o proprietárioS_IXUSR: Permissão de execução para o proprietárioS_IRWXG: Permissões de leitura, escrita e execução para o grupoS_IRGRP: Permissão de leitura para o grupoS_IWGRP: Permissão de escrita para o grupoS_IXGRP: Permissão de execução para o grupoS_IRWXO: Permissões de leitura, escrita e execução para outrosS_IROTH: Permissão de leitura para outrosS_IWOTH: Permissão de escrita para outrosS_IXOTH: Permissão de execução para outros
Exemplo de uso:
#include <stdio.h>
#include <sys/stat.h>
int main(void) {
struct stat statbuf;
// Verifica o estado do arquivo "foo"
if (stat("foo", &statbuf) < 0) {
fprintf(stderr, "Erro ao obter status do arquivo foo\n");
return 1;
}
// Modifica as permissões de "foo", adicionando S_ISGID e mantendo outras permissões
// (statbuf.st_mode & ~S_IXGRP) remove a permissão de execução do grupo
if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) {
fprintf(stderr, "Erro ao alterar permissões de foo\n");
return 1;
}
// Define permissões absolutas para "bar" como "rw-r--r--"
if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
fprintf(stderr, "Erro ao alterar permissões de bar\n");
return 1;
}
return 0;
}
Sticky Bit
O Sticky Bit (S_ISVTX) em versões antigas do UNIX era usado em arquivos executáveis para manter uma cópia do texto do programa na área de troca (swap area) após a primeira execução, acelerando execuções subsequentes. Sistemas modernos com memória virtual e sistemas de arquivos rápidos não necessitam mais dessa funcionalidade para executáveis.
Em diretórios, o Sticky Bit tem uma função importante: quando definido, apenas o proprietário do arquivo, o proprietário do diretório ou o superusuário podem excluir ou renomear arquivos dentro desse diretório, mesmo que outros usuários tenham permissão de escrita no diretório.
Diretórios como /tmp e /var/spool/uucppublic frequentemente utilizam o Sticky Bit para permitir que qualquer usuário crie arquivos, mas impeça que usuários excluam ou renomeiem arquivos de outros.
Funções chown, fchown e lchown
Essas funções alteram o proprietário (UID) e o grupo (GID) de um arquivo.
#include <sys/types.h>
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group); // Altera o proprietário do link simbólico, não do alvo
O retorno é 0 em caso de sucesso e -1 em caso de erro.
A capacidade de um usuário comum alterar o proprietário de um arquivo é restrita (definida por \_POSIX\_CHOWN\_RESTRICTED). Se essa restrição estiver ativa:
- Apenas o superusuário pode alterar o UID de um arquivo.
- Um usuário não-root pode alterar o GID de um arquivo que possui, mas apenas para um dos seus GIDs efetivos ou de grupo adicionais.
Se essas funções forem chamadas por um processo não-root e retornarem com sucesso, os bits SUID e SGID do arquivo serão automaticamente desativados.
Comprimento do Arquivo
O membro st\_size da estrutura stat contém o comprimento do arquivo em bytes. Este campo é significativo para arquivos regulares, diretórios e links simbólicos.
- Para diretórios,
st\_sizeé um múltiplo de um valor específico (como 16 ou 512). - Para links simbólicos,
st\_sizeé o comprimento do nome do arquivo alvo.
Truncamento de Arquivo
As funções truncate e ftruncate podem ser usadas para encurtar um arquivo para um tamanho especificado (length).
#include <sys/types.h>
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
Se o comprimento original do arquivo for maior que length, os dados excedentes são descartados. Se o comprimento original for menor, o comportamento depende do sistema; alguns sistemas expandem o arquivo e preenchem o espaço adicional com zeros.
Sistemas de Arquivos e Inodes
Sistemas de arquivos tradicionais (como o System V) organizam o armazenamento em discos usando partições, cada uma contendo um sistema de arquivos.
- Inode: Uma estrutura de dados de tamanho fixo que contém metadados sobre um arquivo (tipo, permissões, tamanho, ponteiros para blocos de dados).
- Contagem de Links (
st\_nlink): Cada inode possui uma contagem de links. Um link (hard link) é uma entrada de diretório que aponta para um inode. Um arquivo só é removido (e seus blocos de dados liberados) quando sua contagem de links chega a zero. O número máximo de links é definido porLINK\_MAX. - Link Simbólico (Symbolic Link): Um tipo especial de arquivo cujo conteúdo é o nome de outro arquivo.
- Entrada de Diretório: Contém o nome do arquivo e o número do inode correspondente. Entradas de diretório só podem apontar para inodes dentro do mesmo sistema de arquivos.
- Renomear Arquivo: Renomear um arquivo dentro do mesmo sistema de arquivos simplesmente cria uma nova entrada de diretório apontanod para o mesmo inode existente, sem mover os dados do arquivo.
Contagem de Links em Diretórios
A contgaem de links em diretórios é especial:
- Um diretório vazio (folha) tem uma contagem de links de 2: uma para a entrada que o nomeia e uma para a entrada
.dentro dele. - Um diretório que contém subdiretórios tem uma contagem de links de pelo menos 3: a entrada que o nomeia, a entrada
.dentro dele e a entrada..em cada subdiretório.