From: Hugh Dickins <hugh@veritas.com>

Michael Kerrisk has observed that at present any process can SHM_LOCK any
shm segment of size within process RLIMIT_MEMLOCK, despite having no
permissions on the segment: surprising, though not obviously evil.  And any
process can SHM_UNLOCK any shm segment, despite no permissions on it: that
is surely wrong.

Unless CAP_IPC_LOCK, restrict both SHM_LOCK and SHM_UNLOCK to when the
process euid matches the shm owner or creator: that seems the least
surprising behaviour, which could be relaxed if a need appears later.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/ipc/shm.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff -puN ipc/shm.c~shmctl-shm_lock-perms ipc/shm.c
--- 25/ipc/shm.c~shmctl-shm_lock-perms	Thu Dec  9 13:07:12 2004
+++ 25-akpm/ipc/shm.c	Thu Dec  9 13:07:12 2004
@@ -511,11 +511,6 @@ asmlinkage long sys_shmctl (int shmid, i
 	case SHM_LOCK:
 	case SHM_UNLOCK:
 	{
-		/* Allow superuser to lock segment in memory */
-		if (!can_do_mlock() && cmd == SHM_LOCK) {
-			err = -EPERM;
-			goto out;
-		}
 		shp = shm_lock(shmid);
 		if(shp==NULL) {
 			err = -EINVAL;
@@ -525,6 +520,16 @@ asmlinkage long sys_shmctl (int shmid, i
 		if(err)
 			goto out_unlock;
 
+		if (!capable(CAP_IPC_LOCK)) {
+			err = -EPERM;
+			if (current->euid != shp->shm_perm.uid &&
+			    current->euid != shp->shm_perm.cuid)
+				goto out_unlock;
+			if (cmd == SHM_LOCK &&
+			    !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
+				goto out_unlock;
+		}
+
 		err = security_shm_shmctl(shp, cmd);
 		if (err)
 			goto out_unlock;
_