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 70 static struct ctl_table_set *set_lookup(struct ctl_table_root *root) 71 { 72 return ¤t->nsproxy->ipc_ns->mq_set; 73 } 74 75 static int set_is_seen(struct ctl_table_set *set) 76 { 77 return ¤t->nsproxy->ipc_ns->mq_set == set; 78 } 79 80 static void mq_set_ownership(struct ctl_table_header *head, 81 struct ctl_table *table, 82 kuid_t *uid, kgid_t *gid) 83 { 84 struct ipc_namespace *ns = 85 container_of(head->set, struct ipc_namespace, mq_set); 86 87 kuid_t ns_root_uid = make_kuid(ns->user_ns, 0); 88 kgid_t ns_root_gid = make_kgid(ns->user_ns, 0); 89 90 *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID; 91 *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID; 92 } 93 94 static int mq_permissions(struct ctl_table_header *head, struct ctl_table *table) 95 { 96 int mode = table->mode; 97 kuid_t ns_root_uid; 98 kgid_t ns_root_gid; 99 100 mq_set_ownership(head, table, &ns_root_uid, &ns_root_gid); 101 102 if (uid_eq(current_euid(), ns_root_uid)) 103 mode >>= 6; 104 105 else if (in_egroup_p(ns_root_gid)) 106 mode >>= 3; 107 108 mode &= 7; 109 110 return (mode << 6) | (mode << 3) | mode; 111 } 112 113 static struct ctl_table_root set_root = { 114 .lookup = set_lookup, 115 .permissions = mq_permissions, 116 .set_ownership = mq_set_ownership, 117 }; 118 119 bool setup_mq_sysctls(struct ipc_namespace *ns) 120 { 121 struct ctl_table *tbl; 122 123 setup_sysctl_set(&ns->mq_set, &set_root, set_is_seen); 124 125 tbl = kmemdup(mq_sysctls, sizeof(mq_sysctls), GFP_KERNEL); 126 if (tbl) { 127 int i; 128 129 for (i = 0; i < ARRAY_SIZE(mq_sysctls); i++) { 130 if (tbl[i].data == &init_ipc_ns.mq_queues_max) 131 tbl[i].data = &ns->mq_queues_max; 132 133 else if (tbl[i].data == &init_ipc_ns.mq_msg_max) 134 tbl[i].data = &ns->mq_msg_max; 135 136 else if (tbl[i].data == &init_ipc_ns.mq_msgsize_max) 137 tbl[i].data = &ns->mq_msgsize_max; 138 139 else if (tbl[i].data == &init_ipc_ns.mq_msg_default) 140 tbl[i].data = &ns->mq_msg_default; 141 142 else if (tbl[i].data == &init_ipc_ns.mq_msgsize_default) 143 tbl[i].data = &ns->mq_msgsize_default; 144 else 145 tbl[i].data = NULL; 146 } 147 148 ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, 149 "fs/mqueue", tbl, 150 ARRAY_SIZE(mq_sysctls)); 151 } 152 if (!ns->mq_sysctls) { 153 kfree(tbl); 154 retire_sysctl_set(&ns->mq_set); 155 return false; 156 } 157 158 return true; 159 } 160 161 void retire_mq_sysctls(struct ipc_namespace *ns) 162 { 163 const struct ctl_table *tbl; 164 165 tbl = ns->mq_sysctls->ctl_table_arg; 166 unregister_sysctl_table(ns->mq_sysctls); 167 retire_sysctl_set(&ns->mq_set); 168 kfree(tbl); 169 } 170