[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1541432626-27780-4-git-send-email-longman@redhat.com>
Date: Mon, 5 Nov 2018 10:43:45 -0500
From: Waiman Long <longman@...hat.com>
To: "Luis R. Rodriguez" <mcgrof@...nel.org>,
Kees Cook <keescook@...omium.org>,
Andrew Morton <akpm@...ux-foundation.org>,
Jonathan Corbet <corbet@....net>
Cc: linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
linux-doc@...r.kernel.org, Al Viro <viro@...iv.linux.org.uk>,
Matthew Wilcox <willy@...radead.org>,
"Eric W. Biederman" <ebiederm@...ssion.com>,
Takashi Iwai <tiwai@...e.de>, Davidlohr Bueso <dbueso@...e.de>,
Manfred Spraul <manfred@...orfullife.com>,
Waiman Long <longman@...hat.com>
Subject: [PATCH v10 3/4] ipc: Make the new sequence number generation mode available to all
It happens that the new IPC id sequence number inrement mode can be
useful to reduce the chance of IPC id reuse even if the ipcmni_extend
boot command line parameter isn't specified. So a new ipcid_mode sysctl
parameter is added to control the sequence number generation mode -
legacy and delete modes.
In the legacy mode, the sequence number is incremented every time a new
ID is generated. In the delete mode, the number is incremented only if
one or more IDs have been previously deleted. The default is legacy for
non-ipcmni_extend and delete for ipcmni_extend. This new ipcid_mode
parameter is specific to each of the IPC namespaces.
Signed-off-by: Waiman Long <longman@...hat.com>
---
Documentation/sysctl/kernel.txt | 17 +++++++++++++++++
include/linux/ipc_namespace.h | 12 ++++++++++++
ipc/ipc_sysctl.c | 10 ++++++++++
ipc/msg.c | 3 ++-
ipc/namespace.c | 2 ++
ipc/sem.c | 3 ++-
ipc/shm.c | 3 ++-
ipc/util.c | 10 ++++++----
ipc/util.h | 3 ++-
9 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 37a6795..91bada1 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -41,6 +41,7 @@ show up in /proc/sys/kernel:
- hung_task_check_interval_secs
- hung_task_warnings
- hyperv_record_panic_msg
+- ipcid_mode
- kexec_load_disabled
- kptr_restrict
- l2cr [ PPC only ]
@@ -398,6 +399,22 @@ Controls whether the panic kmsg data should be reported to Hyper-V.
==============================================================
+ipcid_mode:
+
+Controls how the IPC ids returned by msgget(), semget() and shmget()
+are being generated.
+
+0: legacy mode
+1: delete mode
+
+There are two components in an IPC id - an integer identifier and a
+sequence number. In the legacy mode, the sequence number is incremented
+every time a new id is generated. In the delete mode, the sequence number
+is only incremented if one or more ids have been previously deleted. The
+delete mode reduces the chance that a given id will be reused again.
+
+==============================================================
+
kexec_load_disabled:
A toggle indicating if the kexec_load syscall has been disabled. This
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index 7d5f553..79d9d50 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -26,6 +26,15 @@ struct ipc_ids {
struct rhashtable key_ht;
};
+/*
+ * IPC id generation mode for controlling how the IPC id returned by
+ * {msg,sem,shm}get() is being generated.
+ */
+enum ipc_id_mode {
+ ipc_id_legacy, /* Sequence # incremented on every allocation */
+ ipc_id_delete, /* Sequence # incremented only if an ID was deleted */
+};
+
struct ipc_namespace {
refcount_t count;
struct ipc_ids ids[3];
@@ -39,6 +48,9 @@ struct ipc_namespace {
atomic_t msg_bytes;
atomic_t msg_hdrs;
+ /* IPC id generation mode */
+ unsigned int ipcid_mode;
+
size_t shm_ctlmax;
size_t shm_ctlall;
unsigned long shm_tot;
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index d9ac6ca..4c30e62 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -200,6 +200,15 @@ static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
.mode = 0644,
.proc_handler = proc_ipc_sem_dointvec,
},
+ {
+ .procname = "ipcid_mode",
+ .data = &init_ipc_ns.ipcid_mode,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_ipc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
#ifdef CONFIG_CHECKPOINT_RESTORE
{
.procname = "sem_next_id",
@@ -254,6 +263,7 @@ static int __init ipc_mni_extend(char *str)
ipc_mni = IPCMNI_EXTEND;
ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
ipc_mni_extended = true;
+ init_ipc_ns.ipcid_mode = ipc_id_delete;
pr_info("IPCMNI extended to %d.\n", ipc_mni);
return 0;
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 0833c64..b401ba2 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -161,7 +161,8 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
INIT_LIST_HEAD(&msq->q_senders);
/* ipc_addid() locks msq upon success. */
- retval = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
+ retval = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni,
+ ns->ipcid_mode);
if (retval < 0) {
ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
return retval;
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 2160779..8b62cbd0 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -55,6 +55,8 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
ns->user_ns = get_user_ns(user_ns);
ns->ucounts = ucounts;
+ ns->ipcid_mode = ipc_mni_extended ? ipc_id_delete : ipc_id_legacy;
+
err = mq_init_ns(ns);
if (err)
goto fail_put;
diff --git a/ipc/sem.c b/ipc/sem.c
index 745dc61..51af634 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -553,7 +553,8 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
sma->sem_ctime = ktime_get_real_seconds();
/* ipc_addid() locks sma upon success. */
- retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+ retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni,
+ ns->ipcid_mode);
if (retval < 0) {
ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
return retval;
diff --git a/ipc/shm.c b/ipc/shm.c
index 0842411..182ae4c 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -676,7 +676,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
shp->shm_creator = current;
/* ipc_addid() locks shp upon success. */
- error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
+ error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni,
+ ns->ipcid_mode);
if (error < 0)
goto no_id;
diff --git a/ipc/util.c b/ipc/util.c
index 6ae0007..04c8e31 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -195,7 +195,8 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
* The caller must own kern_ipc_perm.lock.of the new object.
* On error, the function returns a (negative) error code.
*/
-static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
+static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new,
+ int idmode)
{
int idx, next_id = -1;
@@ -222,7 +223,7 @@ 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 */
- if (!ipc_mni_extended || ids->deleted) {
+ if (idmode == ipc_id_legacy || ids->deleted) {
ids->seq++;
if (ids->seq > IPCID_SEQ_MAX)
ids->seq = 0;
@@ -255,7 +256,8 @@ static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
*
* Called with writer ipc_ids.rwsem held.
*/
-int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
+int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit,
+ int idmode)
{
kuid_t euid;
kgid_t egid;
@@ -282,7 +284,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
new->deleted = false;
- idx = ipc_idr_alloc(ids, new);
+ idx = ipc_idr_alloc(ids, new, idmode);
idr_preload_end();
if (idx >= 0 && new->key != IPC_PRIVATE) {
diff --git a/ipc/util.h b/ipc/util.h
index 1f19729..c8f2d0ed 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -129,7 +129,8 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
#define IPCID_SEQ_MAX (INT_MAX >> IPCMNI_SEQ_SHIFT)
/* must be called with ids->rwsem acquired for writing */
-int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
+int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit,
+ int idmode);
/* must be called with both locks acquired. */
void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
--
1.8.3.1
Powered by blists - more mailing lists