| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * 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>
- #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;
- static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
- static int msg_maxsize_limit_max = HARD_MSGSIZEMAX;
- static struct ctl_table mq_sysctls[] = {
- {
- .procname = "queues_max",
- .data = &init_ipc_ns.mq_queues_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "msg_max",
- .data = &init_ipc_ns.mq_msg_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .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,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &msg_maxsize_limit_min,
- .extra2 = &msg_maxsize_limit_max,
- },
- {
- .procname = "msg_default",
- .data = &init_ipc_ns.mq_msg_default,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .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,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &msg_maxsize_limit_min,
- .extra2 = &msg_maxsize_limit_max,
- },
- };
- static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
- {
- return ¤t->nsproxy->ipc_ns->mq_set;
- }
- 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,
- 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, const struct ctl_table *table)
- {
- int mode = table->mode;
- kuid_t ns_root_uid;
- kgid_t ns_root_gid;
- mq_set_ownership(head, &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)
- {
- 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;
- }
- ns->mq_sysctls = __register_sysctl_table(&ns->mq_set,
- "fs/mqueue", tbl,
- ARRAY_SIZE(mq_sysctls));
- }
- if (!ns->mq_sysctls) {
- kfree(tbl);
- retire_sysctl_set(&ns->mq_set);
- return false;
- }
- return true;
- }
- void retire_mq_sysctls(struct ipc_namespace *ns)
- {
- const 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);
- }
|