2019-06-01 08:08:55 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2009-04-07 02:01:11 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 IBM Corporation
|
|
|
|
*
|
|
|
|
* Author: Cedric Le Goater <clg@fr.ibm.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/nsproxy.h>
|
|
|
|
#include <linux/ipc_namespace.h>
|
|
|
|
#include <linux/sysctl.h>
|
|
|
|
|
2022-02-14 18:18:14 +00:00
|
|
|
#include <linux/stat.h>
|
|
|
|
#include <linux/capability.h>
|
|
|
|
#include <linux/slab.h>
|
2024-01-15 15:46:43 +00:00
|
|
|
#include <linux/cred.h>
|
2009-04-07 02:01:11 +00:00
|
|
|
|
|
|
|
static int msg_max_limit_min = MIN_MSGMAX;
|
ipc/mqueue: cleanup definition names and locations
Since commit b231cca4381e ("message queues: increase range limits") on
Oct 18, 2008, calls to mq_open() that did not pass in an attribute
struct and expected to get default values for the size of the queue and
the max message size now get the system wide maximums instead of
hardwired defaults like they used to get.
This was uncovered when one of the earlier patches in this patch set
increased the default system wide maximums at the same time it increased
the hard ceiling on the system wide maximums (a customer specifically
needed the hard ceiling brought back up, the new ceiling that commit
b231cca4381e introduced was too low for their production systems). By
increasing the default maximums and not realising they were tied to any
attempt to create a message queue without an attribute struct, I had
inadvertently made it such that all message queue creation attempts
without an attribute struct were failing because the new default
maximums would create a queue that exceeded the default rlimit for
message queue bytes.
As a result, the system wide defaults were brought back down to their
previous levels, and the system wide ceilings on the maximums were
raised to meet the customer's needs. However, the fact that the no
attribute struct behavior of mq_open() could be broken by changing the
system wide maximums for message queues was seen as fundamentally broken
itself. So we hardwired the no attribute case back like it used to be.
But, then we realized that on the very off chance that some piece of
software in the wild depended on that behavior, we could work around
that issue by adding two new knobs to /proc that allowed setting the
defaults for message queues created without an attr struct separately
from the system wide maximums.
What is not an option IMO is to leave the current behavior in place. No
piece of software should ever rely on setting the system wide maximums
in order to get a desired message queue. Such a reliance would be so
fundamentally multitasking OS unfriendly as to not really be tolerable.
Fortunately, we don't know of any software in the wild that uses this
except for a regression test program that caught the issue in the first
place. If there is though, we have made accommodations with the two new
/proc knobs (and that's all the accommodations such fundamentally broken
software can be allowed)..
This patch:
The various defines for minimums and maximums of the sysctl controllable
mqueue values are scattered amongst different files and named
inconsistently. Move them all into ipc_namespace.h and make them have
consistent names. Additionally, make the number of queues per namespace
also have a minimum and maximum and use the same sysctl function as the
other two settable variables.
Signed-off-by: Doug Ledford <dledford@redhat.com>
Acked-by: Serge E. Hallyn <serue@us.ibm.com>
Cc: Amerigo Wang <amwang@redhat.com>
Cc: Joe Korty <joe.korty@ccur.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-05-31 23:26:28 +00:00
|
|
|
static int msg_max_limit_max = HARD_MSGMAX;
|
2009-04-07 02:01:11 +00:00
|
|
|
|
|
|
|
static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
|
ipc/mqueue: cleanup definition names and locations
Since commit b231cca4381e ("message queues: increase range limits") on
Oct 18, 2008, calls to mq_open() that did not pass in an attribute
struct and expected to get default values for the size of the queue and
the max message size now get the system wide maximums instead of
hardwired defaults like they used to get.
This was uncovered when one of the earlier patches in this patch set
increased the default system wide maximums at the same time it increased
the hard ceiling on the system wide maximums (a customer specifically
needed the hard ceiling brought back up, the new ceiling that commit
b231cca4381e introduced was too low for their production systems). By
increasing the default maximums and not realising they were tied to any
attempt to create a message queue without an attribute struct, I had
inadvertently made it such that all message queue creation attempts
without an attribute struct were failing because the new default
maximums would create a queue that exceeded the default rlimit for
message queue bytes.
As a result, the system wide defaults were brought back down to their
previous levels, and the system wide ceilings on the maximums were
raised to meet the customer's needs. However, the fact that the no
attribute struct behavior of mq_open() could be broken by changing the
system wide maximums for message queues was seen as fundamentally broken
itself. So we hardwired the no attribute case back like it used to be.
But, then we realized that on the very off chance that some piece of
software in the wild depended on that behavior, we could work around
that issue by adding two new knobs to /proc that allowed setting the
defaults for message queues created without an attr struct separately
from the system wide maximums.
What is not an option IMO is to leave the current behavior in place. No
piece of software should ever rely on setting the system wide maximums
in order to get a desired message queue. Such a reliance would be so
fundamentally multitasking OS unfriendly as to not really be tolerable.
Fortunately, we don't know of any software in the wild that uses this
except for a regression test program that caught the issue in the first
place. If there is though, we have made accommodations with the two new
/proc knobs (and that's all the accommodations such fundamentally broken
software can be allowed)..
This patch:
The various defines for minimums and maximums of the sysctl controllable
mqueue values are scattered amongst different files and named
inconsistently. Move them all into ipc_namespace.h and make them have
consistent names. Additionally, make the number of queues per namespace
also have a minimum and maximum and use the same sysctl function as the
other two settable variables.
Signed-off-by: Doug Ledford <dledford@redhat.com>
Acked-by: Serge E. Hallyn <serue@us.ibm.com>
Cc: Amerigo Wang <amwang@redhat.com>
Cc: Joe Korty <joe.korty@ccur.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-05-31 23:26:28 +00:00
|
|
|
static int msg_maxsize_limit_max = HARD_MSGSIZEMAX;
|
2009-04-07 02:01:11 +00:00
|
|
|
|
2014-06-06 21:38:07 +00:00
|
|
|
static struct ctl_table mq_sysctls[] = {
|
2009-04-07 02:01:11 +00:00
|
|
|
{
|
|
|
|
.procname = "queues_max",
|
|
|
|
.data = &init_ipc_ns.mq_queues_max,
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2022-02-14 18:18:14 +00:00
|
|
|
.proc_handler = proc_dointvec,
|
2009-04-07 02:01:11 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "msg_max",
|
|
|
|
.data = &init_ipc_ns.mq_msg_max,
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2022-02-14 18:18:14 +00:00
|
|
|
.proc_handler = proc_dointvec_minmax,
|
2009-04-07 02:01:11 +00:00
|
|
|
.extra1 = &msg_max_limit_min,
|
|
|
|
.extra2 = &msg_max_limit_max,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "msgsize_max",
|
|
|
|
.data = &init_ipc_ns.mq_msgsize_max,
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2022-02-14 18:18:14 +00:00
|
|
|
.proc_handler = proc_dointvec_minmax,
|
2009-04-07 02:01:11 +00:00
|
|
|
.extra1 = &msg_maxsize_limit_min,
|
|
|
|
.extra2 = &msg_maxsize_limit_max,
|
|
|
|
},
|
2012-05-31 23:26:33 +00:00
|
|
|
{
|
|
|
|
.procname = "msg_default",
|
|
|
|
.data = &init_ipc_ns.mq_msg_default,
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2022-02-14 18:18:14 +00:00
|
|
|
.proc_handler = proc_dointvec_minmax,
|
2012-05-31 23:26:33 +00:00
|
|
|
.extra1 = &msg_max_limit_min,
|
|
|
|
.extra2 = &msg_max_limit_max,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.procname = "msgsize_default",
|
|
|
|
.data = &init_ipc_ns.mq_msgsize_default,
|
|
|
|
.maxlen = sizeof(int),
|
|
|
|
.mode = 0644,
|
2022-02-14 18:18:14 +00:00
|
|
|
.proc_handler = proc_dointvec_minmax,
|
2012-05-31 23:26:33 +00:00
|
|
|
.extra1 = &msg_maxsize_limit_min,
|
|
|
|
.extra2 = &msg_maxsize_limit_max,
|
|
|
|
},
|
2009-04-03 09:51:10 +00:00
|
|
|
{}
|
2009-04-07 02:01:11 +00:00
|
|
|
};
|
|
|
|
|
2022-02-14 18:18:14 +00:00
|
|
|
static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
|
|
|
|
{
|
|
|
|
return ¤t->nsproxy->ipc_ns->mq_set;
|
|
|
|
}
|
2009-04-07 02:01:11 +00:00
|
|
|
|
2022-02-14 18:18:14 +00:00
|
|
|
static int set_is_seen(struct ctl_table_set *set)
|
|
|
|
{
|
|
|
|
return ¤t->nsproxy->ipc_ns->mq_set == set;
|
|
|
|
}
|
|
|
|
|
2024-01-15 15:46:43 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-02-14 18:18:14 +00:00
|
|
|
static struct ctl_table_root set_root = {
|
|
|
|
.lookup = set_lookup,
|
2024-01-15 15:46:43 +00:00
|
|
|
.permissions = mq_permissions,
|
|
|
|
.set_ownership = mq_set_ownership,
|
2009-04-07 02:01:11 +00:00
|
|
|
};
|
|
|
|
|
2022-02-14 18:18:14 +00:00
|
|
|
bool setup_mq_sysctls(struct ipc_namespace *ns)
|
2009-04-07 02:01:11 +00:00
|
|
|
{
|
2022-02-14 18:18:14 +00:00
|
|
|
struct ctl_table *tbl;
|
|
|
|
|
|
|
|
setup_sysctl_set(&ns->mq_set, &set_root, set_is_seen);
|
|
|
|
|
|
|
|
tbl = kmemdup(mq_sysctls, sizeof(mq_sysctls), GFP_KERNEL);
|
|
|
|
if (tbl) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mq_sysctls); i++) {
|
|
|
|
if (tbl[i].data == &init_ipc_ns.mq_queues_max)
|
|
|
|
tbl[i].data = &ns->mq_queues_max;
|
|
|
|
|
|
|
|
else if (tbl[i].data == &init_ipc_ns.mq_msg_max)
|
|
|
|
tbl[i].data = &ns->mq_msg_max;
|
|
|
|
|
|
|
|
else if (tbl[i].data == &init_ipc_ns.mq_msgsize_max)
|
|
|
|
tbl[i].data = &ns->mq_msgsize_max;
|
|
|
|
|
|
|
|
else if (tbl[i].data == &init_ipc_ns.mq_msg_default)
|
|
|
|
tbl[i].data = &ns->mq_msg_default;
|
|
|
|
|
|
|
|
else if (tbl[i].data == &init_ipc_ns.mq_msgsize_default)
|
|
|
|
tbl[i].data = &ns->mq_msgsize_default;
|
|
|
|
else
|
|
|
|
tbl[i].data = NULL;
|
|
|
|
}
|
|
|
|
|
2023-08-09 10:49:57 +00:00
|
|
|
ns->mq_sysctls = __register_sysctl_table(&ns->mq_set,
|
|
|
|
"fs/mqueue", tbl,
|
|
|
|
ARRAY_SIZE(mq_sysctls));
|
2022-02-14 18:18:14 +00:00
|
|
|
}
|
|
|
|
if (!ns->mq_sysctls) {
|
|
|
|
kfree(tbl);
|
|
|
|
retire_sysctl_set(&ns->mq_set);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void retire_mq_sysctls(struct ipc_namespace *ns)
|
|
|
|
{
|
|
|
|
struct ctl_table *tbl;
|
|
|
|
|
|
|
|
tbl = ns->mq_sysctls->ctl_table_arg;
|
|
|
|
unregister_sysctl_table(ns->mq_sysctls);
|
|
|
|
retire_sysctl_set(&ns->mq_set);
|
|
|
|
kfree(tbl);
|
2009-04-07 02:01:11 +00:00
|
|
|
}
|