Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipc/sem: introduce semctl(SEM_STAT_ANY)

There is a permission discrepancy when consulting shm ipc object
metadata between /proc/sysvipc/sem (0444) and the SEM_STAT semctl
command. The later does permission checks for the object vs S_IRUGO.
As such there can be cases where EACCESS is returned via syscall but the
info is displayed anyways in the procfs files.

While this might have security implications via info leaking (albeit no
writing to the sma metadata), this behavior goes way back and showing
all the objects regardless of the permissions was most likely an
overlook - so we are stuck with it. Furthermore, modifying either the
syscall or the procfs file can cause userspace programs to break (ie
ipcs). Some applications require getting the procfs info (without root
privileges) and can be rather slow in comparison with a syscall -- up to
500x in some reported cases for shm.

This patch introduces a new SEM_STAT_ANY command such that the sem ipc
object permissions are ignored, and only audited instead. In addition,
I've left the lsm security hook checks in place, as if some policy can
block the call, then the user has no other choice than just parsing the
procfs file.

Link: http://lkml.kernel.org/r/20180215162458.10059-3-dave@stgolabs.net
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Reported-by: Robert Kettler <robert.kettler@outlook.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Manfred Spraul <manfred@colorfullife.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Michal Hocko <mhocko@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Davidlohr Bueso and committed by
Linus Torvalds
a280d6dc c21a6970

+15 -5
+1
include/uapi/linux/sem.h
··· 19 19 /* ipcs ctl cmds */ 20 20 #define SEM_STAT 18 21 21 #define SEM_INFO 19 22 + #define SEM_STAT_ANY 20 22 23 23 24 /* Obsolete, used only for backwards compatibility and libc5 compiles */ 24 25 struct semid_ds {
+12 -5
ipc/sem.c
··· 1220 1220 memset(semid64, 0, sizeof(*semid64)); 1221 1221 1222 1222 rcu_read_lock(); 1223 - if (cmd == SEM_STAT) { 1223 + if (cmd == SEM_STAT || cmd == SEM_STAT_ANY) { 1224 1224 sma = sem_obtain_object(ns, semid); 1225 1225 if (IS_ERR(sma)) { 1226 1226 err = PTR_ERR(sma); 1227 1227 goto out_unlock; 1228 1228 } 1229 1229 id = sma->sem_perm.id; 1230 - } else { 1230 + } else { /* IPC_STAT */ 1231 1231 sma = sem_obtain_object_check(ns, semid); 1232 1232 if (IS_ERR(sma)) { 1233 1233 err = PTR_ERR(sma); ··· 1235 1235 } 1236 1236 } 1237 1237 1238 - err = -EACCES; 1239 - if (ipcperms(ns, &sma->sem_perm, S_IRUGO)) 1240 - goto out_unlock; 1238 + /* see comment for SHM_STAT_ANY */ 1239 + if (cmd == SEM_STAT_ANY) 1240 + audit_ipc_obj(&sma->sem_perm); 1241 + else { 1242 + err = -EACCES; 1243 + if (ipcperms(ns, &sma->sem_perm, S_IRUGO)) 1244 + goto out_unlock; 1245 + } 1241 1246 1242 1247 err = security_sem_semctl(&sma->sem_perm, cmd); 1243 1248 if (err) ··· 1631 1626 return semctl_info(ns, semid, cmd, p); 1632 1627 case IPC_STAT: 1633 1628 case SEM_STAT: 1629 + case SEM_STAT_ANY: 1634 1630 err = semctl_stat(ns, semid, cmd, &semid64); 1635 1631 if (err < 0) 1636 1632 return err; ··· 1738 1732 return semctl_info(ns, semid, cmd, p); 1739 1733 case IPC_STAT: 1740 1734 case SEM_STAT: 1735 + case SEM_STAT_ANY: 1741 1736 err = semctl_stat(ns, semid, cmd, &semid64); 1742 1737 if (err < 0) 1743 1738 return err;
+1
security/selinux/hooks.c
··· 6273 6273 break; 6274 6274 case IPC_STAT: 6275 6275 case SEM_STAT: 6276 + case SEM_STAT_ANY: 6276 6277 perms = SEM__GETATTR | SEM__ASSOCIATE; 6277 6278 break; 6278 6279 default:
+1
security/smack/smack_lsm.c
··· 3140 3140 case GETALL: 3141 3141 case IPC_STAT: 3142 3142 case SEM_STAT: 3143 + case SEM_STAT_ANY: 3143 3144 may = MAY_READ; 3144 3145 break; 3145 3146 case SETVAL: