From: Karel Zak Date: Mon, 16 Feb 2026 13:43:00 +0000 (+0100) Subject: prlimit: raise a nicer error message when modifying NOFILE X-Git-Tag: v2.43-devel~77^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6fa828cda7c99a3517de73ff3bb891454f653c89;p=thirdparty%2Futil-linux.git prlimit: raise a nicer error message when modifying NOFILE 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 Signed-off-by: Karel Zak --- diff --git a/include/pathnames.h b/include/pathnames.h index c6a7c57d8..718c71b90 100644 --- a/include/pathnames.h +++ b/include/pathnames.h @@ -202,6 +202,7 @@ /* 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 */ diff --git a/sys-utils/prlimit.c b/sys-utils/prlimit.c index d23e0a599..72390bb3d 100644 --- a/sys-utils/prlimit.c +++ b/sys-utils/prlimit.c @@ -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;