Skip to content

Commit dc55e35

Browse files
legionusebiederm
authored andcommitted
ipc: Store mqueue sysctls in the ipc namespace
Right now, the mqueue sysctls take ipc namespaces into account in a rather hacky way. This works in most cases, but does not respect the user namespace. Within the user namespace, the user cannot change the /proc/sys/fs/mqueue/* parametres. This poses a problem in the rootless containers. To solve this I changed the implementation of the mqueue sysctls just like some other sysctls. So far, the changes do not provide additional access to files. This will be done in a future patch. v3: * Don't implemenet set_permissions to keep the current behavior. v2: * Fixed compilation problem if CONFIG_POSIX_MQUEUE_SYSCTL is not specified. Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Alexey Gladkov <legion@kernel.org> Link: https://lkml.kernel.org/r/b0ccbb2489119f1f20c737cf1930c3a9c4e4243a.1644862280.git.legion@kernel.org Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
1 parent ffb217a commit dc55e35

File tree

4 files changed

+88
-65
lines changed

4 files changed

+88
-65
lines changed

include/linux/ipc_namespace.h

+12-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/ns_common.h>
1111
#include <linux/refcount.h>
1212
#include <linux/rhashtable-types.h>
13+
#include <linux/sysctl.h>
1314

1415
struct user_namespace;
1516

@@ -63,6 +64,9 @@ struct ipc_namespace {
6364
unsigned int mq_msg_default;
6465
unsigned int mq_msgsize_default;
6566

67+
struct ctl_table_set mq_set;
68+
struct ctl_table_header *mq_sysctls;
69+
6670
/* user_ns which owns the ipc ns */
6771
struct user_namespace *user_ns;
6872
struct ucounts *ucounts;
@@ -169,14 +173,18 @@ static inline void put_ipc_ns(struct ipc_namespace *ns)
169173

170174
#ifdef CONFIG_POSIX_MQUEUE_SYSCTL
171175

172-
struct ctl_table_header;
173-
extern struct ctl_table_header *mq_register_sysctl_table(void);
176+
void retire_mq_sysctls(struct ipc_namespace *ns);
177+
bool setup_mq_sysctls(struct ipc_namespace *ns);
174178

175179
#else /* CONFIG_POSIX_MQUEUE_SYSCTL */
176180

177-
static inline struct ctl_table_header *mq_register_sysctl_table(void)
181+
static inline void retire_mq_sysctls(struct ipc_namespace *ns)
178182
{
179-
return NULL;
183+
}
184+
185+
static inline bool setup_mq_sysctls(struct ipc_namespace *ns)
186+
{
187+
return true;
180188
}
181189

182190
#endif /* CONFIG_POSIX_MQUEUE_SYSCTL */

ipc/mq_sysctl.c

+66-55
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,9 @@
99
#include <linux/ipc_namespace.h>
1010
#include <linux/sysctl.h>
1111

12-
#ifdef CONFIG_PROC_SYSCTL
13-
static void *get_mq(struct ctl_table *table)
14-
{
15-
char *which = table->data;
16-
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
17-
which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
18-
return which;
19-
}
20-
21-
static int proc_mq_dointvec(struct ctl_table *table, int write,
22-
void *buffer, size_t *lenp, loff_t *ppos)
23-
{
24-
struct ctl_table mq_table;
25-
memcpy(&mq_table, table, sizeof(mq_table));
26-
mq_table.data = get_mq(table);
27-
28-
return proc_dointvec(&mq_table, write, buffer, lenp, ppos);
29-
}
30-
31-
static int proc_mq_dointvec_minmax(struct ctl_table *table, int write,
32-
void *buffer, size_t *lenp, loff_t *ppos)
33-
{
34-
struct ctl_table mq_table;
35-
memcpy(&mq_table, table, sizeof(mq_table));
36-
mq_table.data = get_mq(table);
37-
38-
return proc_dointvec_minmax(&mq_table, write, buffer,
39-
lenp, ppos);
40-
}
41-
#else
42-
#define proc_mq_dointvec NULL
43-
#define proc_mq_dointvec_minmax NULL
44-
#endif
12+
#include <linux/stat.h>
13+
#include <linux/capability.h>
14+
#include <linux/slab.h>
4515

4616
static int msg_max_limit_min = MIN_MSGMAX;
4717
static int msg_max_limit_max = HARD_MSGMAX;
@@ -55,14 +25,14 @@ static struct ctl_table mq_sysctls[] = {
5525
.data = &init_ipc_ns.mq_queues_max,
5626
.maxlen = sizeof(int),
5727
.mode = 0644,
58-
.proc_handler = proc_mq_dointvec,
28+
.proc_handler = proc_dointvec,
5929
},
6030
{
6131
.procname = "msg_max",
6232
.data = &init_ipc_ns.mq_msg_max,
6333
.maxlen = sizeof(int),
6434
.mode = 0644,
65-
.proc_handler = proc_mq_dointvec_minmax,
35+
.proc_handler = proc_dointvec_minmax,
6636
.extra1 = &msg_max_limit_min,
6737
.extra2 = &msg_max_limit_max,
6838
},
@@ -71,7 +41,7 @@ static struct ctl_table mq_sysctls[] = {
7141
.data = &init_ipc_ns.mq_msgsize_max,
7242
.maxlen = sizeof(int),
7343
.mode = 0644,
74-
.proc_handler = proc_mq_dointvec_minmax,
44+
.proc_handler = proc_dointvec_minmax,
7545
.extra1 = &msg_maxsize_limit_min,
7646
.extra2 = &msg_maxsize_limit_max,
7747
},
@@ -80,7 +50,7 @@ static struct ctl_table mq_sysctls[] = {
8050
.data = &init_ipc_ns.mq_msg_default,
8151
.maxlen = sizeof(int),
8252
.mode = 0644,
83-
.proc_handler = proc_mq_dointvec_minmax,
53+
.proc_handler = proc_dointvec_minmax,
8454
.extra1 = &msg_max_limit_min,
8555
.extra2 = &msg_max_limit_max,
8656
},
@@ -89,32 +59,73 @@ static struct ctl_table mq_sysctls[] = {
8959
.data = &init_ipc_ns.mq_msgsize_default,
9060
.maxlen = sizeof(int),
9161
.mode = 0644,
92-
.proc_handler = proc_mq_dointvec_minmax,
62+
.proc_handler = proc_dointvec_minmax,
9363
.extra1 = &msg_maxsize_limit_min,
9464
.extra2 = &msg_maxsize_limit_max,
9565
},
9666
{}
9767
};
9868

99-
static struct ctl_table mq_sysctl_dir[] = {
100-
{
101-
.procname = "mqueue",
102-
.mode = 0555,
103-
.child = mq_sysctls,
104-
},
105-
{}
106-
};
69+
static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
70+
{
71+
return &current->nsproxy->ipc_ns->mq_set;
72+
}
10773

108-
static struct ctl_table mq_sysctl_root[] = {
109-
{
110-
.procname = "fs",
111-
.mode = 0555,
112-
.child = mq_sysctl_dir,
113-
},
114-
{}
74+
static int set_is_seen(struct ctl_table_set *set)
75+
{
76+
return &current->nsproxy->ipc_ns->mq_set == set;
77+
}
78+
79+
static struct ctl_table_root set_root = {
80+
.lookup = set_lookup,
11581
};
11682

117-
struct ctl_table_header *mq_register_sysctl_table(void)
83+
bool setup_mq_sysctls(struct ipc_namespace *ns)
11884
{
119-
return register_sysctl_table(mq_sysctl_root);
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, "fs/mqueue", tbl);
113+
}
114+
if (!ns->mq_sysctls) {
115+
kfree(tbl);
116+
retire_sysctl_set(&ns->mq_set);
117+
return false;
118+
}
119+
120+
return true;
121+
}
122+
123+
void retire_mq_sysctls(struct ipc_namespace *ns)
124+
{
125+
struct ctl_table *tbl;
126+
127+
tbl = ns->mq_sysctls->ctl_table_arg;
128+
unregister_sysctl_table(ns->mq_sysctls);
129+
retire_sysctl_set(&ns->mq_set);
130+
kfree(tbl);
120131
}

ipc/mqueue.c

+4-6
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,6 @@ static void remove_notification(struct mqueue_inode_info *info);
163163

164164
static struct kmem_cache *mqueue_inode_cachep;
165165

166-
static struct ctl_table_header *mq_sysctl_table;
167-
168166
static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
169167
{
170168
return container_of(inode, struct mqueue_inode_info, vfs_inode);
@@ -1713,8 +1711,10 @@ static int __init init_mqueue_fs(void)
17131711
if (mqueue_inode_cachep == NULL)
17141712
return -ENOMEM;
17151713

1716-
/* ignore failures - they are not fatal */
1717-
mq_sysctl_table = mq_register_sysctl_table();
1714+
if (!setup_mq_sysctls(&init_ipc_ns)) {
1715+
pr_warn("sysctl registration failed\n");
1716+
return -ENOMEM;
1717+
}
17181718

17191719
error = register_filesystem(&mqueue_fs_type);
17201720
if (error)
@@ -1731,8 +1731,6 @@ static int __init init_mqueue_fs(void)
17311731
out_filesystem:
17321732
unregister_filesystem(&mqueue_fs_type);
17331733
out_sysctl:
1734-
if (mq_sysctl_table)
1735-
unregister_sysctl_table(mq_sysctl_table);
17361734
kmem_cache_destroy(mqueue_inode_cachep);
17371735
return error;
17381736
}

ipc/namespace.c

+6
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
5959
if (err)
6060
goto fail_put;
6161

62+
err = -ENOMEM;
63+
if (!setup_mq_sysctls(ns))
64+
goto fail_put;
65+
6266
sem_init_ns(ns);
6367
msg_init_ns(ns);
6468
shm_init_ns(ns);
@@ -125,6 +129,8 @@ static void free_ipc_ns(struct ipc_namespace *ns)
125129
msg_exit_ns(ns);
126130
shm_exit_ns(ns);
127131

132+
retire_mq_sysctls(ns);
133+
128134
dec_ipc_namespaces(ns->ucounts);
129135
put_user_ns(ns->user_ns);
130136
ns_free_inum(&ns->ns);

0 commit comments

Comments
 (0)