Divagação sobre Permissões, C e Linux

Introdução

Nesse texto irei comentar sobre permissões, inodes, umask e assuntos relacionados ao ambiente unix (especialmente linux). Irei abordar assuntos já bastante explicados na internet só que tentarei abordá-los maneira diferente. Darei alguns exemplos também na linguagem C.

As Permissões

As permissões dos sistemas unix e derivados são a fonte primária para proteção de seus arquivos. É por esse motivo que elas devem ganhar atenção especial para quem está administrando um sistema ou para quem quer simplesmente proteger a sua máquina de acessos indevidos.

As permissões tem efeitos diferentes sobre arquivos e diretórios. Claro que um diretório é um arquivo, mas aqui os dois vão ter papeis diferentes. Considere como arquivo tudo aquilo que não seja um diretório.

Como você já deve saber, as permissões de arquivos se aplicam a 3 classes. São elas:

+-------+
| dono  |
+-------+
| grupo |
+-------+
|outros |
+-------+

As permissões para dono se aplicam para quem é o dono do arquivo (quem criou o arquivo ou recebeu a posse via chown pelo root). As permissões de grupo se referem a um grupo de usuários. Esses usuários só podem entrar em grupos que o root escolher. E por fim, as permissões outros se aplicam a todos os usuários que não são dono e não estão no mesmo grupo do arquivo.

Vendo Permissões de um arquivo

Bem, o foco desse post não é explicar como ver ou alterar permissões de arquivos, mas sim como elas se relacionam umas com as outras. Mas para o post ficar completo, vou ter que falar algumas coisinhas sobre isso.

Para ver as permissões de um arquivo, utilize o comando ls. Você só terá acesso as permissões de um arquivo se o diretório em que ele pertence tem ‘x’ para você (veja mais abaixo).

$ ls -l /etc/passwd
-rw-r--r-- 1 root root 1052 2011-02-18 13:11 /etc/passwd

O primeiro bit é o tipo do arquivo. Aqui temos um ‘-‘ indicando que o passwd é um arquivo regular. O restante representa as permissões do dono, grupo, outros. A cada três bits (ou três letras, pois as letras representam os bits) se tem a permissão de cada classe. Veja:

- rw- r-- r-- 1 root root 1052 2011-02-18 13:11 /etc/passwd
| |    |  |
| |    |  v
| |    |  outros (r--)
| |    v
| |    grupo (r--)
| v
| dono (rw-)
v
tipo do arquivo.

Formato octal para as permissões

As permissões também podem ser manipuladas pelo formato octal. A base 8 se torna útil aqui porque cada classe contém exatamente 3 bits de permissões, e com 3 bits você consegue listar todos os algarismos da base 8 (que são 0, 1, 2, 3, 4, 5, 6, 7).

Um esquecimento comum é não saber qual número determinada permissão representa. Meu mnemônico para lembrar disso é listar as permissões assim: rwx. Agora para escolher uma permissão, basta colocar ‘1’ na permissão desejada e ‘0’ nas restantes.

O ‘r’ tem valor 4 porque:
rwx
100 (que é 4 em octal)

O ‘w’ tem valor 2 porque:
rwx
010 (que é 2 em octal)

O ‘x’ tem valor 1 porque:
rwx
001 (que é 1 em octal)

Essa dica também funciona para permissões que habilitam mais de uma permissão básica.

+-----------+----+----+----+-------+
|Permissão  | r  | w  | x  | Octal |
+-----------+----+----+----+-------+
|   r--     | 1  | 0  | 0  |   4   |
+-----------+----+----+----+-------+
|   -w-     | 0  | 1  | 0  |   2   |
+-----------+----+----+----+-------+
|   --x     | 0  | 0  | 1  |   1   |
+-----------+----+----+----+-------+
|   rw-     | 1  | 1  | 0  |   6   |
+-----------+----+----+----+-------+
|   r-x     | 1  | 0  | 1  |   5   |
+-----------+----+----+----+-------+
|   -wx     | 0  | 1  | 1  |   3   |
+-----------+----+----+----+-------+

Então a partir de agora, não se preocupe em decorar a tabelinha de permissões (essa tabela de cima foi só para esquematizar a dica), basta lembrar da sequência rwx e ir ativando os bits, e no final trate tudo como binário e transforme para octal.

Mudando as permissões

Esse tipo de tarefa é feita pelo comando chmod. Ele aceita as permissões de entrada no formato rwx ou no formato octal. Sempre que possível utilize o formato rwx por ser mais intuitivo.

No formato rwx, as classes são identificadas pelas letras:

+-------+--------+
|Letra  | Classe |
+-------+--------+
|  u    |  dono  |
+-------+--------+
|  g    |  grupo |
+-------+--------+
|  o    | outros |
+-------+--------+

Os símbolos abaixo permitem especificar as permissões:

+---------+--------------------------------+
|Símbolo  |             Função             |
+---------+--------------------------------+
|   +     | Permite acrescentar permissões |
+---------+--------------------------------+
|   =     |   Permite igualar permissões   |
+---------+--------------------------------+
|   -     |   Permite retirar permissões   |
+---------+--------------------------------+

Alguns exemplos:

$ chmod u=rwx file # Seta as permissões do dono para rwx
$ chmod u=g file   # Seta as permissões do dono igual a do grupo.
$ chmod o-w file   # Retira a permissão de 'w' de outros.
$ chmod ugo= file  # Seta a permissão nula para todas as classes.
$ chmod +r file    # Acrescenta permissão de leitura para todas as classes.

Já no formato octal, as classes são identificadas por cada dígito octal.

$ chmod 654 file
Dono:   6 (110 == rw-)
Grupo:  5 (101 == r-x)
Outros: 4 (100 == r--)
$ chmod 4 file
Dono:   0 (---)
Grupo:  0 (---)
Outros: 4 (100 == r--)

Permissões para Arquivos

Como as permissões se aplicam diferentemente para arquivos e diretórios, nessa parte vou mostrar como elas se relacionam com arquivos. Vamos lá:

r – Permite ler o arquivo

Ler o arquivo significa que você pode abrí-lo com open() e em seguida ler seu conteúdo com read(). Se você não tiver ‘r’ em um arquivo, uma chamada a função do sistema open() irá retornar erro, se você abrir o arquivo para leitura.

w – Permite alterar o conteúdo do arquivo

Entenda como alterar: modificar, truncar, acrescentar, etc. Alguém pode pensar que ter ‘w’ em um arquivo significa também que se possa deletá-lo já que você pode fazer o que quiser com o conteúdo dele. Isso não é verdade. Mais para frente aprenderemos, que para se deletar um arquivo, é preciso acesso ao inode dele para diminuir o número de hard links, e esse acesso é feito somente através do diretório em que o arquivo está.

x – Permite executar um arquivo como um programa.

Essa permissão diz para o kernel que o arquivo deve ser executado como um programa. Cada executável contém os 2 primeiros bits iniciais (chamados de bits mágicos) que o identifica. Os bits mágicos de scripts começam com #!. Se os bits iniciais são desconhecidos, então o arquivo será executado como um shell script (o shell usado é o que está sendo utilizado):

$ echo 'ls' > listar
$ chmod +x listar
$ ./listar
<saída do ls>

Ainda sobre as linguagens de script, é importante lembrar que esses arquivos só são executados se você tiver ‘x’ e ‘r’ ao mesmo tempo. Não é possível executar um programa script sem ter permissão de leitura.

$ chmod -r listar
$ ./listar
zsh: permission denied: ./listar

E se por ventura existe um script ou qualquer outro arquivo executável em que você não tem ‘x’ mas tem ‘r’, você pode copiar o conteúdo desse arquivo para seu home e torná-lo executável.

Inodes

Um inode é o conjunto de informações de cada arquivo. Todo arquivo no sistema de arquivo possui um inode onde são guardadas as informações de dono, grupo, localização no disco, etc.

Um inode não tem nome (o nome de um arquivo por exemplo é armazenado pelo diretório) mas eles tem um index, chamado de inode number, que representa cada inode individualmente em um array de inodes.

Algumas informações que os inodes carregam:

  •  A localização do conteudo do arquivo no disco.
  •  O dono do arquivo.
  • O grupo do arquivo.
  • O timestamp (atime, ctime, mtime)
  • As permissões, tipo de arquivo (diretório, link, regular, etc)
  • O tamanho do arquivo em bytes
  • O número de hard links
  • etc

A quantidade de informações em um inode depende muito do sistema que você estiver utilizando (diferentes sabores de unix) e do sistema de arquivos. Penso que as informações acima são as mais básicas e creio que estejam presente em quase todo tipo de sistema.

Stat

Entenda por stat o ato de se obter o inode de um arquivo. Em C temos a função stat() que salva todas as informações do inode de um arquivo numa struct stat. Não irei mostrar o uso dessa função aqui, mas você pode encontrar mais sobre ela nas referências.

Existe o comando stat que com ele dá para você acessar o inode dos arquivos:

$ stat /etc/passwd
File: `/etc/passwd'
Size: 1052 Blocks: 8 IO Block: 4096 regular file
Device: 802h/2050d Inode: 811390 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 42/ gdm) Gid: ( 0/ root)
Access: 2011-03-03 05:51:32.487342017 -0300
Modify: 2011-02-18 13:11:40.969996299 -0200
Change: 2011-03-01 23:21:18.200804233 -0300

Diretórios

Um diretório no linux é um arquivo comum, mas tratado especialmente pelo sistema de arquivos. Os diretórios são, na verdade, uma tabela que mapeia o nome de um arquivo em seu inode. Como vimos, o inode não carrega o nome do arquivo, ficando essa tarefa a cargo dos diretórios. Imagine um diretório com 4 arquivos dentro sendo um deles outro diretório:

$ ls dir
dir2 file1 file2 file3 file4

internamente ele é visto como:

+-----------------+-----------------+
|Nome do arquivo  | Número do Inode |
+-----------------+-----------------+
|      "."        |       7789      |
+-----------------+-----------------+
|      ".."       |       1205      |
+-----------------+-----------------+
|     "dir2"      |       2145      |
+-----------------+-----------------+
|    "file1"      |       7845      |
+-----------------+-----------------+
|    "file2"      |       2078      |
+-----------------+-----------------+
|    "file3"      |       7845      |
+-----------------+-----------------+
|    "file4"      |       6397      |
+-----------------+-----------------+

O nome do diretório é apenas um ponteiro para uma tabelinha parecida com essa. Repare também que cada diretório contém o diretório “.”, uma referência a si próprio e o diretório “..”, que é o diretório anterior a ele.

(Curiosidade: os inodes dos diretórios “.” e “..” do diretório raiz “/” são os mesmos).

Permissões de diretório

Como diretórios são tratados de forma diferente dos demais arquivos pelo sistema de arquivos, as suas permissões também se diferem.

r – Listar um diretório

Listar um diretório significa descobrir quais arquivos ele contém. Em C utilizamos as funcões opendir() e readdir(). No shell você pode utilizar o comando ls.

Sem ‘r’ é impossível ver os arquivos que um diretório contém, mas isso não impede que você acesse esses arquivos. Continue lendo.

w – Gravar em um diretório

Essa permissão permite que mais arquivos sejam acrescentados na tabelinha vista acima. O ‘w’ não só permite acrescentar, como permite deletar e renomear entradas da tabela também.

Se um diretório tem ‘w’ para seu usuário, então você pode simplesmente deletar todo e qualquer arquivo desse diretório. Por isso que, permissão de escrita para qualquer usuário ou grupo deles em diretórios críticos do sistema, pode acarretar em sérios problemas.

Quando vamos deletar um arquivo e aparece a mensagem “remove write-protected” é porque não temos permissão de escrita nele, mas temos no diretório em que ele pertence. O arquivo será deletado normalmente.

$ id
uid=1000(daemonio) gid=100(users) groups=100(users)
$ mkdir mydir
$ su
# umask
022
# touch mydir/rootao
# exit
$ touch mydir/myfile
$ chmod -w mydir/myfile
$ rm mydir/rootao
rm: remove write-protected regular empty file `ddd/rootao'? y
$ rm mydir/myfile
rm: remove write-protected regular empty file `ddd/myfile'? y

O umask serviu para mostrar que quando o root cria o seu arquivo, ele não vem com permissão de ‘w’ para outros.

O exemplo acima reforçou a idéia de quanto a permissão ‘w’ é importante. Um arquivo pode pertencer a qualquer pessoa inclusive o root ou o Chuck Norris (?), mas se ele estiver em um diretório em que você tem ‘w’, você pode fazer a festa deletando esse arquivo.

O melhor deixei pro final: Esquece tudo o que você leu sobre o ‘w’, pois se o diretório não te dá permissão de execução, então ter ‘w’ não faz sentido.

x – Dar stat nos inodes.

O que adianta um diretório armazenar inodes se você não pode lê-los?? A permissão ‘x’ indica que o usuário em questão pode ter acesso aos inodes dos arquivos do diretório. Quando digo ter acesso, não estou falando em ler ou escrever, estou falando em “enxergar” o arquivo no disco. Para que o kernel possa aplicar as permissões de um arquivo, ele precisa enxegar o mesmo através dos números de inodes.

Achou que aquela seção sobre inodes era só para encher linguiça, né? :)

Se você não tem ‘x’ em um diretório então você não pode acessar os inodes de seus arquivos. Sem acesso aos inodes, você perde, mas perde muita informação sobre determinado arquivo. Para se ter ideia disso é só você voltar na seção de inode e ver as informações que os inodes armazenam. Após isso, leia tudo em voz alta novamente só que dizendo “você NÃO PODE VER” antes de cada item.

Agora você me diz: Faz sentido ter ‘w’ em um diretório em que você não tem ‘x’? NÃO.

Pense comigo: O ‘w’ permite você deletar arquivos de um diretório. Só que para deletar um arquivo você precisa de algumas informações dele, como o número de hard links. Essas informacões estão onde? Sim, no inode. E como se acessa um inode? Stat. Mas stat só é possível com a permissão ‘x’ ativada. Por isso as permissões ‘x’ e ‘w’ andam atreladas, sendo que sem ‘x’ a permissão ‘w’ é inútil.

Veja abaixo todas as combinações de permissões rwx nos diretórios e suas aplicações:

rwx = Faça o que quiser com o diretório. Você pode listá-lo e APAGAR TODOS seus arquivos, mesmo eles não sendo seus.

rw- = Não há muito o que fazer, a não ser listar os arquivos. Nesse caso a permissão ‘w’ é irrelevante, pois o comportamento dela depende da permissão ‘x’. O legal aqui é que você pode ver o nome dos arquivos mas não pode ver suas informações, ou seja, o inode. Faça o teste em qualquer diretório seu aí com essas permissões.

$ ls mydir
file1 file2 file3
$ chmod -x mydir
$ ls -la mydir
ls: cannot access mydir/file3: Permission denied
ls: cannot access mydir/file2: Permission denied
ls: cannot access mydir/..: Permission denied
ls: cannot access mydir/.: Permission denied
ls: cannot access mydir/file1: Permission denied
total 0
d????????? ? ? ? ? ? ./
d????????? ? ? ? ? ? ../
-????????? ? ? ? ? ? file1
-????????? ? ? ? ? ? file2
-????????? ? ? ? ? ? file3

O ls tenta dar stat nos arquivos, mas como você não tem ‘x’ no diretório, ele não consegue e retorna “Permission denied”. Sem stat, sem informacões sobre o arquivo, com isso onde era para estar as permissões, timestamp, hardlinks, etc, aparece o sinal de interrogação.

r– = o mesmo que acima.

-w- = Você não pode fazer nada com esse diretório.

= O mesmo que acima.

-wx = Isso é estranho. Embora você não consiga ver o conteuúo do diretório (via ls), você consegue criar/renomear/apagar qualquer arquivo dentro dele. Nesse caso, você terá que, por exemplo, deletar o arquivo com o nome completo, sem a ajuda do auto-completition do bash/zsh/etc (esse recurso só esta disponível se há ‘r’ no diretório).

r-x = Normal. A única diferença é que você não pode criar/renomear/apagar arquivos nesse diretório, mas você pode ver a lista dos arquivos e acessar as informações deles.

–x = Você pode acessar o inode dos arquivos mas não pode listar o nome deles, além do mais você não pode criar/renomear/apagar nada nesse diretório. O acesso ao arquivo deve ser feito pelo nome absoluto do mesmo (igual a permissão -wx). Após o acesso, vai depender das permissões desse arquivo se você pode lê-lo ou não.

Hard Links

Com hard links é possível quebrar a barreira que a falta da permissão ‘x’ em um diretório. Veja:

$ mkdir mydir
$ echo readme > mydir/myfile
$ chmod -x mydir
$ cat mydir/myfile
cat: mydir/myfile: Permission denied
$ chmod +x mydir
$ ln mydir/myfile hardfile
$ chmod -x mydir
$ cat hardfile
readme

No final conseguimos ver o conteúdo de myfile dentro de um diretório sem ‘x’. Isso é possível porque hardlinks representam o mesmo arquivo, o mesmo inode. A incapacidade de acessar o myfile se deve ao fato de que não podemos acessar seu inode pelo diretório mydir. Só que criando hardlinks em outros diretórios, conseguimos o inode do myfile e enxergar o conteúdo dele.

Symbolic Links

Não há muito o que falar aqui. As permissões dos links simbólicos geralmente são ignoradas pelo kernel dos *nix e para melhor representação, eles tem permissões 777. As permissões do arquivo em que o link aponta são as que serão avalidas pelo kernel quando uma operação nesse arquivo for feita.

Permissões Especiais

Agora um pouco sobre as permissões especiais. Não irei falar muito delas por causa do conteúdo vasto que pode ser encontrado na internet.

As permissões especiais são: SUID, SGID, Sticky Bit. Seus comportamentos também se diferem quando são empregadas em arquivos e diretórios.

Para setar essas permissões, use o chmod. Os valores em octal dessas permissões podem ser vistos abaixo. A dica aqui, para lembrar da tabelinha, é só por em sequência as permissões SUID, SGID, STICKY e depois transformar o número binário em octal, como fizemos antes para as permissões normais.

+----------------------+-------+-------+---------+-------+
|Permissões Desejadas  | SUID  | SGID  | Sticky  | Octal |
+----------------------+-------+-------+---------+-------+
|        SUID          |   1   |   0   |    0    |   4   |
+----------------------+-------+-------+---------+-------+
|     SUID, SGID       |   1   |   1   |    0    |   6   |
+----------------------+-------+-------+---------+-------+
|     SUID, Stick      |   1   |   0   |    1    |   5   |
+----------------------+-------+-------+---------+-------+
|  SUID, SGID, Stick   |   1   |   1   |    1    |   7   |
+----------------------+-------+-------+---------+-------+
|        SGID          |   0   |   1   |    0    |   2   |
+----------------------+-------+-------+---------+-------+
|     SGID, Stick      |   0   |   1   |    1    |   3   |
+----------------------+-------+-------+---------+-------+
|       Sticky         |   0   |   0   |    1    |   1   |
+----------------------+-------+-------+---------+-------+

Setando as permissões especiais

Antes de tudo:

Para usar SUID bit é preciso ter permissão ‘x’ no dono.
Para usar SGID bit é preciso ter permissão ‘x’ no grupo.
Para usar STICKY bit é preciso ter permissão ‘x’ em outros.

Para setar as permissões no chmod, use ‘s’ tanto para SUID e SGID. A diferença é que o primeiro deve ser ativado para o dono do arquivo e o segundo para o grupo. O sticky bit é ativado através da letra ‘t’.

$ chmod u+s file
Ativa SUID bit em file.

$ chmod g+s file
Ativa SGID bit em file.

$ chmod +s file
Ativa tanto SUID quanto SGID em file.

$ chmod +t diretório
Ativa o sticky bit no diretório

SUID – Set User ID

Todo arquivo no disco tem um dono, e esse dono é identificado não pelo seu nome, mas sim pelo seu UID (o id de identificação no sistema). Um programa na memória, ou seja, um processo, possui um segundo identificador, o chamado Effective User Id (ou EUID). O EUID existe para que um processo possa ser executado por um usuário diferente do usuário que está executando esse processo.

Observe o programa passwd. Ele pode ser executado por qualquer usuário no sistema para que ele mude a sua senha. Esse programa precisa alterar o arquivo /etc/shadow, coisa que só o usuário root pode fazer, daí nesse caso, o sistema executa o passwd como usuário root para que o usuário altere sua senha sem problemas.

A maioria dos processos tem EUID igual ao UID, e o UID tem o mesmo valor do UID de quem executa o processo. Até aí tudo bem. Se um programa tem o SUID bit ativado então ele pode ter seu EUID diferente do UID, sendo que o EUID será igual ao UID do DONO do arquivo.

As funções setuid() e seteuid()

A primeira função serve para alterar o UID (o ID real) do programa. O valor do novo UID pode ser igual ao antigo UID ou igual ao EUID. Como disse, se o SUID estiver desativado então UID é igual ao EUID, sempre. Caso o SUID for ativado, então UID apontará para o UID de quem executa o processo e o EUID para o UID do DONO do arquivo.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    printf("UID: %d | EUID: %d\n", getuid(), geteuid() ) ;

    /* faz o ID real ser igual ao EUID */
    setuid(geteuid());

    printf("UID: %d | EUID: %d\n", getuid(), geteuid() ) ;
}

Primeiro o programa mostra o seu UID e o EUID. Depois ele seta o UID para o EUID e mostra as informações novamentes. Veja abaixo um exemplo de execução:

$ su
# gcc -o ex ex.c
# chmod +s ex
# exit
$ ./ex
UID: 1000 | EUID: 0
UID: 0 | EUID: 0

O usuário root compilou e setou o SUID no executável. Um usuário normal de UID 1000 executou o programa. A primeira linha da saída mostrou que o UID do processo é 1000 e o EUID é 0. Após a função setuid() setar o UID = EUID, o UID real do processo ficou como 0, o de super-usuário.

Algum tempo atrás, era possível dar SUID bit em uma shell para que depois, enventualmente, poderia conseguir root no sistema. O problema é que esse esquema não funciona mais, pois a maioria dos shells foram patcheados para contornarem esse problema. Mas, se você conseguiu root no sistema alguma vez, então você pode simplesmente criar um executável qualquer com SUID que invoca uma shell. Essa shell será executada como root.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    if ( geteuid() == 0 ) {
        /* faz o ID real ser igual ao EUID */
        setuid(0);
        execl("/bin/sh", "sh", NULL) ;
    }
}

Se geteuid() for igual a zero, uma shell sh será aberta como root:

$ su
# gcc -o ex2 ex2.c
# chmod +s ex2
# exit
$ ./ex
# id
uid=0(root) gid=100(users)

Já a função seteuid() seta o valor do EUID. Creio que não há muito o que fazer com essa função, exceto no caso em que você quer rebaixar os privilégios do programa.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {

    if ( geteuid() == 0 && getuid() != 0 ) {
        puts("adeus uid 0.") ;
    }

    seteuid(getuid()) ;

    printf("UID: %d | EUID: %d\n", getuid(), geteuid()) ;
}

Testando:

$ su
# gcc -o ex3 ex3.c
# chmod +s x
# exit
$ ./ex3
adeus uid 0.
UID: 1000 | EUID: 1000

Uma coisa também que pode surgir como dúvida é porque a permissão SUID (e SGID) não é ativada em scripts. Por motivo de segurança muitos sistemas desativam as permissões especiais para scripts. Isso implica que não é possível rodar um script e executar a sequência de comandos nele como outro usuário.

# echo 'cat /etc/shadow' > ex
# chmod  4777 ex
# exit
$ ./ex
cat: /etc/shadow: Permission denied

Outra segurança implementada em relação as permissões especiais, é que quando o conteúdo de algum executável com SUID/SGID é alterado, essas permissões são perdidas. Para entender isso, imagine a situação: O root descuidadosamente deu chmod 4777 em algum arquivo executável. Daí um espertinho, como tem ‘w’ no arquivo, altera o conteúdo do mesmo. Após isso ele executa o arquivo com um código criado por ele como root. Isso é possível? Não. Quando o espertinho alterar o conteúdo do arquivo, a permissão SUID desaparece (embora a permissão 777 continue). Os comandos abaixo exemplificam o esquema:

xxx$ ls -la
-rwxr-xr-x 1 daemonio users 5832 2011-03-24 14:35 hack*
-rwsrwxrwx 1 root root 6091 2011-03-24 14:56 suidao*
$ cat hack > suidao
$ ls -la
-rwxr-xr-x 1 daemonio users 5832 2011-03-24 14:35 hack*
-rwxrwxrwx 1 root root 5832 2011-03-24 15:00 suidao*

Veja que o SUID bit do arquivo suidao foi desativado.

Set Group ID – SGID

Em arquivos, o SGID trabalha do mesmo modo que o SUID. A diferenca é que agora o sistema trabalha com o GID e o EGID do processo, mas o esquema é praticamente o mesmo, então não irei explicar novamente.

Você também pode aplicar o SGID em diretórios. Nesse caso o comportamento não tem nada a ver com o que já vimos: Se o SGID bit for ativado em um diretório, todos os arquivos criados desde então nesse diretório terão o seu GID igual ao GID do diretório. Resumindo: Os arquivos serão criados pertencendo ao grupo do diretório.

$ mkdir mydir; touch mydir/file1; ls -la mydir
drwxr-xr-x 2 daemonio users 4096 2011-03-04 02:07 ./
drwx--x--x 49 daemonio users 4096 2011-03-04 02:06 ../
-rw-r--r-- 1 daemonio users 0 2011-03-04 02:07 file1
$ chgrp audio mydir
$ chmod g+s mydir
$ touch mydir/file2
$ ls -la mydir
drwxr-sr-x 2 daemonio audio 4096 2011-03-04 02:08 ./
drwx--x--x 49 daemonio users 4096 2011-03-04 02:07 ../
-rw-r--r-- 1 daemonio users 0 2011-03-04 02:07 file1
-rw-r--r-- 1 daemonio audio 0 2011-03-04 02:08 file2

Sticky Bit

Aplicar o sticky bit em arquivos, hoje em dia já está obsoleto. Antigamente, quando o tamanho da memória RAM era muito pequena (em torno de 64kb) e dentro dela, deveria caber o código do sistema operacional e mais alguns outros programas. Assim, os projetistas pensaram que algo deveria ser feito para facilitar o carregamento de programas. O sticky bit era utilizado em arquivos executáveis e fazia com que o kernel gravasse a imagem de um processo no dispositivo de swap, para que quando esse mesmo processo fosse carregado novamente, ele seria aberto mais rápido.

A utilidade mesmo do sticky bit está nos diretórios. Pelo que vimos por todo esse tutorial, se você tem ‘w’ em um dir, então você pode deletar qualquer arquivo, mesmo não sendo seu, nesse diretório.

Há alguns casos em que os usuários devem ter permissão de gravação em um diretório mas ninguém deve apagar o arquivo do outro. Um exemplo tradiconal é o diretório /tmp. Você pode criar seus arquivos lá,  porque você tem ‘w’, mas não pode apagar arquivos de outras pessoas. Ativando o sticky bit em um diretório, cada usuário só poderá apagar os arquivos de que ele é dono.

Umask

Crie um arquivo, mas não sete permissões para ele. Quais as permissões dadas a ele no momento da criação? E qual o porquê delas? O umask é uma máscara utilizada pelo sistema para indicar as permissões dos arquivos criados. O problema é que o umask, como disse, é uma máscara e não a permissão dos arquivos em si (seria bem melhor se fosse assim).

O umask funciona da seguinte maneira: Cada dígito octal indica uma permissão que NÃO DEVE TER no novo arquivo. Em muitas distribuições o umask padrão é:

$ umask
022

Para saber o valor da permissão, transforme cada dígito octal em sua permissão equivalente. Essa permissão obtida NÃO DEVE ESTAR na permissão final.

Para o umask igual a 022: Para o dono, a permissão é zero. Isso indica que a permissão 0 não deve ser usada, sendo assim, ela libera todas as outras (rwx).

Para o grupo, a permissão é dois. Isso indica que a permissão ‘w’ não deve ser usada, sendo assim, ela libera as permissões r-x.

Para outros, a permissão é dois. Isso indica que a permissão ‘w’ não deve ser usada, sendo assim, ela libera as permissões r-x.

A permissão final, então, será: rwxr-xr-x (ou 755). Certo??

Errado. Uma coisa, em particular, que deve ser notada: Todo arquivo regular não pode ser criado com permissão de execução. No exemplo acima, mesmo o umask retirando somente a permissão ‘w’, para arquivos regulares, a permissão ‘x’ não deve ser concedida.

Então a permissão final será: rw-r–r– (ou 644). Certo?? Depende. -_-“

A máscara do umask serve tanto para arquivos e diretórios. Para arquivos, a permissão ‘x’ deve ser ignorada, como vimos anteriormente. Mas para diretórios não. Se o que criamos acima for um arquivo então a permissão final será o 644. Se for um diretório, então a permissão final será o 755, pois o ‘x’ não é ignorado aqui, e nem pode.

Calculando o umask

Transformar umask em permissão é uma tarefa fácil e ao contrário também. Essas duas tarefas, na verdade, podem ser feitas com a mesma operação. Pense em um operador binário que transforma x em y, depois, ao se aplicar o y como entrada se obtém o x. Que operação é essa?? Estrelinha para quem respondeu: XOR.

É bom ressaltar que o umask contém os bits que devem ser desativados na permissão final. Esses bits estão numa posição específica e que quando são “xorados” com a permissão total (777(8)), eles são desabilitados, e o restante é habilitado. Nada melhor que um exemplo, transformando a umask 022 para permissões de um diretório:

022(8) = 000 010 010 (2)
777(8) = 111 111 111 (2)
 -----------------------------------------> XOR
755(8) = 111 101 101 (2) (permissão para diretórios)

Esse resultado já é a permissão final.

Para arquivos regulares, o bit de execução nunca deve estar ligado. Isso implica que devemos passar uma outra máscara, via AND, que desabilite os bits ‘x’s. A máscara é a 666, que representa a permissão rw-rw-rw- (permissão completa sem o bit ‘x’).

755(8) = 111 101 101 (2) (resultado anterior)
666(8) = 110 110 110 (2)
--------------------------> AND
644(8) = 110 100 100 (2) (permissão para arquivos regulares)

Lembre-se que devemos aplicar essa segunda máscara somente para arquivos regulares. Para diretórios, a permissão final é o próprio resultado do XOR.

Mão na massa agora:

1)
umask:022 (8)
tipo de arquivo: arquivo regular
022(8) = 000 010 010 (2)
777(8) = 111 111 111 (2)

--------------------------> XOR
755(8) = 111 101 101 (2)
666(8) = 110 110 110 (2)
--------------------------> AND
644(8) = 110 100 100 (2)

2)
umask: 341 (8)
tipo de arquivo: arquivo regular

341(8) = 011 100 001 (2)
777(8) = 111 111 111 (2)
--------------------------> XOR
436(8) = 100 011 110 (2)
666(8) = 110 110 110 (2)
--------------------------> AND
426(8) = 100 010 110 (2)

3)
umask: 470 (8)
tipo de arquivo: diretório

470(8) = 100 111 000 (2)
777(8) = 111 111 111 (2)
--------------------------> XOR
307(8) = 011 000 111 (2)

4)
umask: 123 (8)
tipo de arquivo: diretório

123(8) = 001 010 011 (2)
777(8) = 111 111 111 (2)
--------------------------> XOR
654(8) = 110 101 100 (2)

Fiz um codigozinho em C para auxiliar na tarefa de conversão.

#include <stdio.h>

/*
 * [umask2perm.c]
 * Conversor de umask para permissão.
 * by Daemonio
 *
 * Wed Mar  9 14:21:45 BRT 2011
 */

int main() {

    int umask ;

    printf("Digite o umask: ") ;
    scanf("%o", &umask) ;

    if ( umask < 0 || umask > 0x1FF ) {
        printf("Mascara invalida.\n") ;
        return -1 ;
    }

    printf("Permissao para diretorios         : %o\n", (umask ^ 0777)) ;
    printf("Permissao para arquivos regulares : %o\n", (umask ^ 0777) & 0666) ;

    return 0 ;
}

Conclusão

Permissões de arquivos é um diferencial em sistemas baseados no unix. Elas são a fonte primária de segurança, por isso uma configuração mal feita e uma pequena falta de cuidado nelas, pode comprometer o sistema. Espero que este post esclareça as dúvidas de muitos usuários e que sirva de referência para os iniciantes.

Referências

[1] Permissões de Arquivos UNIX (12/2001) by Meleu
http://www.ataliba.eti.br/sections/old-hacking/unsekurity/texto1/permissoes.txt
ou em: http://www.meleuzord.hpg.ig.com.br/

[2] Pratical Unix Security, Capítulo 5 by Simson Garfinkel & Gene Spafford
http://docstore.mik.ua/orelly/networking/puis/ch05_01.htm

3 pensamentos sobre “Divagação sobre Permissões, C e Linux

  1. Pingback: Setuid Em Shell Scripts | Daemonio Labs

  2. Pingback: rafaelmspc.cc | Linux and security stuffs. | Linux – Permissões

Deixe um comentário