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