]> www.infradead.org Git - users/willy/linux.git/commitdiff
ipc: conserve sequence numbers in extended IPCMNI mode
authorWaiman Long <longman@redhat.com>
Wed, 5 Dec 2018 00:14:14 +0000 (11:14 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 6 Dec 2018 22:09:12 +0000 (09:09 +1100)
The mixing in of a sequence number into the IPC IDs is probably to avoid
ID reuse in userspace as much as possible.  With extended IPCMNI mode, the
number of usable sequence numbers is greatly reduced leading to higher
chance of ID reuse.

To address this issue, we need to conserve the sequence number space as
much as possible.  Right now, the sequence number is incremented for every
new ID created.  In reality, we only need to increment the sequence number
when one or more IDs have been removed previously to make sure that those
IDs will not be reused when a new one is built.  This is being done only
in the new extended IPCMNI mode.

Link: http://lkml.kernel.org/r/1536352137-12003-5-git-send-email-longman@redhat.com
Signed-off-by: Waiman Long <longman@redhat.com>
Cc: 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: Stephen Rothwell <sfr@canb.auug.org.au>
include/linux/ipc_namespace.h
ipc/ipc_sysctl.c
ipc/util.c
ipc/util.h

index 6ab8c1bada3fccb11119f93130b1989ddb090ad3..7d5f553a3b2453d39fba8d3b671306fef291e09e 100644 (file)
@@ -16,6 +16,7 @@ struct user_namespace;
 struct ipc_ids {
        int in_use;
        unsigned short seq;
+       unsigned short deleted;
        struct rw_semaphore rwsem;
        struct idr ipcs_idr;
        int max_idx;
index 73b7782eccf48928fb5b8b6106538a751f295a0b..d9ac6caf6a5e7e1af5b3c738b8923498bea23cfe 100644 (file)
@@ -122,6 +122,7 @@ static int one = 1;
 static int int_max = INT_MAX;
 int ipc_mni = IPCMNI;
 int ipc_mni_shift = IPCMNI_SHIFT;
+bool ipc_mni_extended;
 
 static struct ctl_table ipc_kern_table[] = {
        {
@@ -252,6 +253,7 @@ static int __init ipc_mni_extend(char *str)
 {
        ipc_mni = IPCMNI_EXTEND;
        ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
+       ipc_mni_extended = true;
        pr_info("IPCMNI extended to %d.\n", ipc_mni);
        return 0;
 }
index 07ae117ccdc094d97c21685d1a1dd876cc6328a3..3f11a81cf9b76a37a6a3d20cb1c9cbfa0fbb5ee5 100644 (file)
@@ -115,7 +115,8 @@ static const struct rhashtable_params ipc_kht_params = {
 void ipc_init_ids(struct ipc_ids *ids)
 {
        ids->in_use = 0;
-       ids->seq = 0;
+       ids->deleted = false;
+       ids->seq = ipc_mni_extended ? 0 : -1; /* seq # is pre-incremented */
        init_rwsem(&ids->rwsem);
        rhashtable_init(&ids->key_ht, &ipc_kht_params);
        idr_init(&ids->ipcs_idr);
@@ -198,6 +199,11 @@ static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
 {
        int idx, next_id = -1;
 
+/*
+ * To conserve sequence number space with extended ipc_mni when new ID
+ * is built, the sequence number is incremented only when one or more
+ * IDs have been removed previously.
+ */
 #ifdef CONFIG_CHECKPOINT_RESTORE
        next_id = ids->next_id;
        ids->next_id = -1;
@@ -216,9 +222,13 @@ static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
         */
 
        if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */
-               new->seq = ids->seq++;
-               if (ids->seq > IPCID_SEQ_MAX)
-                       ids->seq = 0;
+               if (!ipc_mni_extended || ids->deleted) {
+                       ids->seq++;
+                       if (ids->seq > IPCID_SEQ_MAX)
+                               ids->seq = 0;
+                       ids->deleted = false;
+               }
+               new->seq = ids->seq;
                idx = idr_alloc(&ids->ipcs_idr, new, 0, 0, GFP_NOWAIT);
        } else {
                new->seq = ipcid_to_seqx(next_id);
@@ -436,6 +446,7 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
        idr_remove(&ids->ipcs_idr, idx);
        ipc_kht_remove(ids, ipcp);
        ids->in_use--;
+       ids->deleted = true;
        ipcp->deleted = true;
 
        if (unlikely(idx == ids->max_idx)) {
index 644df117852ce2bff81a7500342075b673d6cd93..127c0fedbd094dba33d5cc2fd0592da59d0d8ea0 100644 (file)
@@ -33,6 +33,7 @@
 #ifdef CONFIG_SYSVIPC_SYSCTL
 extern int ipc_mni;
 extern int ipc_mni_shift;
+extern bool ipc_mni_extended;
 
 #define IPCMNI_SEQ_SHIFT       ipc_mni_shift
 #define IPCMNI_IDX_MASK                ((1 << ipc_mni_shift) - 1)
@@ -40,6 +41,7 @@ extern int ipc_mni_shift;
 #else /* CONFIG_SYSVIPC_SYSCTL */
 
 #define ipc_mni                        IPCMNI
+#define ipc_mni_extended       false
 #define IPCMNI_SEQ_SHIFT       IPCMNI_SHIFT
 #define IPCMNI_IDX_MASK                ((1 << IPCMNI_SHIFT) - 1)
 #endif /* CONFIG_SYSVIPC_SYSCTL */