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 16 static int msg_max_limit_min = MIN_MSGMAX; 17 static int msg_max_limit_max = HARD_MSGMAX; 18 19 static int msg_maxsize_limit_min = MIN_MSGSIZEMAX; 20 static int msg_maxsize_limit_max = HARD_MSGSIZEMAX; 21 22 static struct ctl_table mq_sysctls[] = { 23 { 24 .procname = "queues_max", 25 .data = &init_ipc_ns.mq_queues_max, 26 .maxlen = sizeof(int), 27 .mode = 0644, 28 .proc_handler = proc_dointvec, 29 }, 30 { 31 .procname = "msg_max", 32 .data = &init_ipc_ns.mq_msg_max, 33 .maxlen = sizeof(int), 34 .mode = 0644, 35 .proc_handler = proc_dointvec_minmax, 36 .extra1 = &msg_max_limit_min, 37 .extra2 = &msg_max_limit_max, 38 }, 39 { 40 .procname = "msgsize_max", 41 .data = &init_ipc_ns.mq_msgsize_max, 42 .maxlen = sizeof(int), 43 .mode = 0644, 44 .proc_handler = proc_dointvec_minmax, 45 .extra1 = &msg_maxsize_limit_min, 46 .extra2 = &msg_maxsize_limit_max, 47 }, 48 { 49 .procname = "msg_default", 50 .data = &init_ipc_ns.mq_msg_default, 51 .maxlen = sizeof(int), 52 .mode = 0644, 53 .proc_handler = proc_dointvec_minmax, 54 .extra1 = &msg_max_limit_min, 55 .extra2 = &msg_max_limit_max, 56 }, 57 { 58 .procname = "msgsize_default", 59 .data = &init_ipc_ns.mq_msgsize_default, 60 .maxlen = sizeof(int), 61 .mode = 0644, 62 .proc_handler = proc_dointvec_minmax, 63 .extra1 = &msg_maxsize_limit_min, 64 .extra2 = &msg_maxsize_limit_max, 65 }, 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 struct ctl_table_root set_root = { 80 .lookup = set_lookup, 81 }; 82 83 bool setup_mq_sysctls(struct ipc_namespace *ns) 84 { 85 struct ctl_table *tbl; 86 87 setup_sysctl_set(&ns->mq_set, &set_root, set_is_seen); 88 89 tbl = kmemdup(mq_sysctls, sizeof(mq_sysctls), GFP_KERNEL); 90 if (tbl) { 91 int i; 92 93 for (i = 0; i < ARRAY_SIZE(mq_sysctls); i++) { 94 if (tbl[i].data == &init_ipc_ns.mq_queues_max) 95 tbl[i].data = &ns->mq_queues_max; 96 97 else if (tbl[i].data == &init_ipc_ns.mq_msg_max) 98 tbl[i].data = &ns->mq_msg_max; 99 100 else if (tbl[i].data == &init_ipc_ns.mq_msgsize_max) 101 tbl[i].data = &ns->mq_msgsize_max; 102 103 else if (tbl[i].data == &init_ipc_ns.mq_msg_default) 104 tbl[i].data = &ns->mq_msg_default; 105 106 else if (tbl[i].data == &init_ipc_ns.mq_msgsize_default) 107 tbl[i].data = &ns->mq_msgsize_default; 108 else 109 tbl[i].data = NULL; 110 } 111 112 ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, 113 "fs/mqueue", tbl, 114 ARRAY_SIZE(mq_sysctls)); 115 } 116 if (!ns->mq_sysctls) { 117 kfree(tbl); 118 retire_sysctl_set(&ns->mq_set); 119 return false; 120 } 121 122 return true; 123 } 124 125 void retire_mq_sysctls(struct ipc_namespace *ns) 126 { 127 struct ctl_table *tbl; 128 129 tbl = ns->mq_sysctls->ctl_table_arg; 130 unregister_sysctl_table(ns->mq_sysctls); 131 retire_sysctl_set(&ns->mq_set); 132 kfree(tbl); 133 } 134