Pages

Wednesday, 12 August 2020

Everything you need to know about "ulimit" on Linux

1 Key concepts

  • process resource limits are implemented and enforced in the kernel.
    • limits are part of a process' kernel structure. 
    • we can check their values in /proc/PID/limits.

  • "ulimit" is a built-in in bash, it works by calling system call "getrlimit()" and "setrlimit()".
    • different shell may have different commands for set/get resources limits.

  • A process's resources limits inherit from its parent process. 
    • a shell's child processes all have the same limits as the shell by default.

  • soft limits and hard limits
    • hard limits are the max value soft limits can be set to.
    • soft limits are what the kernel checks and enforces.

  • Most limits are per-process attributes, while two are per-user. For per-user limits, they affect only the calling process. Other processes belonging to this user are not affected unless they also set or inherit these limits.
    • RLIMT_SIGPENDING
    • RLIMIT_NPROC, this limit takes into account both process and threads.

2 Where are limits values from?

2.1 The Linux kernel sets limits for PID 1

The Linux kernel is responsible to create the first userspace process and set the limits of its resource.
Some limits values may be hardcoded, while others may be calculated based on the hardware like memory size.

The PID 1 process can run any program, but usually, it executes /sbin/init which in most Linux distributions is a link to /lib/systemd/systemd.

$ cat /proc/1/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        unlimited            unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             62571                62571                processes
Max open files            1048576              1048576              files
Max locked memory         16777216             16777216             bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       62571                62571                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

As all other userspace processes are created by PID 1 directly or indirectly, they inherit all those values as their default.

2.2 PAM sets the login process's limits

For ordinary Linux users, they login the system before do anyting else. During the login process, PAM would set the process's limits by pam_limits.so.

$ cat /etc/pam.d/system-auth | grep limits
session     required      pam_limits.so

pam_limits.so reads its configration from
  • /etc/security/limits.conf
  • /etc/security/limits.d/*.conf
PAM may hardcod some limits which are not in the configration files.

After successful login, the login process executes the users' defualt shell, so the shell process inherits all these limits.

To see a shell's limits, use its built-in command. For bash, it's 'ulimit'.

# print all hard limits
$ 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) 62571
max locked memory       (kbytes, -l) 16384
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) 62571
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

# print all soft limits
$ ulimit -Sa
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 62571
max locked memory       (kbytes, -l) 16384
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) 62571
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

We can see limits in /proc/$$/limits too.
$ cat /proc/$$/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        unlimited            unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             62571                62571                processes
Max open files            1024                 4096                 files
Max locked memory         16777216             16777216             bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       62571                62571                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

2.3 The process sets its own limits

A process can set its own limits by call 'setrlimits()' system call at any time. But here are some restrictions.
  • Only privileged users can set Hard limits to a higher value.
  • Any user can lower the hard limits.
  • Any user can change soft limits from 0 to the value of their hard one.
  • Hard limits cannot be lower than soft limits. (or, soft limits cannot be higher than hard limits)
  • Some hard limits may have a ceiling posed by the kernel. e.g. Hard limit of nofiles can not be higher than /proc/sys/fs/nr_open.

3 Examples

$ ulimit -Hn
4096
$ ulimit -Sn
1024

# Hard limit can be set higher only by root
$ ulimit -Hn 4097
-bash: ulimit: open files: cannot modify limit: Operation not permitted

# Hard limit can not be lower than soft limit
$ ulimit -Hn 1023
-bash: ulimit: open files: cannot modify limit: Invalid argument

# Soft limit can not be higher than hard limit
$ ulimit -Sn 4097
-bash: ulimit: open files: cannot modify limit: Invalid argument

# check what limits were set by PAM
$ diff /proc/1/limits /proc/$$/limits
9c9
< Max open files            1048576              1048576              files
---
> Max open files            1024                 4096                 files



No comments:

Post a Comment