SSD Nodes Learn 🎉 VPS desde $5.50/mês
Guias Matt ConnorPor Matt Connor

chmod 755 ou u+x: modos numérico e simbólico

Entenda chmod 755 e u+x, os dígitos octais, u/g/o e por que chmod -R 755 quebra árvores. Veja como X maiúsculo evita executar arquivos comuns.

O que o chmod altera

chmod altera os bits de permissão de um ficheiro ou diretório e aceita esses bits numa de duas notações. A forma numérica é um número octal que substitui todos os bits de permissão de uma vez. A forma simbólica identifica uma classe de utilizador e um operador e altera apenas os bits indicados. Ambas terminam na mesma chamada de sistema. A diferença está no que acontece aos bits que não foram mencionados.

Ler um modo e alterar um modo são tarefas diferentes. Se as letras de uma listagem longa ainda não forem claras, leia primeiro o que significa drwxr-xr-x campo a campo. Este guia apenas os altera.

Execute tudo aqui com o seu utilizador de login normal. A conta root ignora estas verificações, por isso uma demonstração de permissões executada como root não comprova nada. Se ainda estiver a trabalhar como root num servidor novo, crie um utilizador normal com privilégios mínimos e volte aqui.

Configure um sandbox descartável

cd "$(mktemp -d)"
touch notes.txt

mktemp -d cria um diretório vazio em /tmp e imprime o caminho criado. A substituição de comandos passa esse caminho diretamente para cd. Nada do que vem a seguir toca num ficheiro importante.

Um comando apresenta o resultado de cada alteração:

stat -c '%a %A %n' notes.txt

%a apresenta o modo como um número octal, %A apresenta o mesmo modo no formato de letras usado por uma listagem longa e %n apresenta o nome. Nos blocos seguintes, uma linha que começa por $ é o que deve escrever e a linha abaixo mostra o que o comando apresentou. Execute os comandos. O resultado no seu computador deve corresponder linha a linha, porque um modo numérico não depende de nada no seu ambiente.

A forma numérica: um dígito octal por classe

O primeiro dígito pertence ao proprietário do ficheiro. O segundo pertence ao grupo do ficheiro. O terceiro pertence a todos os outros utilizadores. Cada dígito é uma soma, com um valor por bit. Ative um bit de cada vez e veja o que stat apresenta.

$ chmod 400 notes.txt
$ stat -c '%a %A %n' notes.txt
400 -r-------- notes.txt
$ chmod 200 notes.txt
$ stat -c '%a %A %n' notes.txt
200 --w------- notes.txt
$ chmod 100 notes.txt
$ stat -c '%a %A %n' notes.txt
100 ---x------ notes.txt

As letras correspondem aos dígitos. Depois do carácter inicial que indica o tipo de ficheiro, o primeiro grupo de três letras é o do proprietário, o seguinte é o do grupo e o último pertence a todos os outros utilizadores. Some os valores para combinar bits dentro de uma classe.

$ chmod 600 notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt
$ chmod 700 notes.txt
$ stat -c '%a %A %n' notes.txt
700 -rwx------ notes.txt
$ chmod 750 notes.txt
$ stat -c '%a %A %n' notes.txt
750 -rwxr-x--- notes.txt

Um modo numérico é absoluto. Escreve os nove bits em todas as execuções, incluindo os bits de uma classe que nunca tenha considerado.

$ chmod 755 notes.txt
$ stat -c '%a %A %n' notes.txt
755 -rwxr-xr-x notes.txt
$ chmod 600 notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt

O segundo comando não especificou nada sobre o grupo nem sobre os outros utilizadores, mas os respetivos bits também foram alterados. Essa é a característica da forma numérica e é por isso que ela não é adequada para uma pequena alteração. (chmod também trata dos bits setuid, setgid e sticky, que ficam num quarto dígito antes destes. Esse é um tema separado, e este guia limita-se aos três.)

A forma simbólica: uma classe, um operador e os bits

Escreva primeiro a classe. u é o proprietário, g é o grupo, o são os restantes utilizadores e a representa todos ao mesmo tempo. Depois, escreva o operador: + adiciona bits, - remove bits e = define essa classe exatamente com os bits indicados, removendo os restantes bits dessa classe. Em seguida, indique os próprios bits, como r, w ou x.

$ chmod 640 notes.txt
$ stat -c '%a %A %n' notes.txt
640 -rw-r----- notes.txt
$ chmod u+x notes.txt
$ stat -c '%a %A %n' notes.txt
740 -rwxr----- notes.txt
$ chmod g-r notes.txt
$ stat -c '%a %A %n' notes.txt
700 -rwx------ notes.txt
$ chmod o=r notes.txt
$ stat -c '%a %A %n' notes.txt
704 -rwx---r-- notes.txt

Cada comando alterou uma classe e manteve as restantes como estavam. Combine as cláusulas com vírgulas e sem espaços. O chmod aplica-as da esquerda para a direita.

$ chmod u=rw,go=r notes.txt
$ stat -c '%a %A %n' notes.txt
644 -rw-r--r-- notes.txt
$ chmod go= notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt

go= sem nada depois do sinal de igualdade remove todos os bits do grupo e dos restantes utilizadores. Este é o formato adequado para um ficheiro que só o proprietário pode ler, como a parte privada de um par de chaves SSH.

O chmod também pode apresentar o resultado da operação. Isto é útil num script quando não há ninguém a observar o ecrã.

chmod -v u+x notes.txt
chmod -v u+x notes.txt

-v apresenta uma linha para cada ficheiro indicado. Execute os dois comandos e compare as linhas no ecrã: a primeira identifica o ficheiro e indica o modo anterior e o modo novo, e a segunda indica que o modo foi mantido, porque o bit que devia adicionar já estava definido. -c apresenta uma linha apenas quando um ficheiro é efetivamente alterado, pelo que é a opção mais adequada para manter num log.

chmod 755 vs u+x: que notação usar

Comece duas vezes com o mesmo ficheiro e compare o que cada notação deixa definido.

$ chmod 640 notes.txt
$ chmod 755 notes.txt
$ stat -c '%a %A %n' notes.txt
755 -rwxr-xr-x notes.txt
$ chmod 640 notes.txt
$ chmod u+x notes.txt
$ stat -c '%a %A %n' notes.txt
740 -rwxr----- notes.txt

Ambos os comandos tornaram o ficheiro executável para o proprietário. Apenas um deles deixou inalteradas as outras duas classes. Use um modo numérico quando souber exatamente qual deve ser o estado final e quiser impô-lo. Este é o caso correto num script de implementação que tem de produzir o mesmo resultado numa máquina que nunca viu. Use um modo simbólico quando a frase que tem em mente contém adicionar ou remover, porque a forma numérica não permite dizer deixar essa parte inalterada.

O modo com que um ficheiro novo começa não vem do chmod. Vem da umask do processo que criou o ficheiro. Execute umask e umask -S na sua própria shell para ver o valor aplicado nesse contexto. Espere que seja diferente entre distribuições, entre a sua shell de login e um serviço systemd, e entre uma conta e outra. A umask define o modo de todos os ficheiros novos, por isso determina o estado inicial antes de o chmod ser executado.

O que o bit de execução faz num diretório

Este é o mal-entendido que mais tempo custa. Num ficheiro normal, o bit de execução indica que o kernel pode executar o ficheiro. Um diretório não contém instruções, portanto não há nada para executar. Num diretório, o bit de execução significa travessia: permissão para resolver um nome dentro dele. Para chegar a dir/file, precisa dessa permissão em dir. O bit de leitura é uma permissão separada e permite listar os nomes contidos no diretório. É possível ter uma permissão sem a outra, algo que é mais fácil de compreender depois de observar esse comportamento.

$ mkdir vault
$ printf 'hello\n' > vault/secret.txt
$ chmod 600 vault/secret.txt
$ chmod 100 vault
$ echo vault/*
vault/*
$ cat vault/secret.txt
hello

A shell apresentou o padrão sem alterações porque expandir vault/* significa ler o diretório, e um glob sem correspondências é mantido como texto literal em vez de gerar um erro. cat continuou a funcionar porque forneceu o nome diretamente e a travessia era permitida. Agora troque os dois bits.

$ chmod 400 vault
$ echo vault/*
vault/secret.txt
$ cat vault/secret.txt
cat: vault/secret.txt: Permission denied

Os nomes estão visíveis, mas o conteúdo não. A leitura fornece a lista. A execução fornece o acesso. Quase todos os diretórios que utiliza precisam das duas permissões.

$ chmod 500 vault
$ cat vault/secret.txt
hello

Por que chmod -R com um modo numérico danifica uma árvore

-R percorre toda a árvore e aplica o modo indicado a tudo o que encontra. Um diretório e um ficheiro de dados precisam de bits diferentes, por isso um único número absoluto não pode estar correto para ambos. Crie uma árvore pequena e observe o erro.

$ mkdir -p site/css
$ touch site/index.html site/css/main.css
$ printf '#!/bin/bash\necho hi\n' > site/deploy.sh
$ chmod 755 site site/css site/deploy.sh
$ chmod 644 site/index.html site/css/main.css
$ stat -c '%a %A %n' site site/css site/index.html site/css/main.css site/deploy.sh
755 drwxr-xr-x site
755 drwxr-xr-x site/css
644 -rw-r--r-- site/index.html
644 -rw-r--r-- site/css/main.css
755 -rwxr-xr-x site/deploy.sh

Essa é a disposição adequada para um diretório de ficheiros estáticos. Este é o primeiro erro recursivo.

$ chmod -R 755 site
$ stat -c '%a %A %n' site/index.html site/css/main.css
755 -rwxr-xr-x site/index.html
755 -rwxr-xr-x site/css/main.css

Nada falhou, e esse é o problema. O erro é silencioso, por isso permanece em instruções copiadas durante anos. Agora, dois ficheiros de dados são identificados como programas. O Git armazena o bit de execução, por isso o próximo commit leva a alteração para todos os que clonarem o repositório, e rsync e tar levam-na para todas as máquinas para as quais copiar a árvore.

O segundo erro recursivo é evidente. Aplique a um diretório um modo sem o bit de execução e o diretório fica fechado.

$ chmod 644 site
$ stat -c '%a %A %n' site
644 drw-r--r-- site
$ echo site/*
site/css site/deploy.sh site/index.html
$ cd site
bash: cd: site: Permission denied
$ cat site/index.html
cat: site/index.html: Permission denied

Os nomes continuam a ser listados porque o bit de leitura permaneceu, e todos os caminhos através do diretório ficam fechados porque o bit de execução não permaneceu. chmod -R 644 site faz isso a todos os diretórios da árvore com um único comando. O resultado nem sempre é uniforme, porque chmod precisa de percorrer os mesmos diretórios cuja travessia está a remover. Por isso, confirme o que foi realmente aplicado com find site -type d -exec stat -c '%a %n' {} + em vez de presumir. Reponha o estado anterior antes de continuar.

$ chmod 755 site
$ chmod 644 site/index.html site/css/main.css
$ stat -c '%a %A %n' site site/index.html
755 drwxr-xr-x site
644 -rw-r--r-- site/index.html

Um chmod recursivo não tem desfazer. chmod não regista aquilo que substituiu, por isso a reparação depende de si: terá de reconstruir os modos com base no que acredita que existia antes. Esse é o mesmo trabalho lento e incerto que reconstruir ficheiros depois de um rm -rf acidental, e a lição é a mesma: verifique o destino de um comando recursivo antes de premir Enter.

O X maiúsculo: executar em diretórios, não em todos os ficheiros

Os modos simbólicos aceitam X e x. X define o bit de execução apenas onde faz sentido: num diretório ou num ficheiro regular que já tenha um bit de execução definido para alguma classe. Essa regra corresponde exatamente à regra que pretendia que -R seguisse.

$ chmod -R u=rwX,go=rX site
$ stat -c '%a %A %n' site site/css site/index.html site/css/main.css site/deploy.sh
755 drwxr-xr-x site
755 drwxr-xr-x site/css
644 -rw-r--r-- site/index.html
644 -rw-r--r-- site/css/main.css
755 -rwxr-xr-x site/deploy.sh

Um comando foi suficiente, e os diretórios continuaram acessíveis enquanto os ficheiros de dados permaneceram inalterados. O script manteve o bit de execução porque já tinha um, que é a segunda parte da regra X. X consulta o modo que um ficheiro tem neste momento, por isso um ficheiro que já perdeu todos os bits de execução não pode recuperá-los através dele.

$ chmod 644 site/deploy.sh
$ chmod -R u=rwX,go=rX site
$ stat -c '%a %A %n' site/deploy.sh
644 -rw-r--r-- site/deploy.sh
$ site/deploy.sh
bash: site/deploy.sh: Permission denied
$ chmod u+x site/deploy.sh
$ stat -c '%a %A %n' site/deploy.sh
744 -rwxr--r-- site/deploy.sh
$ site/deploy.sh
hi

A mesma regra funciona no sentido inverso. X pode estender a outra classe um bit de execução que um ficheiro já tenha:

$ chmod go+X site/deploy.sh
$ stat -c '%a %A %n' site/deploy.sh
755 -rwxr-xr-x site/deploy.sh

Assim, o x minúsculo serve para tornar executável um ficheiro específico, enquanto X serve para percorrer uma árvore. Quando pretende definir um modo exato para cada tipo de objeto, em vez de aplicar uma regra baseada no modo atual, divida a pesquisa com find.

find site -type d -exec chmod 755 {} +
find site -type f -exec chmod 644 {} +
chmod u+x site/deploy.sh

-type d seleciona diretórios e -type f seleciona ficheiros regulares, para que cada tipo receba o modo correto. -exec ... + agrupa muitos caminhos numa única chamada a chmod, em vez de iniciar um processo por ficheiro, o que é importante numa árvore com milhares de entradas. O script recupera o seu bit numa linha separada, de forma deliberada.

Verifique o resultado antes de terminar

Dois comandos encontram os erros relevantes depois de qualquer alteração recursiva. O primeiro lista os diretórios nos quais já não pode entrar.

find . -type d ! -perm -u+x

O segundo lista os ficheiros que qualquer conta na máquina pode editar.

find . -type f -perm -o+w

Em -perm -o+w, o - inicial significa pelo menos estes bits, por isso corresponde a um ficheiro cuja classe o tem o bit de escrita, independentemente dos restantes bits definidos. O resultado pretendido é que nenhum dos comandos apresente saída. Execute ambos no topo de qualquer árvore que tenha acabado de alterar com -R e execute stat -c '%a %A %n' no pequeno conjunto de caminhos que pretendia alterar, para confirmar que o modo que pensa ter definido é o modo que o kernel mantém efetivamente.

FAQ

Qual é a diferença entre chmod 755 e chmod u+x?

Um modo numérico é absoluto. Ele define todos os bits de permissão do ficheiro, incluindo as classes que não tinha intenção de alterar. Um modo simbólico é uma edição. u+x adiciona um bit ao proprietário e mantém todos os outros bits como estão. Use a forma numérica quando souber exatamente qual deve ser o estado final do ficheiro. Use a forma simbólica quando quiser adicionar ou remover apenas uma permissão. Execute stat -c '%a %A %n' <file> antes e depois de qualquer um dos comandos. A diferença aparece no resultado.

Por que chmod -R 755 num diretório com ficheiros web é uma má ideia?

Porque -R aplica o mesmo modo absoluto a diretórios e ficheiros regulares, mas estes precisam de bits diferentes. Um diretório precisa do bit de execução para permitir a travessia. Ficheiros de dados, como HTML e CSS, não precisam desse bit. Marcá-los como executáveis é uma alteração que o git regista no commit seguinte e que o rsync copia para a máquina seguinte. Use chmod -R u=rwX,go=rX <dir> para que o bit de execução seja aplicado apenas aos diretórios, ou use find com -type d e -type f para atribuir um modo próprio a cada tipo.

O que faz o bit de execução num diretório?

Ele permite a travessia, não a execução. Não há nada dentro de um diretório para executar. O bit de execução permite resolver um nome dentro desse diretório. Por isso, precisa dele em todos os diretórios ao longo de um caminho antes de poder abrir o ficheiro no fim desse caminho. O bit de leitura é separado e permite listar os nomes. É possível ter um sem o outro: com apenas o bit de execução, pode abrir um ficheiro cujo nome já conhece, mas a shell não consegue expandir um glob nesse diretório; com apenas o bit de leitura, pode ver os nomes, mas todas as tentativas de abrir um deles falham.

Quando devo usar X maiúsculo em vez de x minúsculo?

Use X sempre que o comando for recursivo. X define o bit de execução nos diretórios e, nos ficheiros regulares, apenas quando já existe um bit de execução definido. Assim, uma única passagem torna uma árvore atravessável sem transformar ficheiros de dados em programas. Use x minúsculo x quando estiver a indicar um único ficheiro e quiser alterar esse ficheiro. Há uma limitação importante: X não consegue restaurar um bit de execução que já tenha sido removido de todos os ficheiros, porque já não existe nenhum bit correspondente. Reponha esse bit com chmod u+x <file>.

O chmod altera o proprietário de um ficheiro?

Não. chmod altera apenas os bits de permissão. A propriedade é definida por chown para o utilizador e por chgrp para o grupo. Transferir um ficheiro para outro utilizador requer root. Isto é importante porque os bits são interpretados com base no utilizador e no grupo registados no ficheiro, não com base em quem o escreveu por último. Execute stat -c '%U %G %a %n' <file> para ver o proprietário, o grupo e o modo em conjunto antes de decidir de quais dos três comandos realmente precisa.