summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2018-08-22 01:01:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-22 13:52:52 -0400
commitdc2c8c84def6ce450c63529e08c1db100020994e (patch)
tree61309e8b4d24ac8caaaafdb2fee262998688dcb8
parent2d22ecf6db1c390974476758681ba4229018e774 (diff)
ipc: get rid of ids->tables_initialized hack
In sysvipc we have an ids->tables_initialized regarding the rhashtable, introduced in 0cfb6aee70bd ("ipc: optimize semget/shmget/msgget for lots of keys") It's there, specifically, to prevent nil pointer dereferences, from using an uninitialized api. Considering how rhashtable_init() can fail (probably due to ENOMEM, if anything), this made the overall ipc initialization capable of failure as well. That alone is ugly, but fine, however I've spotted a few issues regarding the semantics of tables_initialized (however unlikely they may be): - There is inconsistency in what we return to userspace: ipc_addid() returns ENOSPC which is certainly _wrong_, while ipc_obtain_object_idr() returns EINVAL. - After we started using rhashtables, ipc_findkey() can return nil upon !tables_initialized, but the caller expects nil for when the ipc structure isn't found, and can therefore call into ipcget() callbacks. Now that rhashtable initialization cannot fail, we can properly get rid of the hack altogether. [manfred@colorfullife.com: commit id extended to 12 digits] Link: http://lkml.kernel.org/r/20180712185241.4017-10-manfred@colorfullife.com Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Signed-off-by: Manfred Spraul <manfred@colorfullife.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Kees Cook <keescook@chromium.org> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Michal Hocko <mhocko@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/ipc_namespace.h1
-rw-r--r--ipc/util.c23
2 files changed, 8 insertions, 16 deletions
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index 6cea726612b7..e9ccdfdb1928 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -16,7 +16,6 @@ struct user_namespace;
16struct ipc_ids { 16struct ipc_ids {
17 int in_use; 17 int in_use;
18 unsigned short seq; 18 unsigned short seq;
19 bool tables_initialized;
20 struct rw_semaphore rwsem; 19 struct rw_semaphore rwsem;
21 struct idr ipcs_idr; 20 struct idr ipcs_idr;
22 int max_id; 21 int max_id;
diff --git a/ipc/util.c b/ipc/util.c
index bd1863b6ed39..7c1387c9510d 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -126,7 +126,6 @@ int ipc_init_ids(struct ipc_ids *ids)
126 if (err) 126 if (err)
127 return err; 127 return err;
128 idr_init(&ids->ipcs_idr); 128 idr_init(&ids->ipcs_idr);
129 ids->tables_initialized = true;
130 ids->max_id = -1; 129 ids->max_id = -1;
131#ifdef CONFIG_CHECKPOINT_RESTORE 130#ifdef CONFIG_CHECKPOINT_RESTORE
132 ids->next_id = -1; 131 ids->next_id = -1;
@@ -179,19 +178,16 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
179 */ 178 */
180static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) 179static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
181{ 180{
182 struct kern_ipc_perm *ipcp = NULL; 181 struct kern_ipc_perm *ipcp;
183 182
184 if (likely(ids->tables_initialized)) 183 ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
185 ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
186 ipc_kht_params); 184 ipc_kht_params);
185 if (!ipcp)
186 return NULL;
187 187
188 if (ipcp) { 188 rcu_read_lock();
189 rcu_read_lock(); 189 ipc_lock_object(ipcp);
190 ipc_lock_object(ipcp); 190 return ipcp;
191 return ipcp;
192 }
193
194 return NULL;
195} 191}
196 192
197/* 193/*
@@ -269,7 +265,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
269 if (limit > IPCMNI) 265 if (limit > IPCMNI)
270 limit = IPCMNI; 266 limit = IPCMNI;
271 267
272 if (!ids->tables_initialized || ids->in_use >= limit) 268 if (ids->in_use >= limit)
273 return -ENOSPC; 269 return -ENOSPC;
274 270
275 idr_preload(GFP_KERNEL); 271 idr_preload(GFP_KERNEL);
@@ -578,9 +574,6 @@ struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id)
578 struct kern_ipc_perm *out; 574 struct kern_ipc_perm *out;
579 int lid = ipcid_to_idx(id); 575 int lid = ipcid_to_idx(id);
580 576
581 if (unlikely(!ids->tables_initialized))
582 return ERR_PTR(-EINVAL);
583
584 out = idr_find(&ids->ipcs_idr, lid); 577 out = idr_find(&ids->ipcs_idr, lid);
585 if (!out) 578 if (!out)
586 return ERR_PTR(-EINVAL); 579 return ERR_PTR(-EINVAL);