From 9b24fef9f0410fb5364245d6cc2bd044cc064007 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 2 Aug 2016 14:03:07 -0700 Subject: sysv, ipc: fix security-layer leaking Commit 53dad6d3a8e5 ("ipc: fix race with LSMs") updated ipc_rcu_putref() to receive rcu freeing function but used generic ipc_rcu_free() instead of msg_rcu_free() which does security cleaning. Running LTP msgsnd06 with kmemleak gives the following: cat /sys/kernel/debug/kmemleak unreferenced object 0xffff88003c0a11f8 (size 8): comm "msgsnd06", pid 1645, jiffies 4294672526 (age 6.549s) hex dump (first 8 bytes): 1b 00 00 00 01 00 00 00 ........ backtrace: kmemleak_alloc+0x23/0x40 kmem_cache_alloc_trace+0xe1/0x180 selinux_msg_queue_alloc_security+0x3f/0xd0 security_msg_queue_alloc+0x2e/0x40 newque+0x4e/0x150 ipcget+0x159/0x1b0 SyS_msgget+0x39/0x40 entry_SYSCALL_64_fastpath+0x13/0x8f Manfred Spraul suggested to fix sem.c as well and Davidlohr Bueso to only use ipc_rcu_free in case of security allocation failure in newary() Fixes: 53dad6d3a8e ("ipc: fix race with LSMs") Link: http://lkml.kernel.org/r/1470083552-22966-1-git-send-email-fabf@skynet.be Signed-off-by: Fabian Frederick Cc: Davidlohr Bueso Cc: Manfred Spraul Cc: [3.12+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 2 +- ipc/sem.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'ipc') diff --git a/ipc/msg.c b/ipc/msg.c index 1471db9a7e61..c6521c205cb4 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -680,7 +680,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, rcu_read_lock(); ipc_lock_object(&msq->q_perm); - ipc_rcu_putref(msq, ipc_rcu_free); + ipc_rcu_putref(msq, msg_rcu_free); /* raced with RMID? */ if (!ipc_valid_object(&msq->q_perm)) { err = -EIDRM; diff --git a/ipc/sem.c b/ipc/sem.c index ae72b3cddc8d..7c9d4f7683c0 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -438,7 +438,7 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns static inline void sem_lock_and_putref(struct sem_array *sma) { sem_lock(sma, NULL, -1); - ipc_rcu_putref(sma, ipc_rcu_free); + ipc_rcu_putref(sma, sem_rcu_free); } static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) @@ -1381,7 +1381,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, rcu_read_unlock(); sem_io = ipc_alloc(sizeof(ushort)*nsems); if (sem_io == NULL) { - ipc_rcu_putref(sma, ipc_rcu_free); + ipc_rcu_putref(sma, sem_rcu_free); return -ENOMEM; } @@ -1415,20 +1415,20 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, if (nsems > SEMMSL_FAST) { sem_io = ipc_alloc(sizeof(ushort)*nsems); if (sem_io == NULL) { - ipc_rcu_putref(sma, ipc_rcu_free); + ipc_rcu_putref(sma, sem_rcu_free); return -ENOMEM; } } if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) { - ipc_rcu_putref(sma, ipc_rcu_free); + ipc_rcu_putref(sma, sem_rcu_free); err = -EFAULT; goto out_free; } for (i = 0; i < nsems; i++) { if (sem_io[i] > SEMVMX) { - ipc_rcu_putref(sma, ipc_rcu_free); + ipc_rcu_putref(sma, sem_rcu_free); err = -ERANGE; goto out_free; } @@ -1720,7 +1720,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) /* step 2: allocate new undo structure */ new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); if (!new) { - ipc_rcu_putref(sma, ipc_rcu_free); + ipc_rcu_putref(sma, sem_rcu_free); return ERR_PTR(-ENOMEM); } -- cgit v1.2.3 From 3bd080e4d8f2351ee3e143f0ec9307cc95ae6639 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 2 Aug 2016 14:07:32 -0700 Subject: ipc: delete "nr_ipc_ns" Write-only variable. Link: http://lkml.kernel.org/r/20160708214356.GA6785@p183.telecom.by Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ipc_namespace.h | 2 -- ipc/msgutil.c | 2 -- ipc/namespace.c | 2 -- 3 files changed, 6 deletions(-) (limited to 'ipc') diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index 1eee6bcfcf76..d10e54f03c09 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h @@ -63,8 +63,6 @@ struct ipc_namespace { }; extern struct ipc_namespace init_ipc_ns; -extern atomic_t nr_ipc_ns; - extern spinlock_t mq_lock; #ifdef CONFIG_SYSVIPC diff --git a/ipc/msgutil.c b/ipc/msgutil.c index ed81aafd2392..a521999de4f1 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -37,8 +37,6 @@ struct ipc_namespace init_ipc_ns = { #endif }; -atomic_t nr_ipc_ns = ATOMIC_INIT(1); - struct msg_msgseg { struct msg_msgseg *next; /* the next part of the message follows immediately */ diff --git a/ipc/namespace.c b/ipc/namespace.c index 04cb07eb81f1..d87e6baa1323 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -43,7 +43,6 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, kfree(ns); return ERR_PTR(err); } - atomic_inc(&nr_ipc_ns); sem_init_ns(ns); msg_init_ns(ns); @@ -96,7 +95,6 @@ static void free_ipc_ns(struct ipc_namespace *ns) sem_exit_ns(ns); msg_exit_ns(ns); shm_exit_ns(ns); - atomic_dec(&nr_ipc_ns); put_user_ns(ns->user_ns); ns_free_inum(&ns->ns); -- cgit v1.2.3