]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
prlimit: raise a nicer error message when modifying NOFILE
authorKarel Zak <kzak@redhat.com>
Mon, 16 Feb 2026 13:43:00 +0000 (14:43 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 16 Feb 2026 13:43:00 +0000 (14:43 +0100)
When attempting to set RLIMIT_NOFILE to a value exceeding the kernel's
fs.nr_open limit, prlimit(2) returns EPERM. This can mislead users into
thinking they need elevated permissions, even when running as root.

Add a check to detect when the requested NOFILE limit exceeds
fs.nr_open and provide a clear error message indicating the actual
constraint. The check is optional: if /proc/sys/fs/nr_open cannot be
read (e.g., /proc not mounted), the validation is silently skipped to
avoid introducing a hard dependency on /proc.

The nr_open value is cached and read only once per prlimit invocation
for efficiency when setting multiple limits.

Addresses: https://github.com/util-linux/util-linux/issues/4017
Co-authored-by: krajpuro <krajpuro@akamai.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
include/pathnames.h
sys-utils/prlimit.c

index c6a7c57d822233b72e04c1445637a9607b0d64b3..718c71b90d2b3e642c52d2f409b5abc99989ba9d 100644 (file)
 /* sysctl fs paths */
 #define _PATH_PROC_SYS_FS      "/proc/sys/fs"
 #define _PATH_PROC_PIPE_MAX_SIZE       _PATH_PROC_SYS_FS "/pipe-max-size"
+#define _PATH_PROC_NR_OPEN     _PATH_PROC_SYS_FS "/nr_open"
 #define _PATH_PROC_BINFMT_MISC _PATH_PROC_SYS_FS "/binfmt_misc"
 
 /* Posix ipc paths */
index d23e0a599148aef68f2c095b657f862256e3ab89..72390bb3d5561234c068fa0c70ed086049209aa9 100644 (file)
@@ -30,6 +30,8 @@
 #include "strutils.h"
 #include "list.h"
 #include "closestream.h"
+#include "path.h"
+#include "pathnames.h"
 
 #ifndef RLIMIT_RTTIME
 # define RLIMIT_RTTIME 15
@@ -347,6 +349,7 @@ static void get_unknown_hardsoft(struct prlimit *lim)
 static void do_prlimit(struct list_head *lims)
 {
        struct list_head *p, *pnext;
+       unsigned int nr_open = 0;
 
        list_for_each_safe(p, pnext, lims) {
                struct rlimit *new = NULL, *old = NULL;
@@ -361,6 +364,19 @@ static void do_prlimit(struct list_head *lims)
                                 lim->rlim.rlim_max != RLIM_INFINITY))
                                errx(EXIT_FAILURE, _("the soft limit %s cannot exceed the hard limit"),
                                                lim->desc->name);
+
+                       if (lim->desc->resource == RLIMIT_NOFILE) {
+                               if (nr_open == 0)
+                                       ul_path_read_u32(NULL, &nr_open, _PATH_PROC_NR_OPEN);
+
+                               if (nr_open > 0 &&
+                                   (lim->rlim.rlim_cur > nr_open ||
+                                    lim->rlim.rlim_max > nr_open))
+                                       errx(EXIT_FAILURE,
+                                            _("the %s resource limit is not allowed to exceed %u (fs.nr_open)"),
+                                            lim->desc->name, nr_open);
+                       }
+
                        new = &lim->rlim;
                } else
                        old = &lim->rlim;