Como limitar o uso de recursos dos usuários em sistemas UNIX e Linux com o comando ulimit

A limitação de recursos do sistema é a prática de regular até onde usuários, aplicativos e processos podem ir, com o objetivo de manter um equilíbrio entre a completa experiência de usuário e a segurança do sistema.
É bom frisar que, ainda que ajustados em função dos usuários, internamente, sua aplicação se refere aos processos.
Esta abordagem permite que usuários com limitações de recursos, possam rodar softwares que dependam de uma grande quantidade de processos abertos — ou seja, mesmo que um usuário esteja limitado a rodar no máximo 10 processos, ele pode fazer uso de aplicações gráficas (GNOME, KDE, Unity etc) que disparam, potencialmente, outras várias dezenas de processos.
Nos sistemas operacionais UNIX e GNU/Linux o comando ulimit é o que controla os limites dos recursos de sistema — tais como tamanho dos dados processos, quantidade de memória virtual que podem usar, quantidade máxima de arquivos que podem ser abertos etc.

Há diferenças entre um sistema e outro. O Solaris dá acesso ilimitado aos recursos ao root. No AIX, da IBM, há algumas limitações impostas ao superusuário.

Ao configurar os limites de recursos para um processo é importante saber que os limites que se aplicam são aqueles que afetam os processos pai e não os limites para o usuário que o está executando.
Por exemplo, o IBM Directory server roda sob uma conta de usuário ldap, criada no momento da instalação. Embora este serviço seja normalmente iniciado quando logado como root.
Se iniciado sob privilégios administrativos (root), quaisquer limites para o usuário ldap não afetam os processos pertencentes ao IBM Directory server. Para isto, o serviço precisa ser iniciado a partir da conta do usuário ldap.

Como obter informações sobre os limites de recursos de cada usuário

O comando ulimit pode configurar os recursos disponíveis “por usuário”, de maneira flexível (soft) ou rígida (hard).
Para ver todos os ajustes rígidos de recursos relativos ao usuário atual, use-o assim:

ulimit -Ha
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 61250
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 4096
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) unlimited
cpu time               (seconds, -t) unlimited
max user processes              (-u) 61250
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Para ver os ajustes flexíveis de recursos relativos ao usuário atual:

ulimit -Sa

As letras, entre parênteses, indicam a opção que pode ser dada ao ulimit para obter ou alterar aquela informação específica.

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 61250
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 61250
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Para ajudar a memorizar:

  • -H, de hard, se refere às opções rígidas.
  • -S, de soft, se refere às opções flexíveis.

Para exemplificar, se você quiser saber apenas qual a quantidade máxima de arquivos que podem ficar abertos, use ulimit -n.
O comando ulimit -a é equivalente a ulimit -Sa.
Você pode combinar parâmetros, para obter informações customizadas:

ulimit -v -x -u
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
max user processes              (-u) 61250

No Linux, os ajustes rígidos de recursos são feitos pelo root para cada usuário, através do comando chuser.
Já os ajustes flexíveis, podem ser feitos pelo usuário comum livremente. Ou seja, desde que você não ultrapasse os valores estabelecidos pelos ajustes rígidos, pode alterá-los de acordo com suas necessidades.

Como alterar os limites flexíveis do usuário atual

Há momentos em que se deseja reduzir limites de recursos para a própria sessão — quando se deseja testar algum aplicativo, que se tenha dúvida quanto à qualidade de seu código.
Limitar fortemente a quantidade máxima de processos abertos simultaneamente por usuário (max user processes), pode prevenir que código malicioso de uma fork bomb, por exemplo, replique processos indefinidamente até derrubar o seu sistema.
Para aumentar a quantidade máxima de arquivos abertos open files, use o comando seguido da opção ‘-n’:

ulimit -n 2048

Seja parcimonioso(a) com a alteração dos limites flexíveis “para menos”. Valores muito baixos de alguns itens podem tornar o sistema impossível de operar.

Você vai encontrar valores diferentes de um UNIX para outro ou entre as várias distros GNU/Linux. Só para citar um exemplo desta variação, o Debian 8.1 32 bit (quando instalado via netinstall e sem ambiente gráfico), por padrão, usa o valor 841 no parâmetro max user processes. A versão 64 bit, usa o valor 7976.
Isto é normal.

Note, ainda que os valores alterados só valem para a sessão atual. Ao reiniciar o sistema, eles retornam à configuração anterior. Se você errar e ficar com um sistema inutilizável, basta reiniciar ou abrir um outro terminal.

Como configurar o arquivo /etc/security/limits

Para alterar e manter os valores, mesmo após reiniciar o sistema, faça as alterações dentro do arquivo /etc/security/limits.conf (nas distros derivadas do Debian).
O arquivo limits.conf deve ser configurado em 4 colunas:

Parâmetro Descrição
domain Esta coluna pode conter um nome de usuário (justincase, hkeitel) ou de um grupo (p/ex.: @grupo).
type Pode ser tanto soft, para flexível como hard, para rígido.
item Onde se incluem os parâmetros do sistema a configurar. Veja abaixo.
value Os valores podem ser dados em blocos (de 512 ou 1024 bytes, a depender do seu sistema operacional, do seu sistema de arquivos etc.

Os parâmetros de configuração, presentes no Ubuntu 14.04 e Debian 8.1, no arquivo /etc/security/limits.conf, são os seguintes:

  • core – limita o tamanho do arquivo de núcleo ou core file size ou core dump file size. Este arquivo é constituído por uma imagem da memória de um processo, quando ele é terminado abruptamente. Esta informação é geralmente usada por aplicativos depuradores (KB).
  • max data size. Limite do tamanho dos segmentos de dados dos processos (KB).
  • maximum filesize ou maior tamanho de arquivo permitido a um processo abrir (KB).
  • max locked-in-memory address space. O memlock é o tamanho máximo de memória física que pode ser retida por um processo.
    A função deste recurso é certificar que uma certa quantidade de informações esteja sempre armazenada na RAM e nunca movida para o swap — o que mantém a velocidade de acesso a esta informação (KB).
  • max number of open files ou maior quantidade de arquivos que podem ficar abertos simultaneamente (unidades).
  • rss – max resident set size. É a quantidade máxima de dados pertencentes a um processo, que pode ficar residente em memória RAM.
    Um dos motivos para limitar este item é impedir que uma única aplicação do seu sistema devore toda memória principal (RAM), o que forçaria todas as outras aplicações a usar o swap, que é extremamente lento. (KB)

Em computação, o RSS ou resident set size é a porção de memória ocupada por um processo, mantida na memória RAM.
O resto da memória ocupada vai estar no swap ou no sistema de arquivos — ou porque parte foi paginada ou por que partes do arquivo executável, ainda não foram carregadas.

  • stackmax stack size limita o tamanho do process stack ou pilha de processos em bytes. Ao atingir este limite, um sinal SIGSEV é gerado, obrigando o próximo processo a empregar uma nova pilha (KB).
  • cpumax CPU time representa o tempo dedicado pela CPU para processar instruções de um programa ou do sistema operacional (MIN).
  • nprocmax number of processes, delimita a quantidade máxima de processos para a sessão atual.
  • asaddress space limit, estabelece um teto para o tamanho máximo de um processo em memória virtual (KB).
  • maxloginsmax number of logins for this user ou maior número de autenticações no sistema permitido ao usuário atual.
  • maxsysloginsmax number of logins on the system ou maior número de autenticações no sistema permitido.
  • prioritythe priority to run user process with, designa a prioridade para rodar processos do usuário.
  • locksmax number of file locks the user can hold
  • sigpendingmax number of pending signals, especifica o limite de sinais que podem se enfileirar para atingir o ID do usuário, vindas de um determinado processo.
  • msgqueuemax memory used by POSIX message queues Estabelece a quantidade máxima (em bytes) de memória usada por filas de mensagens POSIX.
  • nicemax nice priority allowed to raise to values: [-20, 19]. Especifica um teto para aumentar o valor do nice, com o uso dos comandos setpriority e nice.
  • rtpriomax realtime priority, define um teto para a prioridade de tempo real para a sessão atual.
  • chrootchange root to directory, no Debian, permite informar um novo diretório para o superusuário.

Para que as alterações feitas ao arquivo /etc/security/limits.conf tenham efeito, é necessário reiniciar o sistema.
Para alterar individualmente os limites de usuários, use o comando chuser. Neste caso, basta fechar a sessão e se autenticar de novo para estar sob os efeitos dos novos ajustes.
Para finalizar o assunto, segue um exemplo de uso do comando para alterar o resident set size do usuário salsicha:

chuser rss=-1 salsicha

Referências:
Página do Manual do Linux: http://www.man-page.net/2/setrlimit.
The core dump file: http://man7.org/linux/man-pages/man5/core.5.html.