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

umask no Linux: de onde vêm as permissões padrão

Veja a mensagem de erro exata, imprima a umask, crie arquivo e diretório e compare os modos. Entenda por que root e seu usuário podem ter permissões diferentes.

O que a umask faz no Linux

A umask é um número transportado por cada processo no Linux. Ela determina o modo de cada ficheiro e diretório que esse processo cria. Um programa solicita ao kernel um conjunto de permissões no momento da criação. O kernel limpa todos os bits indicados pela máscara e aplica o que resta. Uma umask nunca concede acesso. Ela apenas remove bits das permissões solicitadas pelo programa que cria o objeto.

O valor não é uma propriedade da sua distribuição. Ele depende da conta que está a utilizar e da forma como a shell foi iniciada. Essas duas respostas podem ser diferentes na mesma máquina, ao mesmo tempo, numa imagem padrão. Por isso, o primeiro passo não é consultar um manual. É medir o valor no sistema que está à sua frente.

Imprima o umask na shell atual

umask
umask -S

A primeira forma imprime a máscara em octal. A segunda imprime a mesma máscara como as permissões que ela permite, no formato simbólico aceite por chmod. Mantenha as duas linhas no ecrã. Tudo o que se segue é uma comparação com o que a sua shell acabou de imprimir.

umask é um builtin da shell, não um programa no disco. Confirme isso com type umask. Isto é importante porque um builtin altera o próprio processo da shell. Um programa separado só poderia alterar o seu próprio processo; depois terminaria e levaria a alteração consigo.

Criar um ficheiro e um diretório e ler novamente os modos

cd "$(mktemp -d)"
touch probe.file
mkdir probe.dir
stat -c '%a %A %n' probe.file probe.dir

%a apresenta o modo em octal e %A apresenta o mesmo modo no formato drwxr-xr-x utilizado por ls -l. Compare ambas as linhas com a máscara apresentada há pouco. Todos os bits definidos na máscara estão ausentes dos modos, porque limpar esses bits é a única função de uma máscara. Se a coluna %A ainda não for óbvia, a string de permissões drwxr-xr-x é o primeiro elemento que deve compreender.

O ficheiro e o diretório diferem entre si, e a máscara não é a causa dessa diferença. touch pede ao kernel permissões de leitura e escrita para o proprietário, o grupo e os outros utilizadores. mkdir pede permissões de leitura, escrita e execução para os três. A mesma máscara é subtraída a dois pedidos diferentes. Por isso, um ficheiro criado por touch nunca é executável, independentemente do conteúdo da máscara: o bit de execução nunca foi pedido, e uma máscara não pode voltar a adicionar um bit.

( umask a=rwx; touch open.file; stat -c '%a %A %n' open.file )

Esses parênteses executam os comandos numa subshell, por isso a alteração desaparece quando ela termina. A máscara passa a pedir que nada seja limpo, e stat continua a indicar que o ficheiro não tem o bit de execução. Execute novamente umask depois disso e o valor original regressa. Isto mostra que a definição existe dentro de um processo e é herdada pelos processos filhos, em vez de ser armazenada no disco.

É nos diretórios que um bit de execução limpo se torna evidente.

( umask a=rw; mkdir noexec.dir; cd noexec.dir )

Como utilizador normal, cd falha com bash: cd: noexec.dir: Permission denied, porque a máscara limpou o bit de execução pedido por mkdir, e não é possível entrar num diretório sem o bit de execução. root ignora essa verificação, por isso este comportamento só é visível numa conta normal.

Por que root e o seu utilizador veem um umask diferente

Execute a mesma medição com outra conta, iniciada de outra forma, e leia as duas saídas lado a lado.

umask
sudo -i umask

sudo -i inicia a shell de login de root e executa o builtin dentro dela. Portanto, trata-se de outra conta a chegar através de outro caminho de arranque. Em imagens de servidor padrão do Ubuntu e do Debian, as duas linhas podem apresentar valores diferentes. As duas linhas estão corretas. Cada uma mostra o resultado produzido pelo seu próprio caminho de arranque. O restante deste artigo explica qual parte do sistema o produziu.

Qual ficheiro na sua imagem decidiu o valor

grep -nE '^(UMASK|USERGROUPS_ENAB)' /etc/login.defs
grep -rn pam_umask /etc/pam.d/
grep -rn umask /etc/profile /etc/profile.d/ /etc/bash.bashrc ~/.profile ~/.bashrc 2>/dev/null || echo 'no umask line in the shell startup files'

Se o primeiro grep não mostrar nada, execute-o novamente sem o marcador ^: a linha pode estar comentada, e uma linha comentada serve como documentação, não como configuração. O terceiro grep é o que costuma surpreender. No Debian e no Ubuntu, o ficheiro fornecido pelo sistema /etc/profile aponta principalmente para PAM, em vez de definir uma máscara diretamente. Por isso, o ficheiro que você presumiu estar no controlo muitas vezes não está. O grep termina com um código diferente de zero quando não encontra correspondências, razão pela qual essa linha termina em || echo: numa imagem em que nenhum ficheiro de arranque menciona uma máscara, a mensagem aparece em vez de não aparecer nada, e essa mensagem é o resultado da verificação.

/etc/login.defs anuncia um valor e o PAM aplica outro

A linha UMASK em /etc/login.defs contém o valor citado pela maioria dos guias. Nem o kernel nem a shell leem esse ficheiro. Ele é lido por pam_umask, um módulo PAM (módulo de autenticação conectável) executado quando uma sessão é criada. O pam_umask usa o primeiro valor que encontra: uma entrada umask= no campo GECOS do utilizador, depois um argumento umask= escrito na própria linha pam_umask.so e, por fim, UMASK de /etc/login.defs. As distribuições aplicam patches a este módulo. Por isso, execute man pam_umask na sua própria imagem e leia a ordem apresentada.

É assim que /etc/login.defs pode anunciar um valor enquanto a sua sessão termina com outro, sem apresentar qualquer aviso. Os comandos grep indicam em que caso se encontra. Se a linha pam_umask.so tiver o seu próprio argumento umask=, o valor definido na linha de login.defs foi ignorado.

USERGROUPS_ENAB e a exceção do root

id -un
id -gn

Se os dois apresentarem o mesmo nome, existe um grupo privado do utilizador: a conta foi criada com um grupo próprio, com o mesmo nome da conta. O pam_umask tem um comportamento usergroups, controlado por USERGROUPS_ENAB em /etc/login.defs. Quando está ativo, a conta não é root e o nome do grupo primário coincide com o nome do utilizador, o módulo copia o dígito do proprietário da máscara para o dígito do grupo. A sessão termina então com uma máscara que deixa abertos os bits do grupo em tudo o que essa conta criar. O root é excluído pelo próprio módulo, e essa exclusão é a razão isolada mais comum para duas shells no mesmo servidor apresentarem máscaras diferentes.

A lógica desta regra é que um grupo privado tem exatamente um membro. Assim, permitir escrita ao grupo equivale apenas a permitir escrita ao proprietário. Isto deixa de ser verdade quando alguém adiciona um segundo membro ao grupo. A partir desse momento, esse novo membro pode escrever em todos os ficheiros que a conta criou anteriormente, sem que tenha sido executado qualquer comando nesses ficheiros para permitir isso. Atribua a cada serviço a sua própria conta de utilizador com privilégios mínimos e mantenha esse grupo deliberadamente com um único membro.

Shell de login, shell sem login e shell não interativa

umask
bash -lc 'umask'
bash -c 'umask'

O PAM é executado quando uma sessão é criada: login na consola, sshd, su, sudo -i. Não é executado quando uma shell inicia outra shell. bash -l é uma shell de login, por isso lê /etc/profile e ~/.profile, mas nunca chama pam_umask, porque não foi criada nenhuma sessão. bash -c não lê nenhum desses ficheiros e herda a máscara do processo que a iniciou. Um trabalho do cron, um hook do git e um programa iniciado por um gestor de serviços enquadram-se nesse último caso. A máscara deles é a que estava definida no processo-pai.

É por isso que “defini-a em /etc/profile e o serviço continua a criar ficheiros com o modo errado” é uma situação tão comum. O serviço nunca leu esse ficheiro.

Onde definir a máscara para que seja mantida

Defina a máscara no local onde a carga de trabalho é realmente iniciada, porque cada caminho de arranque lê um ficheiro diferente.

  1. Para contas que iniciam sessão: UMASK em /etc/login.defs, aplicado por pam_umask a todas as sessões da máquina. A definição é global para a máquina e altera todas as contas ao mesmo tempo.
  2. Para uma conta específica: o argumento umask= na linha pam_umask.so também é global para a máquina. Por isso, um valor por utilizador deve ficar no campo GECOS desse utilizador, ou em ~/.profile para shells de início de sessão e em ~/.bashrc para shells interativas.
  3. Para um daemon gerido pelo systemd: UMask= na secção [Service] da unidade. Uma unidade é iniciada pelo gestor de serviços, por isso /etc/profile nunca é lido e pam_umask nunca é executado. O ficheiro da unidade é o único destes ficheiros que chega ao daemon.
  4. Para um script iniciado pelo cron ou por um hook: um umask explícito na primeira linha, antes de o script criar qualquer coisa.
[Service]
UMask=<the octal mask you chose>

Depois, verifique a partir de um arranque novo desse mesmo caminho e nunca a partir da shell onde editou o ficheiro. A shell atual já tem a sua máscara definida, e editar um ficheiro de configuração não altera retroativamente um processo em execução.

bash -lc 'umask'
sudo -i umask

Por que executar chmod depois não corrige o problema

chmod corrige ficheiros que já existem. A máscara define o modo dos ficheiros que ainda não existem. Execute chmod -R num diretório e o ficheiro seguinte que o serviço criar voltará a ter o modo antigo, porque esse modo veio do processo que criou o ficheiro e nada no diretório o altera.

Também existe uma janela de exposição. Entre o momento em que um ficheiro é criado e o momento em que chmod é executado, o ficheiro permanece no disco com o modo mais permissivo. Qualquer processo que consiga ler o diretório pode abri-lo. No caso de uma chave privada ou de um arquivo de backup, essa janela cria exatamente o risco que estava a tentar eliminar.

Defina o modo no momento da criação. install -m u=rw,go= newfile /etc/app/newfile escreve o destino com um modo explícito, e mkdir -m faz o mesmo para um diretório. Ambos usam o modo indicado e ignoram a máscara. ssh-keygen define o modo da chave privada que escreve. Por isso, esse ficheiro costuma estar correto numa máquina em que todos os outros não estão.

O caso mais comum é o SSH. Um ~/.ssh criado com um mkdir simples, ou um authorized_keys ao qual se acrescenta conteúdo com cat >>, recebe a máscara da sua shell. Com StrictModes ativo, o sshd recusa ler um ficheiro de chave a partir de um diretório com permissão de escrita para o grupo. O cliente recebe Permission denied (publickey), enquanto o /var/log/auth.log do servidor regista a causa real:

Authentication refused: bad ownership or modes for directory /home/deploy/.ssh

Essa verificação é intencional, e proteger o SSH num VPS depende de ela funcionar. Meça a máscara num servidor novo antes de criar as contas que a vão utilizar, juntamente com os primeiros dez minutos num VPS novo, e o modo de cada ficheiro criado por essas contas ficará definido antecipadamente.

Cópias e arquivos ignoram a máscara

cp -p e rsync -a restauram o modo registado no ficheiro de origem, por isso a máscara não influencia o resultado. tar faz o mesmo quando extrai como root ou como utilizador normal com -p. Um ficheiro restaurado a partir de uma cópia de segurança mantém o modo que tinha quando a cópia foi criada. Confirme isso antes de concluir que uma máscara correta está a ser ignorada: para dados restaurados, ela nunca foi consultada.

FAQ

Por que o meu cron job cria ficheiros com um modo diferente da minha sessão ssh?

Um cron job não é uma sessão de login, por isso o pam_umask nunca é executado e não lê /etc/profile nem ~/.profile. Ele herda a máscara do processo que o iniciou. Coloque um umask explícito na primeira linha do script, antes de este criar qualquer coisa, e mostre a máscara uma vez a partir do próprio job. Assim, vê o que esse job tem efetivamente, em vez da máscara da sua própria shell.

Por que /etc/login.defs indica um valor e a minha shell mostra outro?

UMASK em /etc/login.defs é apenas o último fallback do pam_umask. O módulo dá preferência a uma entrada umask= no campo GECOS do utilizador e, depois, a um argumento umask= na linha pam_umask.so em /etc/pam.d/. O comportamento usergroups, ativado por USERGROUPS_ENAB, altera depois o dígito do grupo para qualquer conta que não seja root cujo grupo primário tenha o mesmo nome da conta. Execute grep -rn pam_umask /etc/pam.d/ e id -un; id -gn para ver qual destas opções se aplica à sua conta.

Uma umask pode tornar um ficheiro executável?

Não. Uma máscara só pode limpar bits das permissões solicitadas pelo programa que cria o ficheiro. touch nunca solicita o bit de execução, por isso nenhuma máscara produz um ficheiro executável. Confirme isso num diretório descartável com ( umask a=rwx; touch f; stat -c '%a %A' f ). Para obter um bit de execução, precisa de chmod ou de um programa como install -m que o solicite no momento da criação.

Onde defino a umask de um serviço systemd?

Na unidade, com UMask= na secção [Service]. Um serviço é iniciado pelo gestor de serviços, e não por um login. Por isso, os ficheiros de arranque da shell nunca são lidos e o pam_umask nunca é executado. Depois de systemctl daemon-reload e de reiniciar a unidade, confirme a partir do exterior: deixe o serviço criar um ficheiro e leia o resultado com stat -c '%a %n'.

Uma máscara predefinida que permite escrita pelo grupo é segura?

É segura enquanto o grupo tiver exatamente um membro, que é a situação assumida pelo esquema de grupos privados de utilizadores. Se adicionar uma segunda conta a esse grupo, todos os ficheiros criados pela primeira conta passam imediatamente a poder ser alterados pelo novo membro, sem executar qualquer comando nesses ficheiros. Execute id -un e id -gn: se mostrarem o mesmo nome, está a utilizar um grupo privado. Se partilhar um grupo entre contas, defina uma máscara que limpe o bit de escrita do grupo. Depois, crie um ficheiro e leia stat -c '%a %n' para confirmar que a alteração foi aplicada.

#umask#permissions#pam#login-defs#linux