summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWaiman Long <longman@redhat.com>2018-10-30 18:07:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-31 11:54:14 -0400
commit8c81ddd2acd2c10979f5a64f6784ce7c6717495e (patch)
tree753eefd7695e89bd0667bb877123be642c134642
parent6730e6580177d13f4612767873cb5a533ad63c61 (diff)
ipc: IPCMNI limit check for semmni
For SysV semaphores, the semmni value is the last part of the 4-element sem number array. To make semmni behave in a similar way to msgmni and shmmni, we can't directly use the _minmax handler. Instead, a special sem specific handler is added to check the last argument to make sure that it is limited to the [0, IPCMNI] range. An error will be returned if this is not the case. Link: http://lkml.kernel.org/r/1536352137-12003-3-git-send-email-longman@redhat.com Signed-off-by: Waiman Long <longman@redhat.com> Reviewed-by: Davidlohr Bueso <dave@stgolabs.net> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Kees Cook <keescook@chromium.org> Cc: Luis R. Rodriguez <mcgrof@kernel.org> Cc: Matthew Wilcox <willy@infradead.org> Cc: Takashi Iwai <tiwai@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--ipc/ipc_sysctl.c23
-rw-r--r--ipc/util.h9
2 files changed, 31 insertions, 1 deletions
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index f87cb29436ef..49f9bf4ffc7f 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -88,12 +88,33 @@ static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
88 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); 88 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
89} 89}
90 90
91static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
92 void __user *buffer, size_t *lenp, loff_t *ppos)
93{
94 int ret, semmni;
95 struct ipc_namespace *ns = current->nsproxy->ipc_ns;
96
97 semmni = ns->sem_ctls[3];
98 ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
99
100 if (!ret)
101 ret = sem_check_semmni(current->nsproxy->ipc_ns);
102
103 /*
104 * Reset the semmni value if an error happens.
105 */
106 if (ret)
107 ns->sem_ctls[3] = semmni;
108 return ret;
109}
110
91#else 111#else
92#define proc_ipc_doulongvec_minmax NULL 112#define proc_ipc_doulongvec_minmax NULL
93#define proc_ipc_dointvec NULL 113#define proc_ipc_dointvec NULL
94#define proc_ipc_dointvec_minmax NULL 114#define proc_ipc_dointvec_minmax NULL
95#define proc_ipc_dointvec_minmax_orphans NULL 115#define proc_ipc_dointvec_minmax_orphans NULL
96#define proc_ipc_auto_msgmni NULL 116#define proc_ipc_auto_msgmni NULL
117#define proc_ipc_sem_dointvec NULL
97#endif 118#endif
98 119
99static int zero; 120static int zero;
@@ -175,7 +196,7 @@ static struct ctl_table ipc_kern_table[] = {
175 .data = &init_ipc_ns.sem_ctls, 196 .data = &init_ipc_ns.sem_ctls,
176 .maxlen = 4*sizeof(int), 197 .maxlen = 4*sizeof(int),
177 .mode = 0644, 198 .mode = 0644,
178 .proc_handler = proc_ipc_dointvec, 199 .proc_handler = proc_ipc_sem_dointvec,
179 }, 200 },
180#ifdef CONFIG_CHECKPOINT_RESTORE 201#ifdef CONFIG_CHECKPOINT_RESTORE
181 { 202 {
diff --git a/ipc/util.h b/ipc/util.h
index 1ee81bce25e9..d768fdbed515 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -217,6 +217,15 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
217void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, 217void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
218 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)); 218 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
219 219
220static inline int sem_check_semmni(struct ipc_namespace *ns) {
221 /*
222 * Check semmni range [0, IPCMNI]
223 * semmni is the last element of sem_ctls[4] array
224 */
225 return ((ns->sem_ctls[3] < 0) || (ns->sem_ctls[3] > IPCMNI))
226 ? -ERANGE : 0;
227}
228
220#ifdef CONFIG_COMPAT 229#ifdef CONFIG_COMPAT
221#include <linux/compat.h> 230#include <linux/compat.h>
222struct compat_ipc_perm { 231struct compat_ipc_perm {