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 requer x para 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 root pode 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 -R segue 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 -h se 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. Com umask 033, novo arquivo tem permissão 644, não 633. A razão é que o bit x não existe em 666 para 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. /tmp usa este bit e é exibido como drwxrwxrwt.

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 777 para “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 755 em árvore de diretórios. Esse comando torna todos os arquivos executáveis. Use X maiúscula ou find como 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 sudo e depois esquecer de mudar o proprietário. Arquivos criados por sudo pertencem a root, então um aplicativo executado como usuário comum não conseguirá escrever. Execute chown logo 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_keys ou chave privada se as permissões forem muito amplas. O diretório ~/.ssh precisa de permissão 700, chave privada precisa de 600.

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.

linuxchmodchownumasksegurança