diff -uNr 99-pre4-5/ipc/shm.c c4-5/ipc/shm.c
--- 99-pre4-5/ipc/shm.c	Sat Apr  8 11:22:14 2000
+++ c4-5/ipc/shm.c	Sat Apr  8 15:57:00 2000
@@ -68,6 +68,13 @@
 #define SHM_FMT ".IPC_%08x"
 #define SHM_FMT_LEN 13
 
+/* shm_mode upper byte flags */
+/* SHM_DEST and SHM_LOCKED are used in ipcs(8) */
+#define PRV_DEST	0010000	/* segment will be destroyed on last detach */
+#define PRV_LOCKED	0020000	/* segment will not be swapped */
+#define SHM_UNLK	0040000	/* filename is unlinked */
+#define SHM_SYSV	0100000	/* It is a SYSV shm segment */
+
 struct shmid_kernel /* private to the kernel */
 {	
 	struct kern_ipc_perm	shm_perm;
@@ -83,7 +90,6 @@
 			time_t			ctime;
 			pid_t			cpid;
 			pid_t			lpid;
-			int			unlinked;
 			int			nlen;
 			char			nm[0];
 		} shmem;
@@ -101,7 +107,7 @@
 #define shm_lprid	permap.shmem.lpid
 #define shm_namelen	permap.shmem.nlen
 #define shm_name	permap.shmem.nm
-#define shm_unlinked	permap.shmem.unlinked
+#define shm_flags	shm_perm.mode
 #define zsem		permap.zero.sema
 #define zero_list	permap.zero.list
 
@@ -112,8 +118,6 @@
 #define shm_lockall()	ipc_lockall(&shm_ids)
 #define shm_unlockall()	ipc_unlockall(&shm_ids)
 #define shm_get(id)	((struct shmid_kernel*)ipc_get(&shm_ids,id))
-#define shm_checkid(s, id)	\
-	ipc_checkid(&shm_ids,&s->shm_perm,id)
 #define shm_buildid(id, seq) \
 	ipc_buildid(&shm_ids, id, seq)
 
@@ -317,6 +321,15 @@
 	return 0;
 }
 
+static inline int shm_checkid(struct shmid_kernel *s, int id)
+{
+	if (!(s->shm_flags & SHM_SYSV))
+		return -EINVAL;
+	if (ipc_checkid(&shm_ids,&s->shm_perm,id))
+		return -EIDRM;
+	return 0;
+}
+
 static inline struct shmid_kernel *shm_rmid(int id)
 {
 	return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
@@ -384,7 +397,7 @@
 	if (id < SEQ_MULTIPLIER) {
 		if (!(shp = shm_lock (id)))
 			return;
-		inode->i_mode = shp->shm_perm.mode | S_IFREG;
+		inode->i_mode = (shp->shm_flags & S_IALLUGO) | S_IFREG;
 		inode->i_uid  = shp->shm_perm.uid;
 		inode->i_gid  = shp->shm_perm.gid;
 		inode->i_size = shp->shm_segsz;
@@ -456,7 +469,7 @@
 				continue;
 			if (!(shp = shm_get (nr-2))) 
 				continue;
-			if (shp->shm_unlinked)
+			if (shp->shm_flags & SHM_UNLK)
 				continue;
 			if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr) < 0 )
 				break;;
@@ -485,7 +498,7 @@
 			continue;
 		if (!(shp = shm_lock(i)))
 			continue;
-		if (!(shp->shm_unlinked) &&
+		if (!(shp->shm_flags & SHM_UNLK) &&
 		    dent->d_name.len == shp->shm_namelen &&
 		    strncmp(dent->d_name.name, shp->shm_name, shp->shm_namelen) == 0)
 			goto found;
@@ -523,8 +536,7 @@
 	down (&shm_ids.sem);
 	if (!(shp = shm_lock (inode->i_ino)))
 		BUG();
-	shp->shm_unlinked = 1;
-	shp->shm_perm.mode |= SHM_DEST;
+	shp->shm_flags |= SHM_UNLK | PRV_DEST;
 	shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
 	shm_unlock (inode->i_ino);
 	up (&shm_ids.sem);
@@ -743,18 +755,18 @@
 		return -ENOSPC;
 	}
 	shp->shm_perm.key = key;
-	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
+	shp->shm_flags = (shmflg & S_IRWXUGO);
 	shp->shm_segsz = size;
 	shp->shm_cprid = current->pid;
 	shp->shm_lprid = 0;
 	shp->shm_atim = shp->shm_dtim = 0;
 	shp->shm_ctim = CURRENT_TIME;
 	shp->id = shm_buildid(id,shp->shm_perm.seq);
-	shp->shm_unlinked = 0;
 	if (namelen != 0) {
 		shp->shm_namelen = namelen;
 		memcpy (shp->shm_name, name, namelen);		  
 	} else {
+		shp->shm_flags |= SHM_SYSV;
 		shp->shm_namelen = sprintf (shp->shm_name, SHM_FMT, shp->id);
 	}
 	shm_unlock(id);
@@ -863,7 +875,7 @@
 
 		out->uid	= tbuf.shm_perm.uid;
 		out->gid	= tbuf.shm_perm.gid;
-		out->mode	= tbuf.shm_perm.mode;
+		out->mode	= tbuf.shm_flags;
 
 		return 0;
 	    }
@@ -876,7 +888,7 @@
 
 		out->uid	= tbuf_old.shm_perm.uid;
 		out->gid	= tbuf_old.shm_perm.gid;
-		out->mode	= tbuf_old.shm_perm.mode;
+		out->mode	= tbuf_old.shm_flags;
 
 		return 0;
 	    }
@@ -980,12 +992,13 @@
 			return -EINVAL;
 		if(cmd==SHM_STAT) {
 			err = -EINVAL;
-			if (shmid > shm_ids.max_id)
+			if (!(shp->shm_flags & SHM_SYSV) ||
+			    shmid > shm_ids.max_id)
 				goto out_unlock;
 			result = shm_buildid(shmid, shp->shm_perm.seq);
 		} else {
-			err = -EIDRM;
-			if(shm_checkid(shp,shmid))
+			err = shm_checkid(shp,shmid);
+			if(err)
 				goto out_unlock;
 			result = 0;
 		}
@@ -993,6 +1006,13 @@
 		if (ipcperms (&shp->shm_perm, S_IRUGO))
 			goto out_unlock;
 		kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
+		/* ugly hack to keep binary compatibility for ipcs */
+		tbuf.shm_flags &= PRV_DEST | PRV_LOCKED | S_IRWXUGO;
+		if (tbuf.shm_flags & PRV_DEST)
+			tbuf.shm_flags |= SHM_DEST;
+		if (tbuf.shm_flags & PRV_LOCKED)
+			tbuf.shm_flags |= SHM_LOCKED;
+		tbuf.shm_flags &= SHM_DEST | SHM_LOCKED | S_IRWXUGO;
 		tbuf.shm_segsz	= shp->shm_segsz;
 		tbuf.shm_atime	= shp->shm_atim;
 		tbuf.shm_dtime	= shp->shm_dtim;
@@ -1011,7 +1031,6 @@
 /* Allow superuser to lock segment in memory */
 /* Should the pages be faulted in here or leave it to user? */
 /* need to determine interaction with current->swappable */
-		struct kern_ipc_perm *ipcp;
 		if ((shmid % SEQ_MULTIPLIER)== zero_id)
 			return -EINVAL;
 		if (!capable(CAP_IPC_LOCK))
@@ -1020,21 +1039,13 @@
 		shp = shm_lock(shmid);
 		if(shp==NULL)
 			return -EINVAL;
-		err=-EIDRM;
-		if(shm_checkid(shp,shmid))
+		err = shm_checkid(shp,shmid);
+		if(err)
 			goto out_unlock;
-		ipcp = &shp->shm_perm;
-		if(cmd==SHM_LOCK) {
-			if (!(ipcp->mode & SHM_LOCKED)) {
-				ipcp->mode |= SHM_LOCKED;
-				err = 0;
-			}
-		} else {
-			if (ipcp->mode & SHM_LOCKED) {
-				ipcp->mode &= ~SHM_LOCKED;
-				err = 0;
-			}
-		}
+		if(cmd==SHM_LOCK)
+			shp->shm_flags |= PRV_LOCKED;
+		else
+			shp->shm_flags &= ~PRV_LOCKED;
 		shm_unlock(shmid);
 		return err;
 	}
@@ -1058,9 +1069,10 @@
 			up(&shm_ids.sem);
 			return -EINVAL;
 		}
-		err = -EIDRM;
-		if (shm_checkid(shp, shmid) == 0) {
-			if (shp->shm_nattch == 0) {
+		err = shm_checkid(shp, shmid);
+		if (err == 0) {
+			if (shp->shm_nattch == 0 && 
+			    !(shp->shm_flags & SHM_UNLK)) {
 				int id=shp->id;
 				shm_unlock(shmid);
 				up(&shm_ids.sem);
@@ -1071,10 +1083,9 @@
 				 */
 				return shm_remove_name(id);
 			}
-			/* Do not find me any more */
-			shp->shm_perm.mode |= SHM_DEST;
-			shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
-			err = 0;
+			shp->shm_flags |= PRV_DEST;
+			/* Do not find it any more */
+			shp->shm_perm.key = IPC_PRIVATE;
 		}
 		/* Unlock */
 		shm_unlock(shmid);
@@ -1094,8 +1105,8 @@
 		err=-EINVAL;
 		if(shp==NULL)
 			goto out_up;
-		err=-EIDRM;
-		if(shm_checkid(shp,shmid))
+		err = shm_checkid(shp,shmid);
+		if(err)
 			goto out_unlock_up;
 		err=-EPERM;
 		if (current->euid != shp->shm_perm.uid &&
@@ -1106,7 +1117,7 @@
 
 		shp->shm_perm.uid = setbuf.uid;
 		shp->shm_perm.gid = setbuf.gid;
-		shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
+		shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
 			| (setbuf.mode & S_IRWXUGO);
 		shp->shm_ctim = CURRENT_TIME;
 		break;
@@ -1248,7 +1259,16 @@
 	dentry = lookup_one(name, dget(dir));
 	error = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
-		error = vfs_unlink(dir->d_inode, dentry);
+		/*
+		 * We have to do our own unlink to prevent the vfs
+		 * permission check. The SYSV IPC layer has already
+		 * checked the permissions which do not comply to the
+		 * vfs rules.
+		 */
+		struct inode *inode = dir->d_inode;
+		down(&inode->i_zombie);
+		error = shm_unlink(inode, dentry);
+		up(&inode->i_zombie);
 		dput(dentry);
 	}
 	unlock_dir(dir);
@@ -1273,7 +1293,9 @@
 	shp->shm_lprid = current->pid;
 	shp->shm_dtim = CURRENT_TIME;
 	shp->shm_nattch--;
-	if(shp->shm_nattch == 0 && shp->shm_perm.mode & SHM_DEST) {
+	if(shp->shm_nattch == 0 && 
+	   shp->shm_flags & PRV_DEST &&
+	   !(shp->shm_flags & SHM_UNLK)) {
 		int pid=shp->id;
 		int err;
 		shm_unlock(id);
@@ -1487,7 +1509,7 @@
 	shm_lockall();
 check_id:
 	shp = shm_get(swap_id);
-	if(shp==NULL || shp->shm_perm.mode & SHM_LOCKED) {
+	if(shp==NULL || shp->shm_flags & SHM_LOCKED) {
 next_id:
 		swap_idx = 0;
 		if (++swap_id > shm_ids.max_id) {
@@ -1605,7 +1627,7 @@
 			len += sprintf(buffer + len, format,
 				shp->shm_perm.key,
 				shm_buildid(i, shp->shm_perm.seq),
-				shp->shm_perm.mode,
+				shp->shm_flags,
 				shp->shm_segsz,
 				shp->shm_cprid,
 				shp->shm_lprid,
@@ -1619,7 +1641,7 @@
 				shp->shm_ctim,
 				shp->shm_namelen,
 				shp->shm_name,
-				shp->shm_unlinked ? " (deleted)" : "");
+				shp->shm_flags & SHM_UNLK ? " (deleted)" : "");
 			shm_unlock(i);
 
 			pos += len;