by inetknght | 2025-07-26 06:28:21+00:00
> I have a bunch of questions.

If I were reading the documentation for higher level language APIs, I'd also read the documentation for setting up/using the types that are associated.

With well-written documentation, there's usually related information and/or see-also. Indeed, this has `SEE ALSO` for `getrlimit(2)`, which is equivalent to `man 2 getrlimit` [0].

From there, the things are a bit more descriptive.

RLIMIT_AS This is the maximum size of the process's virtual memory (address space). The limit is specified in bytes, and is rounded down to the system page size. This limit affects calls to brk(2), mmap(2), and mremap(2), which fail with the error ENOMEM upon exceeding this limit. In addition, automatic stack expansion fails (and generates a SIGSEGV that kills the process if no alternate stack has been made available via sigaltstack(2)). Since the value is a long, on machines with a 32-bit long either this limit is at most 2 GiB, or this resource is unlimited. RLIMIT_DATA This is the maximum size of the process's data segment (initialized data, uninitialized data, and heap). The limit is specified in bytes, and is rounded down to the system page size. This limit affects calls to brk(2), sbrk(2), and (since Linux 4.7) mmap(2), which fail with the error ENOMEM upon encountering the soft limit of this resource.

The documentation also links to the affected system calls (`brk` [1], `sbrk` [1], `mmap` [2], `mremap` [3], and `signalstack`). Note that all of this is in section 2 and 3 of the manual for system interface calls and libraries that interact with the system. You might find some installations of linux complaining about missing documentation (eg minimalized containers and/or release distros -- documentation takes up a decent chunk of disk space and isn't generally needed outside of a developer's workstation), in which case the most likely reason is that the documentation package should be re/installed via your package manager.

So,

> What is `data` ? "maximum data size (KB)".

"data" is the process's data segment [1]. Perhaps this might be clearer, but it is fairly well defined if you then read the documentation for `brk` [1]:

brk() and sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.

This rabbit hole goes into describing system internals for process memory layouts [5] and it can expand pretty widely into understanding how's and why's. This level of system knowledge is literally understanding your operating system and... it's IMO well documented if you just keep searching terms that you're unfamiliar with; instead of `man` you might try `apropos` (and see `man apropos`). You'll end up exploring a huge chunk of the C-language system API, and a fair bit of glibc too.

Then,

> Is `address space limit (KB)` virtual or physical ?

First sentence of the C-language documentation for RLIMIT_AS:

RLIMIT_AS This is the maximum size of the process's virtual memory (address space).

> What is maximum filesize in a context of a process ?!

System API `open()`, `opendir()`, `openat()`, [6] etc with _system file descriptors_? Well assuming your _file descriptor_ points to a file, then it's whatever the filesystem supports. But your system generally can support 32-bit-or-64-bit (depending on macros usually defined during kernel compilation) with `lseek` [7] and `off_t` [8], or you can force 64-bit bit support with `lseek64` [9] and `off64_t` [8], and fail to compile your app if your kernel wasn't compiled with 64-bit support.

It's more complicated if you use a different API (such as C's FILE* functions [10] or etc).

> what happens if a file is bigger?

I'm not sure -- I've never had to worry about it because I use the 64-bit APIs. You could try mounting a filesystem supporting 64-bit files, then write a file beyond 32-bits, then boot into a 32-bit OS and try mounting it and reading the file. You'll probably get an error code that you can then look up in the documentation. If it's not clear what it is, then the kernel source code is fairly easy to navigate to find where the error could come from and what it might mean, and I've done it for mremap failures.

> Maybe it can't write bigger file than that, maybe it can't execute file bigger than that.

That heavily depends on system architecture and your operating system support. But unless I'm mistaken with Linux on x86_64, just about any user-land virtual address page can be marked executable; but it's different in kernel-land with reserved/register/io address space.

And, as I understand it, the kernel memory-maps your executable from your filesystem. So, generally, user-land code can map to "anywhere" (this is good for ASLR safety) and could be executed even with minimal physical address space available. But in practice, your executable is mapped to within a certain region of the virtual address space, which leaves the other region of your address space available for allocations (this is how `brk` works). What's generally far more important is how much memory you might allocate during your program's lifecycle, and whether or not you end up fragmenting that memory.

In any case, the documentation for `/etc/security/limits.conf` (linked earlier) states:

If a hard limit or soft limit of a resource is set to a valid value, but outside of the supported range of the local system, the system may reject the new limit or unexpected behavior may occur. If the control value required is used, the module will reject the login if a limit could not be set.

If you set your limits so low that you can't start processes because you run out of address space while trying to load them, then that might be classified as "unexpected behavior" if you didn't expect that to happen and so is... well documented. I don't see where it says anything about "valid value" or "supported range" for specific limits, but for those I would just poke around the kernel source code [11] where those C macros are used and look for limits around them. `grep -nR` [12] is what I'd use for that.

That's enough rabbit hole for me.

[0]: https://www.man7.org/linux/man-pages/man2/getrlimit.2.html

[1]: https://www.man7.org/linux/man-pages/man2/brk.2.html

[2]: https://www.man7.org/linux/man-pages/man2/mmap.2.html

[3]: https://www.man7.org/linux/man-pages/man2/mremap.2.html

[4]: https://www.man7.org/linux/man-pages/man2/sigaltstack.2.html

[5]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format

[6]: https://man7.org/linux/man-pages/man2/open.2.html

[7]: https://man7.org/linux/man-pages/man2/lseek.2.html

[8]: https://man7.org/linux/man-pages/man3/off64_t.3type.html

[9]: https://man7.org/linux/man-pages/man3/lseek64.3.html

[10]: https://man7.org/linux/man-pages/man3/file.3type.html

[11]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...

[12]: https://man7.org/linux/man-pages/man1/grep.1.html