This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit cc48013050c2fdd0c76503505b18bb4590511fb7 Author: Marco Casaroli <[email protected]> AuthorDate: Sun Oct 18 20:06:04 2026 +0200 sched/group: Keep resource limits per process. setrlimit() kept nothing and returned OK, and getrlimit() returned fixed values. So a limit that a program or a shell set had no effect. Keep RLIMIT_STACK and RLIMIT_NOFILE in the task group, and make getrlimit() and setrlimit() system calls that read and write them, as the limits must not be in memory that the process can change. A new process gets the limits of its parent. The defaults are no stack limit and OPEN_MAX open files. setrlimit() fails with EINVAL for a resource that NuttX does not enforce, or for a soft limit above the hard limit, and with EPERM when an unprivileged process raises a hard limit or when the limit of open files is above OPEN_MAX. getrlimit() reports the resources that NuttX does not limit as RLIM_INFINITY. sysconf(_SC_OPEN_MAX) returns the RLIMIT_NOFILE soft limit, as POSIX says. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- include/nuttx/sched.h | 6 ++ include/sys/syscall_lookup.h | 2 + libs/libc/unistd/CMakeLists.txt | 2 - libs/libc/unistd/Make.defs | 3 +- libs/libc/unistd/lib_getrlimit.c | 93 ---------------- libs/libc/unistd/lib_setrlimit.c | 55 ---------- libs/libc/unistd/lib_sysconf.c | 14 ++- sched/group/CMakeLists.txt | 1 + sched/group/Make.defs | 2 +- sched/group/group.h | 2 + sched/group/group_create.c | 4 + sched/group/group_rlimit.c | 221 +++++++++++++++++++++++++++++++++++++++ syscall/syscall.csv | 2 + 13 files changed, 253 insertions(+), 154 deletions(-) diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index cf08f12e2a7..e77cd69ef84 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -30,6 +30,7 @@ #include <nuttx/config.h> #include <sys/types.h> +#include <sys/resource.h> #include <stdbool.h> #include <stdint.h> #include <sched.h> @@ -462,6 +463,11 @@ struct task_group_s uint8_t tg_flags; /* See GROUP_FLAG_* definitions */ uint8_t tg_caps; /* See PR_CAP_* definitions */ + /* Resource limits (getrlimit() and setrlimit()) **************************/ + + struct rlimit tg_rlimit_stack; /* RLIMIT_STACK */ + struct rlimit tg_rlimit_nofile; /* RLIMIT_NOFILE */ + /* User identity (POSIX real, effective, and saved-set IDs) ***************/ #ifdef CONFIG_SCHED_USER_IDENTITY diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index 5bbd5b017b8..d5153628194 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -56,6 +56,8 @@ SYSCALL_LOOKUP(nxsched_get_stackinfo, 2) #endif SYSCALL_LOOKUP(sysinfo, 1) +SYSCALL_LOOKUP(getrlimit, 2) +SYSCALL_LOOKUP(setrlimit, 2) SYSCALL_LOOKUP(gethostname, 2) SYSCALL_LOOKUP(sethostname, 2) diff --git a/libs/libc/unistd/CMakeLists.txt b/libs/libc/unistd/CMakeLists.txt index 06ed405a890..f2bce74698f 100644 --- a/libs/libc/unistd/CMakeLists.txt +++ b/libs/libc/unistd/CMakeLists.txt @@ -49,8 +49,6 @@ set(SRCS lib_getrusage.c lib_utime.c lib_utimes.c - lib_setrlimit.c - lib_getrlimit.c lib_setpriority.c lib_getpriority.c lib_futimes.c diff --git a/libs/libc/unistd/Make.defs b/libs/libc/unistd/Make.defs index 20a4e048786..2d9110ad4b0 100644 --- a/libs/libc/unistd/Make.defs +++ b/libs/libc/unistd/Make.defs @@ -29,8 +29,7 @@ CSRCS += lib_getopt_long.c lib_getopt_longonly.c lib_getoptvars.c lib_getoptargp CSRCS += lib_getopterrp.c lib_getoptindp.c lib_getoptoptp.c lib_times.c CSRCS += lib_alarm.c lib_fstatvfs.c lib_statvfs.c lib_sleep.c lib_nice.c CSRCS += lib_getrusage.c lib_utime.c lib_utimes.c lib_getdtablesize.c -CSRCS += lib_getpagesize.c -CSRCS += lib_setrlimit.c lib_getrlimit.c lib_setpriority.c lib_getpriority.c +CSRCS += lib_getpagesize.c lib_setpriority.c lib_getpriority.c CSRCS += lib_futimes.c lib_lutimes.c lib_gethostname.c lib_sethostname.c CSRCS += lib_fchownat.c lib_linkat.c lib_readlinkat.c lib_symlinkat.c CSRCS += lib_unlinkat.c lib_usleep.c lib_getpgrp.c lib_getpgid.c diff --git a/libs/libc/unistd/lib_getrlimit.c b/libs/libc/unistd/lib_getrlimit.c deleted file mode 100644 index 1e4850aafc5..00000000000 --- a/libs/libc/unistd/lib_getrlimit.c +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** - * libs/libc/unistd/lib_getrlimit.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <string.h> -#include <errno.h> - -#include <sys/resource.h> -#include <pthread.h> - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: getrlimit - * - * Description: - * The getrlimit() and setrlimit() system calls get and - * set resource limits respectively. - * - ****************************************************************************/ - -int getrlimit(int resource, FAR struct rlimit *rlp) -{ - UNUSED(resource); - - if (rlp == NULL) - { - set_errno(EINVAL); - return ERROR; - } - - /* This is a dummy realization to make the compiler happy */ - - memset(rlp, 0, sizeof(*rlp)); - - switch (resource) - { - case RLIMIT_NOFILE: - { - rlp->rlim_cur = OPEN_MAX; - rlp->rlim_max = OPEN_MAX; - } - break; - case RLIMIT_STACK: - { - rlp->rlim_cur = PTHREAD_STACK_DEFAULT; - rlp->rlim_max = RLIM_INFINITY; - } - break; - case RLIMIT_RTPRIO: - { - rlp->rlim_cur = SCHED_PRIORITY_DEFAULT; - rlp->rlim_max = SCHED_PRIORITY_MAX; - } - break; - case RLIMIT_RTTIME: - { - rlp->rlim_cur = UINT32_MAX; - rlp->rlim_max = UINT32_MAX; - } - break; - default: - break; - } - - return OK; -} diff --git a/libs/libc/unistd/lib_setrlimit.c b/libs/libc/unistd/lib_setrlimit.c deleted file mode 100644 index 6f21c9110da..00000000000 --- a/libs/libc/unistd/lib_setrlimit.c +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** - * libs/libc/unistd/lib_setrlimit.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <string.h> -#include <errno.h> - -#include <sys/resource.h> - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: setrlimit - * - * Description: - * The getrlimit() and setrlimit() system calls get and - * set resource limits respectively. - * - ****************************************************************************/ - -int setrlimit(int resource, FAR const struct rlimit *rlp) -{ - /* This is a dummy realization to make the compiler happy */ - - UNUSED(resource); - UNUSED(rlp); - - return OK; -} diff --git a/libs/libc/unistd/lib_sysconf.c b/libs/libc/unistd/lib_sysconf.c index f05e171cb7b..840279d5ad6 100644 --- a/libs/libc/unistd/lib_sysconf.c +++ b/libs/libc/unistd/lib_sysconf.c @@ -28,6 +28,7 @@ #include <nuttx/atexit.h> +#include <sys/resource.h> #include <unistd.h> #include <limits.h> #include <sched.h> @@ -245,7 +246,18 @@ long sysconf(int name) return ARG_MAX; case _SC_OPEN_MAX: - return OPEN_MAX; + { + struct rlimit rlim; + + /* The soft limit of the process, which setrlimit() can change */ + + if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) + { + return rlim.rlim_cur; + } + + return OPEN_MAX; + } case _SC_NGROUPS_MAX: return NGROUPS_MAX; diff --git a/sched/group/CMakeLists.txt b/sched/group/CMakeLists.txt index 5353552c849..58919779e4e 100644 --- a/sched/group/CMakeLists.txt +++ b/sched/group/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRCS group_create.c + group_rlimit.c group_join.c group_leave.c group_setupidlefiles.c diff --git a/sched/group/Make.defs b/sched/group/Make.defs index b2605e53fe5..e060dcc8c66 100644 --- a/sched/group/Make.defs +++ b/sched/group/Make.defs @@ -20,7 +20,7 @@ # ############################################################################ -CSRCS += group_create.c group_join.c group_leave.c +CSRCS += group_create.c group_join.c group_leave.c group_rlimit.c CSRCS += group_setupidlefiles.c group_setuptaskfiles.c CSRCS += group_foreachchild.c group_killchildren.c diff --git a/sched/group/group.h b/sched/group/group.h index 665ee69ac7b..915997b19f5 100644 --- a/sched/group/group.h +++ b/sched/group/group.h @@ -59,6 +59,8 @@ void task_initialize(void); /* Task group data structure management */ int group_allocate(FAR struct tcb_s *tcb, uint8_t ttype); +void group_init_rlimit(FAR struct task_group_s *group, + FAR struct task_group_s *parent); void group_initialize(FAR struct tcb_s *tcb); #ifndef CONFIG_DISABLE_PTHREAD void group_bind(FAR struct tcb_s *tcb); diff --git a/sched/group/group_create.c b/sched/group/group_create.c index 5febd80e11b..aa20c811718 100644 --- a/sched/group/group_create.c +++ b/sched/group/group_create.c @@ -254,6 +254,10 @@ int group_allocate(FAR struct tcb_s *tcb, uint8_t ttype) group->tg_caps = this_task()->group != NULL ? this_task()->group->tg_caps : PR_CAP_ALL; + /* Inherit the resource limits from the parent task group */ + + group_init_rlimit(group, this_task()->group); + /* Initialize file descriptors for the TCB */ fdlist_init(&group->tg_fdlist); diff --git a/sched/group/group_rlimit.c b/sched/group/group_rlimit.c new file mode 100644 index 00000000000..730c8def329 --- /dev/null +++ b/sched/group/group_rlimit.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * sched/group/group_rlimit.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/resource.h> +#include <errno.h> +#include <limits.h> +#include <sched.h> +#include <stdint.h> + +#include <nuttx/sched.h> + +#include "group/group.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: group_rlimit + * + * Description: + * Return the limit of a task group for a resource that NuttX enforces, + * or NULL for any other resource. + * + ****************************************************************************/ + +static inline FAR struct rlimit *group_rlimit(FAR struct task_group_s *group, + int resource) +{ + switch (resource) + { + case RLIMIT_STACK: + return &group->tg_rlimit_stack; + + case RLIMIT_NOFILE: + return &group->tg_rlimit_nofile; + + default: + return NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: group_init_rlimit + * + * Description: + * Give a new task group the resource limits of its parent, or the + * defaults if it has none: no stack limit and OPEN_MAX open files. At + * boot, the idle task is its own parent: it gets the defaults. + * + ****************************************************************************/ + +void group_init_rlimit(FAR struct task_group_s *group, + FAR struct task_group_s *parent) +{ + if (parent != NULL && parent != group) + { + group->tg_rlimit_stack = parent->tg_rlimit_stack; + group->tg_rlimit_nofile = parent->tg_rlimit_nofile; + } + else + { + group->tg_rlimit_stack.rlim_cur = RLIM_INFINITY; + group->tg_rlimit_stack.rlim_max = RLIM_INFINITY; + group->tg_rlimit_nofile.rlim_cur = OPEN_MAX; + group->tg_rlimit_nofile.rlim_max = OPEN_MAX; + } +} + +/**************************************************************************** + * Name: getrlimit + * + * Description: + * Return the soft and hard limit of a resource of the calling process. + * RLIMIT_STACK and RLIMIT_NOFILE are limits of the process. The + * resources that NuttX does not limit are reported as RLIM_INFINITY. + * + * Input Parameters: + * resource - The resource, RLIMIT_*. + * rlp - The location that receives the limits. + * + * Returned Value: + * Zero (OK) on success. On failure, -1 (ERROR) is returned and errno is + * set to EINVAL: rlp is NULL or resource is not valid. + * + ****************************************************************************/ + +int getrlimit(int resource, FAR struct rlimit *rlp) +{ + FAR struct rlimit *limit; + + if (rlp == NULL) + { + set_errno(EINVAL); + return ERROR; + } + + limit = group_rlimit(nxsched_self()->group, resource); + if (limit != NULL) + { + *rlp = *limit; + return OK; + } + + switch (resource) + { + case RLIMIT_CORE: + case RLIMIT_CPU: + case RLIMIT_DATA: + case RLIMIT_FSIZE: + case RLIMIT_AS: + case RLIMIT_MEMLOCK: + rlp->rlim_cur = RLIM_INFINITY; + rlp->rlim_max = RLIM_INFINITY; + break; + + case RLIMIT_NICE: + rlp->rlim_cur = 0; + rlp->rlim_max = 0; + break; + + case RLIMIT_RTPRIO: + rlp->rlim_cur = SCHED_PRIORITY_DEFAULT; + rlp->rlim_max = SCHED_PRIORITY_MAX; + break; + + case RLIMIT_RTTIME: + rlp->rlim_cur = UINT32_MAX; + rlp->rlim_max = UINT32_MAX; + break; + + default: + set_errno(EINVAL); + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: setrlimit + * + * Description: + * Set the soft and hard limit of a resource of the calling process. The + * process gives its limits to the processes that it creates. NuttX + * enforces RLIMIT_STACK (the default stack size of new threads and + * programs) and RLIMIT_NOFILE (the number of open files). + * + * Input Parameters: + * resource - RLIMIT_STACK or RLIMIT_NOFILE. + * rlp - The new limits. + * + * Returned Value: + * Zero (OK) on success. On failure, -1 (ERROR) is returned and errno is + * set: + * + * EINVAL - rlp is NULL, the soft limit is above the hard limit, or + * NuttX does not enforce the resource. + * EPERM - The hard limit is raised without privileges, or the limit + * of open files is above OPEN_MAX. + * + ****************************************************************************/ + +int setrlimit(int resource, FAR const struct rlimit *rlp) +{ + FAR struct task_group_s *group = nxsched_self()->group; + FAR struct rlimit *limit; + + limit = group_rlimit(group, resource); + if (rlp == NULL || limit == NULL || rlp->rlim_cur > rlp->rlim_max) + { + set_errno(EINVAL); + return ERROR; + } + + if (resource == RLIMIT_NOFILE && rlp->rlim_max > OPEN_MAX) + { + set_errno(EPERM); + return ERROR; + } + +#ifdef CONFIG_SCHED_USER_IDENTITY + if (rlp->rlim_max > limit->rlim_max && group->tg_euid != 0) + { + set_errno(EPERM); + return ERROR; + } +#endif + + *limit = *rlp; + return OK; +} diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 873629b2d89..bcb29d3c853 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -48,6 +48,7 @@ "getitimer","sys/time.h","!defined(CONFIG_DISABLE_POSIX_TIMERS)","int","int","FAR struct itimerval *" "getpeername","sys/socket.h","defined(CONFIG_NET)","int","int","FAR struct sockaddr *","FAR socklen_t *" "getppid","unistd.h","defined(CONFIG_SCHED_HAVE_PARENT)","pid_t" +"getrlimit","sys/resource.h","","int","int","FAR struct rlimit *" "getsockname","sys/socket.h","defined(CONFIG_NET)","int","int","FAR struct sockaddr *","FAR socklen_t *" "getsockopt","sys/socket.h","defined(CONFIG_NET)","int","int","int","int","FAR void *","FAR socklen_t *" "gettimeofday","sys/time.h","","int","FAR struct timeval *","FAR struct timezone *" @@ -166,6 +167,7 @@ "setgid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","gid_t" "sethostname","unistd.h","","int","FAR const char *","size_t" "setitimer","sys/time.h","!defined(CONFIG_DISABLE_POSIX_TIMERS)","int","int","FAR const struct itimerval *","FAR struct itimerval *" +"setrlimit","sys/resource.h","","int","int","FAR const struct rlimit *" "setsockopt","sys/socket.h","defined(CONFIG_NET) && defined(CONFIG_NET_SOCKOPTS)","int","int","int","int","FAR const void *","socklen_t" "settimeofday","sys/time.h","","int","FAR const struct timeval *","FAR const struct timezone *" "setuid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","uid_t"
