sysctl: Allow change system v ipc sysctls inside ipc namespace
Subsystems (3)
PATCH 1/1 sysctl: Allow change system v ipc sysctls inside ipc namespace
Rootless containers are not allowed to modify kernel IPC parameters such as kernel.msgmnb.
It seems to me that we can allow customization of these parameters if the user has CAP_SYS_RESOURCE in that ipc namespace.
CAP_SYS_RESOURCE is already needed in order to overcome mqueue limits (msg_max and msgsize_max).
--- ipc/ipc_sysctl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
ipc/ipc_sysctl.c +5 -2
@@ -193,16 +193,19 @@ static int set_is_seen(struct ctl_table_set *set)static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) {int mode = table->mode; - -#ifdef CONFIG_CHECKPOINT_RESTORE struct ipc_namespace *ns = current->nsproxy->ipc_ns; +#ifdef CONFIG_CHECKPOINT_RESTORE if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) mode =0666 ; + else#endif +if (ns_capable (ns->user_ns,CAP_SYS_RESOURCE )) + mode =0666 ; +return mode; }
Signature · 1 line
2.33.3
Quoted 8 lines · Alexey Gladkov
Rootless containers are not allowed to modify kernel IPC parameters such as kernel.msgmnb.
It seems to me that we can allow customization of these parameters if the user has
CAP_SYS_RESOURCEin that ipc namespace.
CAP_SYS_RESOURCEis already needed in order to overcome mqueue limits (msg_maxandmsgsize_max).
For changing the permissions on who can modify the SysV limits, I don't think this change is safe. I don't see anything that will prevent abuse if anyone can modify these limits. Replacing the ordinary unix DAC permission check with ns_capable will allow anyone to modify the limits.
That said there is RLIMIT_MSGQUEUE that limits the posix messages queues so those should be safe to allow anyone to modify their limits.
The code in mqueue_get_inode is where that limiting happens.
For the posix message queues all that should be needed is to change the owner of the sysctl files from the global root to the user namespace root. There are also two capable calls in ipc/mqueue.c that can probably be changed to ns_capable calls.
The only posix message queue limit that I don't immediately see something that will prevent abuse of is /proc/sys/fs/mqueue/queus_max. That probably still runs into RLIMIT_MSGQUEUE somewhere but it was not immediately obvious at first glance.
Eric
Quoted 31 lines
Signed-off-by Alexey Gladkov <[email protected]>--- ipc/ipc_sysctl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)ipc/ipc_sysctl.c +5
-2@@ -193,16 +193,19 @@ static int set_is_seen(struct ctl_table_set *set)static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) {int mode = table->mode; - -#ifdef CONFIG_CHECKPOINT_RESTORE struct ipc_namespace *ns = current->nsproxy->ipc_ns; +#ifdef CONFIG_CHECKPOINT_RESTORE if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) mode =0666 ; + else#endif +if (ns_capable (ns->user_ns,CAP_SYS_RESOURCE )) + mode =0666 ; +return mode; }
Quoted 8 lines · Eric W. Biederman
Quoted 6 lines · Alexey Gladkov
Rootless containers are not allowed to modify kernel IPC parameters such as kernel.msgmnb.
It seems to me that we can allow customization of these parameters if the user has
CAP_SYS_RESOURCEin that ipc namespace.
Quoted 8 lines
Quoted 2 lines
CAP_SYS_RESOURCEis already needed in order to overcome mqueue limits (msg_maxandmsgsize_max).For changing the permissions on who can modify the SysV limits, I don't think this change is safe. I don't see anything that will prevent abuse if anyone can modify these limits. Replacing the ordinary unix DAC permission check with
ns_capablewill allow anyone to modify the limits.
All limits are set to almost maximum values - ULONG_MAX. Limit values are not inherited and are counted in the each ipc namespace (shm_tot is not global and is located in ipc_ns). In fact, limits are disabled by default. They can only be reduced.
Quoted 11 lines
That said there is
RLIMIT_MSGQUEUEthat limits the posix messages queues so those should be safe to allow anyone to modify their limits.The code in
mqueue_get_inodeis where that limiting happens.For the posix message queues all that should be needed is to change the owner of the sysctl files from the global root to the user namespace root. There are also two capable calls in
ipc/mqueue.cthat can probably be changed tons_capablecalls.
Quoted 4 lines
The only posix message queue limit that I don't immediately see something that will prevent abuse of is
/proc/sys/fs/mqueue/queus_max. That probably still runs intoRLIMIT_MSGQUEUEsomewhere but it was not immediately obvious at first glance.
Everything always ends in mqueue_get_inode. In mqueue_create_attr we check mq_queues_max and call mqueue_get_inode almost immediately.
I suggest allowing root in user namespace to change ipc namespace limits.
--
Alexey Gladkov (3):
sysctl: Allow change system v ipc sysctls inside ipc namespace
sysctl: Allow to change limits for posix messages queues
docs: Add information about ipc sysctls limitations
Documentation/admin-guide/sysctl/kernel.rst | 14 ++++++-- ipc/ipc_sysctl.c | 34 ++++++++++++++++--- ipc/mq_sysctl.c | 36 +++++++++++++++++++++ 3 files changed, 76 insertions(+), 8 deletions(-)
Signature · 1 line
2.33.4
PATCH 1/3 sysctl: Allow change system v ipc sysctls inside ipc namespace
Rootless containers are not allowed to modify kernel IPC parameters.
All default limits are set to such high values that in fact there are no limits at all. All limits are not inherited and are initialized to default values when a new ipc_namespace is created.
For new ipc_namespace:
size_t ipc_ns.shm_ctlmax = SHMMAX; // (ULONG_MAX - (1UL << 24)) size_t ipc_ns.shm_ctlall = SHMALL; // (ULONG_MAX - (1UL << 24)) int ipc_ns.shm_ctlmni = IPCMNI; // (1 << 15) int ipc_ns.shm_rmid_forced = 0;
unsigned int ipc_ns.msg_ctlmax = MSGMAX; // 8192
unsigned int ipc_ns.msg_ctlmni = MSGMNI; // 32000
unsigned int ipc_ns.msg_ctlmnb = MSGMNB; // 16384
The shm_tot (total amount of shared pages) has also ceased to be global, it is located in ipc_namespace and is not inherited from anywhere.
In such conditions, it cannot be said that these limits limit anything. The real limiter for them is cgroups.
If we allow rootless containers to change these parameters, then it can only be reduced.
--- ipc/ipc_sysctl.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-)
ipc/ipc_sysctl.c +29 -5
@@ -192,23 +192,47 @@ static int set_is_seen(struct ctl_table_set *set)static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) { -int mode = table->mode; - -#ifdef CONFIG_CHECKPOINT_RESTORE struct ipc_namespace *ns = current->nsproxy->ipc_ns; +#ifdef CONFIG_CHECKPOINT_RESTORE if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) - mode =0666 ; +return 0666 ;#endif -return mode; +if (ns->user_ns != &init_user_ns) { +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + +if (uid_valid (ns_root_uid) &&uid_eq (current_euid (), ns_root_uid)) +return table->mode >>6 ; + +if (gid_valid (ns_root_gid) &&in_egroup_p (ns_root_gid)) +return table->mode >>3 ; + } + +return table->mode; +} + +static void ipc_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; }static struct ctl_table_root set_root = { .lookup = set_lookup, .permissions = ipc_permissions, + .set_ownership = ipc_set_ownership, };bool setup_ipc_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.33.4
Quoted 20 lines · Alexey Gladkov
Rootless containers are not allowed to modify kernel IPC parameters.
All default limits are set to such high values that in fact there are no limits at all. All limits are not inherited and are initialized to default values when a new
ipc_namespaceis created.For new
ipc_namespace:size_t ipc_ns.shm_ctlmax = SHMMAX; // (ULONG_MAX - (1UL << 24)) size_t ipc_ns.shm_ctlall = SHMALL; // (ULONG_MAX - (1UL << 24)) int ipc_ns.shm_ctlmni = IPCMNI; // (1 << 15) int ipc_ns.shm_rmid_forced = 0;unsigned int ipc_ns.msg_ctlmax = MSGMAX; // 8192
unsigned int ipc_ns.msg_ctlmni = MSGMNI; // 32000
unsigned int ipc_ns.msg_ctlmnb = MSGMNB; // 16384The
shm_tot(total amount of shared pages) has also ceased to be global, it is located inipc_namespaceand is not inherited from anywhere.
Quoted 5 lines
In such conditions, it cannot be said that these limits limit anything. The real limiter for them is cgroups.
If we allow rootless containers to change these parameters, then it can only be reduced.
Manfred does that analysis sound correct to you?
Do you have any concerns about allowing the users who create the ipc namespace to be able to set it's limits?
At a quick skim through everything Alex's analysis above appears correct to me.
From 10,000 feet this patch looks good. I do see a couple of nits that should be fixed before we merge this into Linus's tree.
Quoted 10 lines
Signed-off-by Alexey Gladkov <[email protected]>--- ipc/ipc_sysctl.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-)ipc/ipc_sysctl.c +0
-0
ipc/ipc_sysctl.c static int set_is_seen(struct ctl_table_set *set) · line 195
Quoted 7 lines
ipc/ipc_sysctl.c +0
-3@@ -192,23 +192,47 @@ static int set_is_seen(struct ctl_table_set *set)static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) { -int mode = table->mode; - -#ifdef CONFIG_CHECKPOINT_RESTORE struct ipc_namespace *ns = current->nsproxy->ipc_ns;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Historically that was the best we could do. But now that we have an ipc_set member in struct ipc_namespace you can use container_of to compute this value.
For a permission check that is much safer.
Quoted 8 lines
ipc/ipc_sysctl.c +2
-1+#ifdef CONFIG_CHECKPOINT_RESTORE if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) - mode =0666 ; +return 0666 ;#endif
ipc/ipc_sysctl.c static int set_is_seen(struct ctl_table_set *set) · line 212
Quoted 10 lines
ipc/ipc_sysctl.c +9
-1-return mode; +if (ns->user_ns != &init_user_ns) { +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + +if (uid_valid (ns_root_uid) &&uid_eq (current_euid (), ns_root_uid)) +return table->mode >>6 ; + +if (gid_valid (ns_root_gid) &&in_egroup_p (ns_root_gid)) +return table->mode >>3 ;
From 10,000 fee this is fine. But this has to interact with test_perm in proc_systl.c. So can you please do what net_ctl_permissions does and replicate the chosen mode all through the mode line.
Perhaps something like:
kuid_t ns_root_uid; kgid_t ns_root_gid ipc_set_ownership(head, table, &ns_root_uid, &ns_root_gid);
#ifdef CONFIG_CHECKPOINT_RESTORE
if (...)
mode = 0666;
else
#endif
if (uid_eq(current_euid(), ns_root_uid))
mode >>= 6;
else if (uid_eq(in_group_p(ns_root_gid))
mode >>= 3;
mode &= 7;
mode = (mode << 6) | (mode << 3) | mode;
return mode;If we always pass through the same logic there is the advantage that we will always test it, and there is less room for bugs to slip through.
I added a couple of unnecessary simplifications in there that I just saw as I was writing my example code.
Eric
Quoted 16 lines
ipc/ipc_sysctl.c +16
-0+ } + +return table->mode; +} + +static void ipc_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ;
ipc/ipc_sysctl.c static int set_is_seen(struct ctl_table_set *set) · line 238
Quoted 10 lines
ipc/ipc_sysctl.c +2
-0+ *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; }static struct ctl_table_root set_root = { .lookup = set_lookup, .permissions = ipc_permissions, + .set_ownership = ipc_set_ownership, };bool setup_ipc_sysctls (struct ipc_namespace *ns)
I can't see anything wrong with your proposed ipc_set_ownership.
Eric
Quoted 14 lines · Eric W. Biederman
ipc/ipc_sysctl.c static int set_is_seen(struct ctl_table_set *set) · line 195
Quoted 13 lines
ipc/ipc_sysctl.c +0
-3@@ -192,23 +192,47 @@ static int set_is_seen(struct ctl_table_set *set)static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) { -int mode = table->mode; - -#ifdef CONFIG_CHECKPOINT_RESTORE struct ipc_namespace *ns = current->nsproxy->ipc_ns;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Quoted 5 lines
Historically that was the best we could do. But now that we have an
ipc_setmember in structipc_namespaceyou can usecontainer_ofto compute this value.For a permission check that is much safer.
Yes. It make sense.
Quoted 47 lines
Quoted 19 lines
ipc/ipc_sysctl.c +11
-2+#ifdef CONFIG_CHECKPOINT_RESTORE if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) - mode =0666 ; +return 0666 ;#endif -return mode; +if (ns->user_ns != &init_user_ns) { +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + +if (uid_valid (ns_root_uid) &&uid_eq (current_euid (), ns_root_uid)) +return table->mode >>6 ; + +if (gid_valid (ns_root_gid) &&in_egroup_p (ns_root_gid)) +return table->mode >>3 ;Quoted 1 line
From 10,000 fee this is fine. But this has to interact with
test_perminproc_systl.c. So can you please do whatnet_ctl_permissionsdoes and replicate the chosen mode all through the mode line.Perhaps something like:
kuid_t ns_root_uid; kgid_t ns_root_gid ipc_set_ownership(head, table, &ns_root_uid, &ns_root_gid);#ifdef CONFIG_CHECKPOINT_RESTORE if (...) mode = 0666; else #endif if (uid_eq(current_euid(), ns_root_uid)) mode >>= 6; else if (uid_eq(in_group_p(ns_root_gid)) mode >>= 3; mode &= 7; mode = (mode << 6) | (mode << 3) | mode; return mode;
Quoted 5 lines
If we always pass through the same logic there is the advantage that we will always test it, and there is less room for bugs to slip through.
I added a couple of unnecessary simplifications in there that I just saw as I was writing my example code.
Thanks! It looks better. I'll fix it and send a new version.
Signature · 1 line
Rgrds, legion
v2 cover Allow to change ipc/mq sysctls inside ipc namespace
Right now ipc and mq limits count as per ipc namespace, but only real root can change them. By default, the current values of these limits are such that it can only be reduced. Since only root can change the values, it is impossible to reduce these limits in the rootless container.
We can allow limit changes within ipc namespace because mq parameters are limited by RLIMIT_MSGQUEUE and ipc parameters are not limited to anything other than cgroups.
--
Alexey Gladkov (3):
sysctl: Allow change system v ipc sysctls inside ipc namespace
sysctl: Allow to change limits for posix messages queues
docs: Add information about ipc sysctls limitations
Documentation/admin-guide/sysctl/kernel.rst | 14 ++++++-- ipc/ipc_sysctl.c | 34 ++++++++++++++++-- ipc/mq_sysctl.c | 38 +++++++++++++++++++++ 3 files changed, 80 insertions(+), 6 deletions(-)
Signature · 1 line
2.33.4
PATCH v2 1/3 sysctl: Allow change system v ipc sysctls inside ipc namespace
Rootless containers are not allowed to modify kernel IPC parameters.
All default limits are set to such high values that in fact there are no limits at all. All limits are not inherited and are initialized to default values when a new ipc_namespace is created.
For new ipc_namespace:
size_t ipc_ns.shm_ctlmax = SHMMAX; // (ULONG_MAX - (1UL << 24)) size_t ipc_ns.shm_ctlall = SHMALL; // (ULONG_MAX - (1UL << 24)) int ipc_ns.shm_ctlmni = IPCMNI; // (1 << 15) int ipc_ns.shm_rmid_forced = 0;
unsigned int ipc_ns.msg_ctlmax = MSGMAX; // 8192
unsigned int ipc_ns.msg_ctlmni = MSGMNI; // 32000
unsigned int ipc_ns.msg_ctlmnb = MSGMNB; // 16384
The shm_tot (total amount of shared pages) has also ceased to be global, it is located in ipc_namespace and is not inherited from anywhere.
In such conditions, it cannot be said that these limits limit anything. The real limiter for them is cgroups.
If we allow rootless containers to change these parameters, then it can only be reduced.
--- ipc/ipc_sysctl.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-)
ipc/ipc_sysctl.c +31 -3
@@ -190,25 +190,53 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->ipc_set == set; } +static void ipc_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} +static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) { +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set);int mode = table->mode; +kuid_t ns_root_uid; +kgid_t ns_root_gid; -#ifdef CONFIG_CHECKPOINT_RESTORE -struct ipc_namespace *ns = current->nsproxy->ipc_ns; +ipc_set_ownership (head, table, &ns_root_uid, ns_root_gid); +#ifdef CONFIG_CHECKPOINT_RESTORE if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) mode =0666 ; + else#endif -return mode; +if (uid_eq (current_euid (), ns_root_uid)) + mode >>=6 ; + +else if (in_egroup_p (ns_root_gid)) + mode >>=3 ; + + mode &=7 ; + +return (mode <<6 ) | (mode <<3 ) | mode; }static struct ctl_table_root set_root = { .lookup = set_lookup, .permissions = ipc_permissions, + .set_ownership = ipc_set_ownership, };bool setup_ipc_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.33.4
kernel test robot
build botThank you for the patch! Yet something to improve:
Hi Alexey,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on kees/for-next/pstore linus/master v6.0-rc6 next-20220920] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Alexey-Gladkov/sysctl-Allow-change-system-v-ipc-sysctls-inside-ipc-namespace/20220921-030939 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything config: hexagon-randconfig-r041-20220921 (https://download.01.org/0day-ci/archive/20220921/[email protected]/config) compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 791a7ae1ba3efd6bca96338e10ffde557ba83920)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/eb972fb9aad60123519d8dd32df26cb58985ce4a
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Alexey-Gladkov/sysctl-Allow-change-system-v-ipc-sysctls-inside-ipc-namespace/20220921-030939 git checkout eb972fb9aad60123519d8dd32df26cb58985ce4a
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash
If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <[email protected]>
All errors (new ones prefixed by >>):
>> ipc/ipc_sysctl.c:215:47: error: passing 'kgid_t' to parameter of incompatible type 'kgid_t *'; take the address with &
ipc_set_ownership(head, table, &ns_root_uid, ns_root_gid);
^~~~~~~~~~~
&
ipc/ipc_sysctl.c:195:31: note: passing argument to parameter 'gid' here
kuid_t *uid, kgid_t *gid)
^
>> ipc/ipc_sysctl.c:225:13: error: call to undeclared function 'current_euid'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
if (uid_eq(current_euid(), ns_root_uid))
^
ipc/ipc_sysctl.c:225:13: note: did you mean 'current_work'?
include/linux/workqueue.h:467:28: note: 'current_work' declared here
extern struct work_struct *current_work(void);
^
>> ipc/ipc_sysctl.c:225:13: error: passing 'int' to parameter of incompatible type 'kuid_t'
if (uid_eq(current_euid(), ns_root_uid))
^~~~~~~~~~~~~~
include/linux/uidgid.h:61:34: note: passing argument to parameter 'left' here
static inline bool uid_eq(kuid_t left, kuid_t right)
^
>> ipc/ipc_sysctl.c:228:11: error: call to undeclared function 'in_egroup_p'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] else if (in_egroup_p(ns_root_gid))
^
4 errors generated.
vim +215 ipc/ipc_sysctl.c
206
207 static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table)
208 {
209 struct ipc_namespace *ns =
210 container_of(head->set, struct ipc_namespace, ipc_set);
211 int mode = table->mode;
212 kuid_t ns_root_uid;
213 kgid_t ns_root_gid;
214
> 215 ipc_set_ownership(head, table, &ns_root_uid, ns_root_gid); 216 217 #ifdef CONFIG_CHECKPOINT_RESTORE 218 if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || 219 (table->data == &ns->ids[IPC_MSG_IDS].next_id) || 220 (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && 221 checkpoint_restore_ns_capable(ns->user_ns)) 222 mode = 0666; 223 else 224 #endif > 225 if (uid_eq(current_euid(), ns_root_uid)) 226 mode >>= 6; 227 > 228 else if (in_egroup_p(ns_root_gid))
229 mode >>= 3;
230
231 mode &= 7;
232
233 return (mode << 6) | (mode << 3) | mode;
234 }
235
Signature · 2 lines
0-DAY CI Kernel Test Service https://01.org/lkp
v3 cover Allow to change ipc/mq sysctls inside ipc namespace
Right now ipc and mq limits count as per ipc namespace, but only real root can change them. By default, the current values of these limits are such that it can only be reduced. Since only root can change the values, it is impossible to reduce these limits in the rootless container.
We can allow limit changes within ipc namespace because mq parameters are limited by RLIMIT_MSGQUEUE and ipc parameters are not limited to anything other than cgroups.
--
Alexey Gladkov (3):
sysctl: Allow change system v ipc sysctls inside ipc namespace
sysctl: Allow to change limits for posix messages queues
docs: Add information about ipc sysctls limitations
Documentation/admin-guide/sysctl/kernel.rst | 14 ++++++-- ipc/ipc_sysctl.c | 36 +++++++++++++++++++-- ipc/mq_sysctl.c | 36 +++++++++++++++++++++ 3 files changed, 81 insertions(+), 5 deletions(-)
Signature · 1 line
2.33.4
PATCH v3 1/3 sysctl: Allow change system v ipc sysctls inside ipc namespace
Rootless containers are not allowed to modify kernel IPC parameters.
All default limits are set to such high values that in fact there are no limits at all. All limits are not inherited and are initialized to default values when a new ipc_namespace is created.
For new ipc_namespace:
size_t ipc_ns.shm_ctlmax = SHMMAX; // (ULONG_MAX - (1UL << 24)) size_t ipc_ns.shm_ctlall = SHMALL; // (ULONG_MAX - (1UL << 24)) int ipc_ns.shm_ctlmni = IPCMNI; // (1 << 15) int ipc_ns.shm_rmid_forced = 0;
unsigned int ipc_ns.msg_ctlmax = MSGMAX; // 8192
unsigned int ipc_ns.msg_ctlmni = MSGMNI; // 32000
unsigned int ipc_ns.msg_ctlmnb = MSGMNB; // 16384
The shm_tot (total amount of shared pages) has also ceased to be global, it is located in ipc_namespace and is not inherited from anywhere.
In such conditions, it cannot be said that these limits limit anything. The real limiter for them is cgroups.
If we allow rootless containers to change these parameters, then it can only be reduced.
--- ipc/ipc_sysctl.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-)
ipc/ipc_sysctl.c +34 -2
@@ -190,25 +190,57 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->ipc_set == set; } +static void ipc_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} +static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) {int mode = table->mode;#ifdef CONFIG_CHECKPOINT_RESTORE -struct ipc_namespace *ns = current->nsproxy->ipc_ns; +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set);if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) mode =0666 ; + else#endif -return mode; + { +kuid_t ns_root_uid; +kgid_t ns_root_gid; + +ipc_set_ownership (head, table, &ns_root_uid, &ns_root_gid); + +if (uid_eq (current_euid (), ns_root_uid)) + mode >>=6 ; + +else if (in_egroup_p (ns_root_gid)) + mode >>=3 ; + } + + mode &=7 ; + +return (mode <<6 ) | (mode <<3 ) | mode; }static struct ctl_table_root set_root = { .lookup = set_lookup, .permissions = ipc_permissions, + .set_ownership = ipc_set_ownership, };bool setup_ipc_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.33.4
PATCH v3 2/3 sysctl: Allow to change limits for posix messages queues
In reply to Alexey GladkovAll parameters of posix messages queues (queues_max/msg_max/msgsize_max) end up being limited by RLIMIT_MSGQUEUE. The code in mqueue_get_inode is where that limiting happens.
The RLIMIT_MSGQUEUE is bound to the user namespace and is counted hierarchically.
We can allow root in the user namespace to modify the posix messages queues parameters.
--- ipc/mq_sysctl.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
ipc/mq_sysctl.c +36 -0
@@ -12,6 +12,7 @@#include <linux/stat.h> #include <linux/capability.h> #include <linux/slab.h> +#include <linux/cred.h> static int msg_max_limit_min =MIN_MSGMAX ;static int msg_max_limit_max =HARD_MSGMAX ;
@@ -76,8 +77,43 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->mq_set == set; } +static void mq_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} + +static int mq_permissions (struct ctl_table_header *head,struct ctl_table *table) +{ +int mode = table->mode; +kuid_t ns_root_uid; +kgid_t ns_root_gid; + +mq_set_ownership (head, table, &ns_root_uid, &ns_root_gid); + +if (uid_eq (current_euid (), ns_root_uid)) + mode >>=6 ; + +if (in_egroup_p (ns_root_gid)) + mode >>=3 ; + + mode &=7 ; + +return (mode <<6 ) | (mode <<3 ) | mode; +} +static struct ctl_table_root set_root = { .lookup = set_lookup, + .permissions = mq_permissions, + .set_ownership = mq_set_ownership, };bool setup_mq_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.33.4
PATCH v3 3/3 docs: Add information about ipc sysctls limitations
In reply to Alexey GladkovAfter 25b21cb2f6d6 ("[PATCH] IPC namespace core") and 4e9823111bdc ("[PATCH] IPC namespace - shm") the shared memory page count stopped being global and started counting per ipc namespace. The documentation and shmget(2) still says that shmall is a global option.
shmget(2):
SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size. On Linux, this limit can be read and modified via /proc/sys/kernel/shmall.
I think the changes made in 2006 should be documented.
--- Documentation/admin-guide/sysctl/kernel.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
Documentation/admin-guide/sysctl/kernel.rst +11 -3
@@ -541,6 +541,9 @@ default (``MSGMNB``). ``msgmni`` is the maximum number of IPC queues. 32000 by default (``MSGMNI``). +All of these parameters are set per ipc namespace. The maximum number of bytes +in POSIX message queues is limited by ``RLIMIT_MSGQUEUE``. This limit is +respected hierarchically in the each user namespace. msg_next_id, sem_next_id, and shm_next_id (System V IPC) ========================================================
@@ -1181,15 +1184,20 @@ are doing anyway :) shmall ====== -This parameter sets the total amount of shared memory pages that -can be used system wide. Hence, ``shmall`` should always be at least -``ceil(shmmax/PAGE_SIZE)``. +This parameter sets the total amount of shared memory pages that can be used +inside ipc namespace. The shared memory pages counting occurs for each ipc +namespace separately and is not inherited. Hence, ``shmall`` should always be at +least ``ceil(shmmax/PAGE_SIZE)``. If you are not sure what the default ``PAGE_SIZE`` is on your Linux system, you can run the following command:: # getconf PAGE_SIZE +To reduce or disable the ability to allocate shared memory, you must create a +new ipc namespace, set this parameter to the required value and prohibit the +creation of a new ipc namespace in the current user namespace or cgroups can +be used. shmmax ======
Signature · 1 line
2.33.4
v3 cover Allow to change ipc/mq sysctls inside ipc namespace
In reply to Alexey GladkovRight now ipc and mq limits count as per ipc namespace, but only real root can change them. By default, the current values of these limits are such that it can only be reduced. Since only root can change the values, it is impossible to reduce these limits in the rootless container.
We can allow limit changes within ipc namespace because mq parameters are limited by RLIMIT_MSGQUEUE and ipc parameters are not limited to anything other than cgroups.
This is just a rebase of patches on v6.7-6264-g70d201a40823.
---
Alexey Gladkov (3):
sysctl: Allow change system v ipc sysctls inside ipc namespace
docs: Add information about ipc sysctls limitations
sysctl: Allow to change limits for posix messages queues
Documentation/admin-guide/sysctl/kernel.rst | 14 ++++++-- ipc/ipc_sysctl.c | 37 +++++++++++++++++++-- ipc/mq_sysctl.c | 36 ++++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-)
Signature · 1 line
2.43.0
PATCH RESEND v3 1/3 sysctl: Allow change system v ipc sysctls inside ipc namespace
Rootless containers are not allowed to modify kernel IPC parameters.
All default limits are set to such high values that in fact there are no limits at all. All limits are not inherited and are initialized to default values when a new ipc_namespace is created.
For new ipc_namespace:
size_t ipc_ns.shm_ctlmax = SHMMAX; // (ULONG_MAX - (1UL << 24)) size_t ipc_ns.shm_ctlall = SHMALL; // (ULONG_MAX - (1UL << 24)) int ipc_ns.shm_ctlmni = IPCMNI; // (1 << 15) int ipc_ns.shm_rmid_forced = 0;
unsigned int ipc_ns.msg_ctlmax = MSGMAX; // 8192
unsigned int ipc_ns.msg_ctlmni = MSGMNI; // 32000
unsigned int ipc_ns.msg_ctlmnb = MSGMNB; // 16384
The shm_tot (total amount of shared pages) has also ceased to be global, it is located in ipc_namespace and is not inherited from anywhere.
In such conditions, it cannot be said that these limits limit anything. The real limiter for them is cgroups.
If we allow rootless containers to change these parameters, then it can only be reduced.
--- ipc/ipc_sysctl.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-)
ipc/ipc_sysctl.c +35 -2
@@ -14,6 +14,7 @@#include <linux/ipc_namespace.h> #include <linux/msg.h> #include <linux/slab.h> +#include <linux/cred.h> #include "util.h" static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
@@ -190,25 +191,57 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->ipc_set == set; } +static void ipc_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} +static int ipc_permissions (struct ctl_table_header *head,struct ctl_table *table) {int mode = table->mode;#ifdef CONFIG_CHECKPOINT_RESTORE -struct ipc_namespace *ns = current->nsproxy->ipc_ns; +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, ipc_set);if (((table->data == &ns->ids[IPC_SEM_IDS ].next_id) || (table->data == &ns->ids[IPC_MSG_IDS ].next_id) || (table->data == &ns->ids[IPC_SHM_IDS ].next_id)) &&checkpoint_restore_ns_capable (ns->user_ns)) mode =0666 ; + else#endif -return mode; + { +kuid_t ns_root_uid; +kgid_t ns_root_gid; + +ipc_set_ownership (head, table, &ns_root_uid, &ns_root_gid); + +if (uid_eq (current_euid (), ns_root_uid)) + mode >>=6 ; + +else if (in_egroup_p (ns_root_gid)) + mode >>=3 ; + } + + mode &=7 ; + +return (mode <<6 ) | (mode <<3 ) | mode; }static struct ctl_table_root set_root = { .lookup = set_lookup, .permissions = ipc_permissions, + .set_ownership = ipc_set_ownership, };bool setup_ipc_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.43.0
PATCH RESEND v3 2/3 docs: Add information about ipc sysctls limitations
In reply to Alexey GladkovAfter 25b21cb2f6d6 ("[PATCH] IPC namespace core") and 4e9823111bdc ("[PATCH] IPC namespace - shm") the shared memory page count stopped being global and started counting per ipc namespace. The documentation and shmget(2) still says that shmall is a global option.
shmget(2):
SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size. On Linux, this limit can be read and modified via /proc/sys/kernel/shmall.
I think the changes made in 2006 should be documented.
--- Documentation/admin-guide/sysctl/kernel.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
Documentation/admin-guide/sysctl/kernel.rst +11 -3
@@ -594,6 +594,9 @@ default (``MSGMNB``). ``msgmni`` is the maximum number of IPC queues. 32000 by default (``MSGMNI``). +All of these parameters are set per ipc namespace. The maximum number of bytes +in POSIX message queues is limited by ``RLIMIT_MSGQUEUE``. This limit is +respected hierarchically in the each user namespace. msg_next_id, sem_next_id, and shm_next_id (System V IPC) ========================================================
@@ -1274,15 +1277,20 @@ are doing anyway :) shmall ====== -This parameter sets the total amount of shared memory pages that -can be used system wide. Hence, ``shmall`` should always be at least -``ceil(shmmax/PAGE_SIZE)``. +This parameter sets the total amount of shared memory pages that can be used +inside ipc namespace. The shared memory pages counting occurs for each ipc +namespace separately and is not inherited. Hence, ``shmall`` should always be at +least ``ceil(shmmax/PAGE_SIZE)``. If you are not sure what the default ``PAGE_SIZE`` is on your Linux system, you can run the following command:: # getconf PAGE_SIZE +To reduce or disable the ability to allocate shared memory, you must create a +new ipc namespace, set this parameter to the required value and prohibit the +creation of a new ipc namespace in the current user namespace or cgroups can +be used. shmmax ======
Signature · 1 line
2.43.0
Re: [RESEND PATCH v3 2/3] docs: Add information about ipc sysctls limitations
Hi Alexey,
Quoted 26 lines · Alexey Gladkov
After
25b21cb2f6d6("[PATCH] IPC namespace core") and4e9823111bdc("[PATCH] IPC namespace - shm") the shared memory page count stopped being global and started counting per ipc namespace. The documentation and shmget(2) still says that shmall is a global option.shmget(2):
SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size. On Linux, this limit can be read and modified via
/proc/sys/kernel/shmall.I think the changes made in 2006 should be documented.
Signed-off-by Alexey Gladkov <[email protected]>Link https://lkml.kernel.org/r/ede20ddf7be48b93e8084c3be2e920841ee1a641.1663756794.git.legion@kernel.org open hereSigned-off-by Eric W. Biederman <[email protected]>--- Documentation/admin-guide/sysctl/kernel.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)Documentation/admin-guide/sysctl/kernel.rst +0
-0
Documentation/admin-guide/sysctl/kernel.rst default (``MSGMNB``). · line 599
Quoted 6 lines
Documentation/admin-guide/sysctl/kernel.rst +3
-0@@ -594,6 +594,9 @@ default (``MSGMNB``). ``msgmni`` is the maximum number of IPC queues. 32000 by default (``MSGMNI``). +All of these parameters are set per ipc namespace. The maximum number of bytes +in POSIX message queues is limited by ``RLIMIT_MSGQUEUE``. This limit is +respected hierarchically in the each user namespace.
This block is about mqueue, not about SHM.
Could you mention the change also in the change description.
And: It is not fully clear to me what you mean with "respected hierarchically"
Quoted 14 lines
Documentation/admin-guide/sysctl/kernel.rst +4
-3msg_next_id, sem_next_id, and shm_next_id (System V IPC) ========================================================@@ -1274,15 +1277,20 @@ are doing anyway :) shmall ====== -This parameter sets the total amount of shared memory pages that -can be used system wide. Hence, ``shmall`` should always be at least -``ceil(shmmax/PAGE_SIZE)``. +This parameter sets the total amount of shared memory pages that can be used +inside ipc namespace. The shared memory pages counting occurs for each ipc +namespace separately and is not inherited. Hence, ``shmall`` should always be at +least ``ceil(shmmax/PAGE_SIZE)``.
Documentation/admin-guide/sysctl/kernel.rst are doing anyway :) · line 1293
Quoted 10 lines
Documentation/admin-guide/sysctl/kernel.rst +4
-0If you are not sure what the default ``PAGE_SIZE`` is on your Linux system, you can run the following command:: # getconf PAGE_SIZE +To reduce or disable the ability to allocate shared memory, you must create a +new ipc namespace, set this parameter to the required value and prohibit the +creation of a new ipc namespace in the current user namespace or cgroups can +be used.
cgroups are an alternative to which part of the sentence?
"prohibit the creation of a new ipc namespace"? or to the whole sentence?
+To reduce or disable the ability to allocate shared memory, you must
+ * create a new ipc namespace, set this parameter to the required value and
+ prohibit the creation of a new ipc namespace in the current user namespace
+ * use cgroups
--
Manfred
PATCH RESEND v3 3/3 sysctl: Allow to change limits for posix messages queues
In reply to Alexey GladkovAll parameters of posix messages queues (queues_max/msg_max/msgsize_max) end up being limited by RLIMIT_MSGQUEUE. The code in mqueue_get_inode is where that limiting happens.
The RLIMIT_MSGQUEUE is bound to the user namespace and is counted hierarchically.
We can allow root in the user namespace to modify the posix messages queues parameters.
--- ipc/mq_sysctl.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
ipc/mq_sysctl.c +36 -0
@@ -12,6 +12,7 @@#include <linux/stat.h> #include <linux/capability.h> #include <linux/slab.h> +#include <linux/cred.h> static int msg_max_limit_min =MIN_MSGMAX ;static int msg_max_limit_max =HARD_MSGMAX ;
@@ -76,8 +77,43 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->mq_set == set; } +static void mq_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} + +static int mq_permissions (struct ctl_table_header *head,struct ctl_table *table) +{ +int mode = table->mode; +kuid_t ns_root_uid; +kgid_t ns_root_gid; + +mq_set_ownership (head, table, &ns_root_uid, &ns_root_gid); + +if (uid_eq (current_euid (), ns_root_uid)) + mode >>=6 ; + +else if (in_egroup_p (ns_root_gid)) + mode >>=3 ; + + mode &=7 ; + +return (mode <<6 ) | (mode <<3 ) | mode; +} +static struct ctl_table_root set_root = { .lookup = set_lookup, + .permissions = mq_permissions, + .set_ownership = mq_set_ownership, };bool setup_mq_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.43.0
PATCH v2 2/3 sysctl: Allow to change limits for posix messages queues
In reply to Alexey GladkovAll parameters of posix messages queues (queues_max/msg_max/msgsize_max) end up being limited by RLIMIT_MSGQUEUE. The code in mqueue_get_inode is where that limiting happens.
The RLIMIT_MSGQUEUE is bound to the user namespace and is counted hierarchically.
We can allow root in the user namespace to modify the posix messages queues parameters.
--- ipc/mq_sysctl.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
ipc/mq_sysctl.c +38 -0
@@ -12,6 +12,7 @@#include <linux/stat.h> #include <linux/capability.h> #include <linux/slab.h> +#include <linux/cred.h> static int msg_max_limit_min =MIN_MSGMAX ;static int msg_max_limit_max =HARD_MSGMAX ;
@@ -76,8 +77,45 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->mq_set == set; } +static void mq_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} + +static int mq_permissions (struct ctl_table_header *head,struct ctl_table *table) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); +int mode = table->mode; +kuid_t ns_root_uid; +kgid_t ns_root_gid; + +mq_set_ownership (head, table, &ns_root_uid, &ns_root_gid); + +if (uid_eq (current_euid (), ns_root_uid)) + mode >>=6 ; + +if (in_egroup_p (ns_root_gid)) + mode >>=3 ; + + mode &=7 ; + +return (mode <<6 ) | (mode <<3 ) | mode; +} +static struct ctl_table_root set_root = { .lookup = set_lookup, + .permissions = mq_permissions, + .set_ownership = mq_set_ownership, };bool setup_mq_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.33.4
PATCH v2 3/3 docs: Add information about ipc sysctls limitations
In reply to Alexey GladkovAfter 25b21cb2f6d6 ("[PATCH] IPC namespace core") and 4e9823111bdc ("[PATCH] IPC namespace - shm") the shared memory page count stopped being global and started counting per ipc namespace. The documentation and shmget(2) still says that shmall is a global option.
shmget(2):
SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size. On Linux, this limit can be read and modified via /proc/sys/kernel/shmall.
I think the changes made in 2006 should be documented.
--- Documentation/admin-guide/sysctl/kernel.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
Documentation/admin-guide/sysctl/kernel.rst +11 -3
@@ -541,6 +541,9 @@ default (``MSGMNB``). ``msgmni`` is the maximum number of IPC queues. 32000 by default (``MSGMNI``). +All of these parameters are set per ipc namespace. The maximum number of bytes +in POSIX message queues is limited by ``RLIMIT_MSGQUEUE``. This limit is +respected hierarchically in the each user namespace. msg_next_id, sem_next_id, and shm_next_id (System V IPC) ========================================================
@@ -1181,15 +1184,20 @@ are doing anyway :) shmall ====== -This parameter sets the total amount of shared memory pages that -can be used system wide. Hence, ``shmall`` should always be at least -``ceil(shmmax/PAGE_SIZE)``. +This parameter sets the total amount of shared memory pages that can be used +inside ipc namespace. The shared memory pages counting occurs for each ipc +namespace separately and is not inherited. Hence, ``shmall`` should always be at +least ``ceil(shmmax/PAGE_SIZE)``. If you are not sure what the default ``PAGE_SIZE`` is on your Linux system, you can run the following command:: # getconf PAGE_SIZE +To reduce or disable the ability to allocate shared memory, you must create a +new ipc namespace, set this parameter to the required value and prohibit the +creation of a new ipc namespace in the current user namespace or cgroups can +be used. shmmax ======
Signature · 1 line
2.33.4
PATCH 2/3 sysctl: Allow to change limits for posix messages queues
In reply to Alexey GladkovAll parameters of posix messages queues (queues_max/msg_max/msgsize_max) end up being limited by RLIMIT_MSGQUEUE. The code in mqueue_get_inode is where that limiting happens.
The RLIMIT_MSGQUEUE is bound to the user namespace and is counted hierarchically.
We can allow root in the user namespace to modify the posix messages queues parameters.
--- ipc/mq_sysctl.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
ipc/mq_sysctl.c +36 -0
@@ -12,6 +12,7 @@#include <linux/stat.h> #include <linux/capability.h> #include <linux/slab.h> +#include <linux/cred.h> static int msg_max_limit_min =MIN_MSGMAX ;static int msg_max_limit_max =HARD_MSGMAX ;
@@ -76,8 +77,43 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->mq_set == set; } +static int mq_permissions (struct ctl_table_header *head,struct ctl_table *table) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +if (ns->user_ns != &init_user_ns) { +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + +if (uid_valid (ns_root_uid) &&uid_eq (current_euid (), ns_root_uid)) +return table->mode >>6 ; + +if (gid_valid (ns_root_gid) &&in_egroup_p (ns_root_gid)) +return table->mode >>3 ; + } + +return table->mode; +} + +static void mq_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} +static struct ctl_table_root set_root = { .lookup = set_lookup, + .permissions = mq_permissions, + .set_ownership = mq_set_ownership, };bool setup_mq_sysctls (struct ipc_namespace *ns)
Signature · 1 line
2.33.4
Re: [PATCH v1 2/3] sysctl: Allow to change limits for posix messages queues
Quoted 9 lines · Alexey Gladkov
All parameters of posix messages queues (queues_max/msg_max/msgsize_max) end up being limited by
RLIMIT_MSGQUEUE. The code inmqueue_get_inodeis where that limiting happens.The
RLIMIT_MSGQUEUEis bound to the user namespace and is counted hierarchically.We can allow root in the user namespace to modify the posix messages queues parameters.
This looks good from 10,000 feet. But the same nits with setting mode in mq_permissions as in ipc_set_permissions in your other patch.
Eric
Quoted 61 lines
Signed-off-by Alexey Gladkov <[email protected]>--- ipc/mq_sysctl.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)ipc/mq_sysctl.c +36
-0@@ -12,6 +12,7 @@#include <linux/stat.h> #include <linux/capability.h> #include <linux/slab.h> +#include <linux/cred.h> static int msg_max_limit_min =MIN_MSGMAX ;static int msg_max_limit_max =HARD_MSGMAX ;@@ -76,8 +77,43 @@ static int set_is_seen(struct ctl_table_set *set)return ¤t->nsproxy->ipc_ns->mq_set == set; } +static int mq_permissions (struct ctl_table_header *head,struct ctl_table *table) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +if (ns->user_ns != &init_user_ns) { +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + +if (uid_valid (ns_root_uid) &&uid_eq (current_euid (), ns_root_uid)) +return table->mode >>6 ; + +if (gid_valid (ns_root_gid) &&in_egroup_p (ns_root_gid)) +return table->mode >>3 ; + } + +return table->mode; +} + +static void mq_set_ownership (struct ctl_table_header *head, +struct ctl_table *table, +kuid_t *uid,kgid_t *gid) +{ +struct ipc_namespace *ns = + container_of(head->set, struct ipc_namespace, mq_set); + +kuid_t ns_root_uid =make_kuid (ns->user_ns,0 ); +kgid_t ns_root_gid =make_kgid (ns->user_ns,0 ); + + *uid =uid_valid (ns_root_uid) ? ns_root_uid :GLOBAL_ROOT_UID ; + *gid =gid_valid (ns_root_gid) ? ns_root_gid :GLOBAL_ROOT_GID ; +} +static struct ctl_table_root set_root = { .lookup = set_lookup, + .permissions = mq_permissions, + .set_ownership = mq_set_ownership, };bool setup_mq_sysctls (struct ipc_namespace *ns)
PATCH 3/3 docs: Add information about ipc sysctls limitations
In reply to Alexey GladkovAfter 25b21cb2f6d6 ("[PATCH] IPC namespace core") and 4e9823111bdc ("[PATCH] IPC namespace - shm") the shared memory page count stopped being global and started counting per ipc namespace. The documentation and shmget(2) still says that shmall is a global option.
shmget(2):
SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size. On Linux, this limit can be read and modified via /proc/sys/kernel/shmall.
I think the changes made in 2006 should be documented.
--- Documentation/admin-guide/sysctl/kernel.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
Documentation/admin-guide/sysctl/kernel.rst +11 -3
@@ -541,6 +541,9 @@ default (``MSGMNB``). ``msgmni`` is the maximum number of IPC queues. 32000 by default (``MSGMNI``). +All of these parameters are set per ipc namespace. The maximum number of bytes +in POSIX message queues is limited by ``RLIMIT_MSGQUEUE``. This limit is +respected hierarchically in the each user namespace. msg_next_id, sem_next_id, and shm_next_id (System V IPC) ========================================================
@@ -1169,15 +1172,20 @@ are doing anyway :) shmall ====== -This parameter sets the total amount of shared memory pages that -can be used system wide. Hence, ``shmall`` should always be at least -``ceil(shmmax/PAGE_SIZE)``. +This parameter sets the total amount of shared memory pages that can be used +inside ipc namespace. The shared memory pages counting occurs for each ipc +namespace separately and is not inherited. Hence, ``shmall`` should always be at +least ``ceil(shmmax/PAGE_SIZE)``. If you are not sure what the default ``PAGE_SIZE`` is on your Linux system, you can run the following command:: # getconf PAGE_SIZE +To reduce or disable the ability to allocate shared memory, you must create a +new ipc namespace, set this parameter to the required value and prohibit the +creation of a new ipc namespace in the current user namespace or cgroups can +be used. shmmax ======
Signature · 1 line
2.33.4
Re: [PATCH v1 3/3] docs: Add information about ipc sysctls limitations
Quoted 5 lines · Alexey Gladkov
After
25b21cb2f6d6("[PATCH] IPC namespace core") and4e9823111bdc("[PATCH] IPC namespace - shm") the shared memory page count stopped being global and started counting per ipc namespace. The documentation and shmget(2) still says that shmall is a global option.
Quoted 7 lines
shmget(2):
SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size. On Linux, this limit can be read and modified via
/proc/sys/kernel/shmall.I think the changes made in 2006 should be documented.
Agreed. Documenting these limits only apply to their ipc namespace is overdue.
Quoted 43 lines
Signed-off-by Alexey Gladkov <[email protected]>--- Documentation/admin-guide/sysctl/kernel.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)Documentation/admin-guide/sysctl/kernel.rst +11
-3@@ -541,6 +541,9 @@ default (``MSGMNB``). ``msgmni`` is the maximum number of IPC queues. 32000 by default (``MSGMNI``). +All of these parameters are set per ipc namespace. The maximum number of bytes +in POSIX message queues is limited by ``RLIMIT_MSGQUEUE``. This limit is +respected hierarchically in the each user namespace. msg_next_id, sem_next_id, and shm_next_id (System V IPC) ========================================================@@ -1169,15 +1172,20 @@ are doing anyway :) shmall ====== -This parameter sets the total amount of shared memory pages that -can be used system wide. Hence, ``shmall`` should always be at least -``ceil(shmmax/PAGE_SIZE)``. +This parameter sets the total amount of shared memory pages that can be used +inside ipc namespace. The shared memory pages counting occurs for each ipc +namespace separately and is not inherited. Hence, ``shmall`` should always be at +least ``ceil(shmmax/PAGE_SIZE)``. If you are not sure what the default ``PAGE_SIZE`` is on your Linux system, you can run the following command:: # getconf PAGE_SIZE +To reduce or disable the ability to allocate shared memory, you must create a +new ipc namespace, set this parameter to the required value and prohibit the +creation of a new ipc namespace in the current user namespace or cgroups can +be used. shmmax ======