1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2007 IBM Corporation 4 * 5 * Author: Cedric Le Goater <clg@fr.ibm.com> 6 */ 7 8 #include <linux/nsproxy.h> 9 #include <linux/ipc_namespace.h> 10 #include <linux/sysctl.h> 11 12 #include <linux/stat.h> 13 #include <linux/capability.h> 14 #include <linux/slab.h> 15 #include <linux/cred.h> 16 17 static int msg_max_limit_min = MIN_MSGMAX; 18 static int msg_max_limit_max = HARD_MSGMAX; 19 20 static int msg_maxsize_limit_min = MIN_MSGSIZEMAX; 21 static int msg_maxsize_limit_max = HARD_MSGSIZEMAX; 22 23 static struct ctl_table mq_sysctls[] = { 24 { 25 .procname = "queues_max", 26 .data = &init_ipc_ns.mq_queues_max, 27 .maxlen = sizeof(int), 28 .mode = 0644, 29 .proc_handler = proc_dointvec, 30 }, 31 { 32 .procname = "msg_max", 33 .data = &init_ipc_ns.mq_msg_max, 34 .maxlen = sizeof(int), 35 .mode = 0644, 36 .proc_handler = proc_dointvec_minmax, 37 .extra1 = &msg_max_limit_min, 38 .extra2 = &msg_max_limit_max, 39 }, 40 { 41 .procname = "msgsize_max", 42 .data = &init_ipc_ns.mq_msgsize_max, 43 .maxlen = sizeof(int), 44 .mode = 0644, 45 .proc_handler = proc_dointvec_minmax, 46 .extra1 = &msg_maxsize_limit_min, 47 .extra2 = &msg_maxsize_limit_max, 48 }, 49 { 50 .procname = "msg_default", 51 .data = &init_ipc_ns.mq_msg_default, 52 .maxlen = sizeof(int), 53 .mode = 0644, 54 .proc_handler = proc_dointvec_minmax, 55 .extra1 = &msg_max_limit_min, 56 .extra2 = &msg_max_limit_max, 57 }, 58 { 59 .procname = "msgsize_default", 60 .data = &init_ipc_ns.mq_msgsize_default, 61 .maxlen = sizeof(int), 62 .mode = 0644, 63 .proc_handler = proc_dointvec_minmax, 64 .extra1 = &msg_maxsize_limit_min, 65 .extra2 = &msg_maxsize_limit_max, 66 }, 67 }; 68 69 static struct ctl_table_set *set_lookup(struct ctl_table_root *root) 70 { 71 return ¤t->nsproxy->ipc_ns->mq_set; 72 } 73 74 static int set_is_seen(struct ctl_table_set *set) 75 { 76 return ¤t->nsproxy->ipc_ns->mq_set == set; 77 } 78 79 static void mq_set_ownership(struct ctl_table_header *head, 80 kuid_t *uid, kgid_t *gid) 81 { 82 struct ipc_namespace *ns = 83 container_of(head->set, struct ipc_namespace, mq_set); 84 85 kuid_t ns_root_uid = make_kuid(ns->user_ns, 0); 86 kgid_t ns_root_gid = make_kgid(ns->user_ns, 0); 87 88 *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID; 89 *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID; 90 } 91 92 static int mq_permissions(struct ctl_table_header *head, const struct ctl_table *table) 93 { 94 int mode = table->mode; 95 kuid_t ns_root_uid; 96 kgid_t ns_root_gid; 97 98 mq_set_ownership(head, &ns_root_uid, &ns_root_gid); 99 100 if (uid_eq(current_euid(), ns_root_uid)) 101 mode >>= 6; 102 103 else if (in_egroup_p(ns_root_gid)) 104 mode >>= 3; 105 106 mode &= 7; 107 108 return (mode << 6) | (mode << 3) | mode; 109 } 110 111 static struct ctl_table_root set_root = { 112 .lookup = set_lookup, 113 .permissions = mq_permissions, 114 .set_ownership = mq_set_ownership, 115 }; 116 117 bool setup_mq_sysctls(struct ipc_namespace *ns) 118 { 119 struct ctl_table *tbl; 120 121 setup_sysctl_set(&ns->mq_set, &set_root, set_is_seen); 122 123 tbl = kmemdup(mq_sysctls, sizeof(mq_sysctls), GFP_KERNEL); 124 if (tbl) { 125 int i; 126 127 for (i = 0; i < ARRAY_SIZE(mq_sysctls); i++) { 128 if (tbl[i].data == &init_ipc_ns.mq_queues_max) 129 tbl[i].data = &ns->mq_queues_max; 130 131 else if (tbl[i].data == &init_ipc_ns.mq_msg_max) 132 tbl[i].data = &ns->mq_msg_max; 133 134 else if (tbl[i].data == &init_ipc_ns.mq_msgsize_max) 135 tbl[i].data = &ns->mq_msgsize_max; 136 137 else if (tbl[i].data == &init_ipc_ns.mq_msg_default) 138 tbl[i].data = &ns->mq_msg_default; 139 140 else if (tbl[i].data == &init_ipc_ns.mq_msgsize_default) 141 tbl[i].data = &ns->mq_msgsize_default; 142 else 143 tbl[i].data = NULL; 144 } 145 146 ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, 147 "fs/mqueue", tbl, 148 ARRAY_SIZE(mq_sysctls)); 149 } 150 if (!ns->mq_sysctls) { 151 kfree(tbl); 152 retire_sysctl_set(&ns->mq_set); 153 return false; 154 } 155 156 return true; 157 } 158 159 void retire_mq_sysctls(struct ipc_namespace *ns) 160 { 161 const struct ctl_table *tbl; 162 163 tbl = ns->mq_sysctls->ctl_table_arg; 164 unregister_sysctl_table(ns->mq_sysctls); 165 retire_sysctl_set(&ns->mq_set); 166 kfree(tbl); 167 } 168