From: Davidlohr Bueso <d...@stgolabs.net>

In sysvipc we have an ids->tables_initialized regarding the
rhashtable, introduced in:

commit 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.

Signed-off-by: Davidlohr Bueso <dbu...@suse.de>

(commit id extended to 12 digits)
Signed-off-by: Manfred Spraul <manf...@colorfullife.com>
---
 include/linux/ipc_namespace.h |  1 -
 ipc/util.c                    | 23 ++++++++---------------
 2 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index b5630c8eb2f3..37f3a4b7c637 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -16,7 +16,6 @@ struct user_namespace;
 struct ipc_ids {
        int in_use;
        unsigned short seq;
-       bool tables_initialized;
        struct rw_semaphore rwsem;
        struct idr ipcs_idr;
        int max_id;
diff --git a/ipc/util.c b/ipc/util.c
index a41b8a69de13..ae485b41ea0b 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -125,7 +125,6 @@ int ipc_init_ids(struct ipc_ids *ids)
        if (err)
                return err;
        idr_init(&ids->ipcs_idr);
-       ids->tables_initialized = true;
        ids->max_id = -1;
 #ifdef CONFIG_CHECKPOINT_RESTORE
        ids->next_id = -1;
@@ -178,19 +177,16 @@ void __init ipc_init_proc_interface(const char *path, 
const char *header,
  */
 static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
 {
-       struct kern_ipc_perm *ipcp = NULL;
+       struct kern_ipc_perm *ipcp;
 
-       if (likely(ids->tables_initialized))
-               ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
+       ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
                                              ipc_kht_params);
+       if (!ipcp)
+               return NULL;
 
-       if (ipcp) {
-               rcu_read_lock();
-               ipc_lock_object(ipcp);
-               return ipcp;
-       }
-
-       return NULL;
+       rcu_read_lock();
+       ipc_lock_object(ipcp);
+       return ipcp;
 }
 
 /*
@@ -246,7 +242,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm 
*new, int limit)
        if (limit > IPCMNI)
                limit = IPCMNI;
 
-       if (!ids->tables_initialized || ids->in_use >= limit)
+       if (ids->in_use >= limit)
                return -ENOSPC;
 
        idr_preload(GFP_KERNEL);
@@ -568,9 +564,6 @@ struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids 
*ids, int id)
        struct kern_ipc_perm *out;
        int lid = ipcid_to_idx(id);
 
-       if (unlikely(!ids->tables_initialized))
-               return ERR_PTR(-EINVAL);
-
        out = idr_find(&ids->ipcs_idr, lid);
        if (!out)
                return ERR_PTR(-EINVAL);
-- 
2.17.1

Reply via email to