Permissões de arquivo no Linux: chmod, chown e umask
1. Visão geral
O erro Permission denied é um dos erros mais comuns ao fazer deploy de aplicações em Linux. A aplicação não consegue gravar logs, não consegue ler arquivo de configuração, ou arquivo secreto acaba sendo lido por qualquer usuário.
Este artigo explica o modelo de permissões de arquivo do Linux e como usar três ferramentas principais: chmod para mudar permissões, chown para mudar o proprietário, umask para controlar as permissões padrão de novos arquivos. Ao final, você será capaz de ler as permissões de qualquer arquivo, conceder permissões no nível correto necessário, e manipular permissões POSIX a partir de Java.
2. Leia permissões de arquivo com ls -l
Comecemos com um diretório de exemplo:
mkdir -p shop && cd shop
echo "id,total" > order.csv
mkdir reports
ls -l
-rw-r--r-- 1 an dev 9 Oct 13 09:00 order.csv
drwxr-xr-x 2 an dev 4096 Oct 13 09:00 reports
A primeira coluna tem 10 caracteres:
- Caractere 1 é o tipo:
-é arquivo regular,dé diretório,lé symbolic link. - Os 9 caracteres restantes são divididos em três grupos, cada grupo com 3 caracteres: user (proprietário), group (grupo), other (todos os outros).
- Cada grupo contém
r(leitura),w(escrita),x(execução). O hífen-significa que não há essa permissão.
A terceira e quarta coluna são o proprietário (an) e grupo (dev). Portanto, com order.csv, an pode ler e escrever, membros do grupo dev apenas leem, e outros usuários também apenas leem.
Para ver as permissões em forma numérica, use stat:
stat -c '%a %A %U:%G %n' order.csv reports
644 -rw-r--r-- an:dev order.csv
755 drwxr-xr-x an:dev reports
O kernel verifica permissões em ordem. Se você é o proprietário, apenas o grupo de permissões do user é aplicado. Se não for o proprietário mas for membro do grupo, apenas o grupo de permissões do group é aplicado. Caso contrário, usa-se other. Os grupos não se acumulam. Portanto, um arquivo com permissões ---r--r-- impedirá até o proprietário de ler, mesmo que todos os outros possam ler.
3. Mude permissões com chmod
3.1. Forma simbólica
A forma simbólica tem a sintaxe [ugoa][+-=][rwxX]. Onde u é user, g é group, o é other, a é tudo.
chmod g+w order.csv # adiciona permissão de escrita para o grupo
chmod o-r order.csv # remove permissão de leitura de other
chmod u=rw,go= order.csv # user: rw, grupo e other: nada
stat -c '%a %A' order.csv
600 -rw-------
Os operadores + e - apenas adicionam ou removem as permissões específicas mencionadas, outras permissões permanecem inalteradas. O operador = reatribui todo o grupo. A forma simbólica é segura quando você deseja modificar apenas uma parte sem precisar conhecer as permissões atuais.
3.2. Forma numérica octal
Cada permissão tem um valor: r = 4, w = 2, x = 1. Somar os valores resulta em um dígito para cada grupo.
| Número | Permissão | Caso de uso |
|---|---|---|
| 7 | rwx |
proprietário de diretório ou script |
| 6 | rw- |
proprietário de arquivo de dados |
| 5 | r-x |
leitura e acesso ao diretório, executar script |
| 4 | r-- |
apenas leitura |
| 0 | --- |
sem permissões |
Por exemplo, crie um script e um arquivo contendo senha:
printf '#!/bin/bash\necho "Backup orders..."\n' > backup.sh
echo "db.password=s3cret" > secret.properties
chmod 755 backup.sh
chmod 600 secret.properties
./backup.sh
stat -c '%a %n' backup.sh secret.properties
Backup orders...
755 backup.sh
600 secret.properties
755 permite que qualquer pessoa execute o script, mas apenas o proprietário pode modificá-lo. 600 faz com que apenas o proprietário possa ler e escrever no arquivo secreto. A forma numérica atribui todas as permissões de uma vez, então é apropriada quando você sabe exatamente o estado desejado.
3.3. Mude permissões recursivamente e o X maiúsculo
Um erro clássico é executar o seguinte comando:
chmod -R 755 shop/
Este comando atribui permissão de execução a todos os arquivos, incluindo order.csv. A forma correta é usar X maiúscula. Este símbolo apenas adiciona x para diretórios, ou para arquivos que já têm x em algum grupo:
chmod -R u=rwX,go=rX shop/
O resultado é que diretórios têm permissão 755, arquivos normais têm 644, e backup.sh retém 755. Se precisar de controle mais fino, você pode separar usando find:
find shop -type d -exec chmod 750 {} +
find shop -type f -exec chmod 640 {} +
4. Permissões em diretório diferem de permissões em arquivo
Para diretórios, rwx tem significado diferente:
r: listar nomes de itens dentro (ls).w: criar, deletar, renomear itens dentro. Esta permissão requerxpara ter efeito.x: entrar no diretório (cd) e acessar itens dentro se souber o nome.
Uma consequência surpreendente: deletar um arquivo depende das permissões do diretório, não das permissões do arquivo.
mkdir inbox && echo "data" > inbox/invoice.txt
chmod 444 inbox/invoice.txt # arquivo somente leitura
rm -f inbox/invoice.txt # ainda consegue deletar porque inbox tem permissão w
ls inbox # vazio
Inversamente, se remover a permissão x do diretório, você não consegue ler o arquivo dentro, mesmo que o arquivo tenha permissão 644:
echo "data" > inbox/invoice.txt
chmod 644 inbox/invoice.txt
chmod u-x inbox
cat inbox/invoice.txt
cat: inbox/invoice.txt: Permission denied
Quando a aplicação reporta Permission denied mas as permissões do arquivo parecem corretas, verifique todos os diretórios pai na caminho. O comando namei -l /path/to/file lista as permissões de cada nível. Antes de continuar, restaure a permissão do diretório com chmod u+x inbox.
5. Mude o proprietário com chown e chgrp
chown muda o proprietário, grupo ou ambos:
sudo chown appuser order.csv # apenas muda o proprietário
sudo chown appuser:dev order.csv # muda proprietário e grupo
sudo chown :dev order.csv # apenas muda o grupo
sudo chown -R appuser:appuser /opt/shop
Alguns pontos a lembrar:
- Apenas
rootpode mudar o proprietário. Um usuário comum não pode “presentear” seu arquivo a outra pessoa. - Um usuário comum pode mudar o grupo de um arquivo que possui, mas apenas para um grupo do qual é membro. O comando é
chgrp dev order.csv. chown -Rsegue a árvore de diretórios. Ao encontrar um link simbólico, por padrão muda o proprietário do arquivo que o link aponta. Adicione-hse quiser mudar o proprietário do link em si.
Um padrão comum ao fazer deploy é executar o serviço com um usuário dedicado, enquanto a equipe de operações compartilha um grupo:
sudo chown -R appuser:ops /var/log/shop
sudo chmod -R u=rwX,g=rX,o= /var/log/shop
Com essa configuração, o serviço pode gravar logs, o grupo ops pode ler logs, e outros usuários não têm acesso.
6. Permissões padrão com umask
Ao criar um novo arquivo, o programa normalmente solicita permissões 666 para arquivo e 777 para diretório. Depois, o kernel desativa os bits que estão em umask. O resultado é:
permissão efetiva = permissão solicitada AND (NOT umask)
umask # exibe o valor atual
umask 027 # muda para a shell atual
touch customer.csv && mkdir archive
stat -c '%a %n' customer.csv archive
0022
640 customer.csv
750 archive
Com umask 027: arquivo recebe 666 menos bits 027 resultando em 640, diretório recebe 777 menos 027 resultando em 750. Other perde todas as permissões, grupo perde permissão de escrita.
Nota:
umaské um mascaramento de bits, não uma subtração aritmética. Comumask 033, novo arquivo tem permissão644, não633. A razão é que o bitxnão existe em666para começar, então não há nada para desativar.
Alguns valores comuns:
| umask | Arquivo | Diretório | Caso de uso |
|---|---|---|---|
022 |
644 | 755 | padrão na maioria das distros |
027 |
640 | 750 | servidor, compartilhado apenas no grupo |
077 |
600 | 700 | dados sensíveis |
O comando umask só tem efeito no processo atual e nos processos filho. Para definir permanentemente para um serviço systemd, declare no arquivo unit:
[Service]
User=appuser
UMask=0027
7. Três bits especiais: setuid, setgid, sticky
Além dos 9 bits básicos, Linux tem três bits especiais. Eles são escritos como um quarto dígito no início da forma octal:
- setuid (4): programa executa com as permissões do proprietário. Por exemplo,
/usr/bin/passwdé exibido como-rwsr-xr-x. - setgid (2): quando definido em diretório, novos arquivos criados dentro herdam o grupo do diretório. Esse bit é muito útil para diretórios de trabalho compartilhados.
- sticky (1): quando definido em diretório, apenas o proprietário do arquivo pode deletar esse arquivo.
/tmpusa este bit e é exibido comodrwxrwxrwt.
Por exemplo, criar um diretório compartilhado para o grupo dev:
sudo mkdir /srv/shared && sudo chown :dev /srv/shared
sudo chmod 2770 /srv/shared
stat -c '%a %A' /srv/shared
2770 drwxrws---
Nota: Não defina setuid em scripts ou arquivos que você escreveu a menos que realmente entenda os riscos. Um programa setuid root com falhas é uma forma clássica de escalação de privilégios.
8. Manipule permissões POSIX a partir de Java
Java NIO suporta permissões POSIX via PosixFilePermissions. A classe abaixo escreve arquivo secreto e garante que apenas o proprietário possa ler:
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermissions;
public class SecretWriter {
public Path writeSecret(Path dir, String content) throws IOException {
Path file = dir.resolve("secret.properties");
Files.writeString(file, content);
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("rw-------"));
return file;
}
}
fromString("rw-------") converte a string simbólica para Set<PosixFilePermission>. Depois, setPosixFilePermissions funciona como o comando chmod 600.
Você pode tentar passar PosixFilePermissions.asFileAttribute(...) para Files.createFile. Essa abordagem ainda está sujeita a umask, como a chamada de sistema open(). Para arquivos sensíveis, chame setPosixFilePermissions após criar para garantir o resultado. Uma forma ainda mais segura é criar o arquivo com permissões restritas desde o início, para evitar uma janela de tempo em que outro usuário possa ler o arquivo.
Teste com JUnit 5 e AssertJ:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermissions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
class SecretWriterTest {
@TempDir
Path tempDir;
@Test
void givenSecret_whenWritten_thenOnlyOwnerCanReadAndWrite() throws Exception {
assumeTrue(FileSystems.getDefault().supportedFileAttributeViews().contains("posix"));
Path file = new SecretWriter().writeSecret(tempDir, "db.password=s3cret");
String perms = PosixFilePermissions.toString(Files.getPosixFilePermissions(file));
assertThat(perms).isEqualTo("rw-------");
assertThat(Files.readString(file)).contains("db.password");
}
}
assumeTrue pulará o teste no Windows, onde não há attribute view posix. Sem essa linha, o teste lançará UnsupportedOperationException.
9. Erros comuns
- Usar
chmod 777para “consertar rápido”. Isso abre permissão de escrita para todos os usuários na máquina. Determine qual usuário o processo está executando (ps -o user= -p <pid>), então conceda permissões apenas para esse usuário ou grupo. - Executar
chmod -R 755em árvore de diretórios. Esse comando torna todos os arquivos executáveis. UseXmaiúscula oufindcomo na seção 3.3. - Verificar apenas as permissões do arquivo. Você precisa verificar também os diretórios pai com
namei -l. - Executar
sudoe depois esquecer de mudar o proprietário. Arquivos criados porsudopertencem aroot, então um aplicativo executado como usuário comum não conseguirá escrever. Executechownlogo depois. - Montar volume no Docker. O UID dentro do container pode ser diferente do UID no host. As permissões são verificadas pelo kernel baseado no número UID, não no nome do usuário.
- SSH rejeita chave. SSH ignora
~/.ssh/authorized_keysou chave privada se as permissões forem muito amplas. O diretório~/.sshprecisa de permissão700, chave privada precisa de600.
10. Conclusão
O modelo de permissões do Linux consiste de três grupos (user, group, other) e três permissões (r, w, x). Essas permissões têm significados diferentes entre arquivos e diretórios.
Use chmod para mudar permissões: forma simbólica quando precisa alterar apenas parte, forma numérica quando quer atribuir completamente. Use chown e chgrp para dar arquivos ao usuário e grupo corretos. Use umask para que novos arquivos sejam criados com permissões seguras desde o início.
O princípio consistente é conceder o mínimo de permissões possível. Execute o serviço com um usuário dedicado, compartilhe através de grupos, e deixe other em nível 0 para tudo sensível.