Subject: shm ipc broken

From: Guido Guenther <[email-masked]>
Date: Sun, 29 Apr 2001 21:06:01 +0200

The attached patch fixes a problem with shm ipc. The structs ipc_perm in
/u/i/bits/ipc.h and ipc64_perm in include/asm/ipcbuf.h had different sizes
and so caused the copy_shminfo_to_user in ipc/shm.c to corrupt user space(the
kernel structure was 8 bytes larger). This is probably not the correct fix,
since the other arches have this padding, so maybe glibc must be fixed.
There's still a small problem since shm_nattch is a short in glibc and a long
in the kernel, so the attach-numbers are wrong(which I'm also not sure where
it has to be fixed).  
 -- Guido

P.S.: this fixes the X server crashes some people were seeing.
--- include/asm-mips/ipcbuf.h.orig	Sun Apr 29 19:55:41 2001
+++ include/asm-mips/ipcbuf.h	Sun Apr 29 20:23:00 2001
@@ -2,13 +2,12 @@
 #define _ASM_IPCBUF_H
 
 /* 
- * The ipc64_perm structure for alpha architecture.
+ * The ipc64_perm structure for mips architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
  *
  * Pad space is left for:
  * - 32-bit seq
- * - 2 miscellaneous 64-bit values
  */
 
 struct ipc64_perm
@@ -21,8 +20,6 @@
 	__kernel_mode_t	mode; 
 	unsigned short	seq;
 	unsigned short	__pad1;
-	unsigned long	__unused1;
-	unsigned long	__unused2;
 };
 
 #endif /* _ASM_IPCBUF_H */

---

From: Ralf Baechle <[email-masked]>
Date: Mon, 30 Apr 2001 00:44:57 -0300

> in the kernel, so the attach-numbers are wrong(which I'm also not sure where

Thanks for the report.  Now, the kernel interface is what it is supposed
to be so you patch was unacceptable.  Instead I've sent below patch to
to the libc maintainers for inclusion.  Also for semaphores we also had
a structure missmatch.

Yet again it's amazing how long systems can apparently work reliable with
such capital bugs ...

  Ralf

2001-04-29  Ralf Baechle  <[email-masked]>

	* sysdeps/unix/sysv/linux/mips/bits/sem.h: Make structure definitions
	match the kernel definitions.
	sysdeps/unix/sysv/linux/mips/bits/ipc.h: Likewise.
	sysdeps/unix/sysv/linux/mips/bits/shm.h: Likewise.

diff -urN libc-cygnus/sysdeps/unix/sysv/linux/mips/bits/ipc.h libc-mips/sysdeps/unix/sysv/linux/mips/bits/ipc.h
--- libc-cygnus/sysdeps/unix/sysv/linux/mips/bits/ipc.h	Sun Apr 29 20:42:52 2001
+++ libc-mips/sysdeps/unix/sysv/linux/mips/bits/ipc.h	Sun Apr 29 21:07:14 2001
@@ -20,7 +20,7 @@
 # error "Never use <bits/ipc.h> directly; include <sys/ipc.h> instead."
 #endif
 
-#include <sys/types.h>
+#include <bits/types.h>
 
 /* Mode bits for `msgget', `semget', and `shmget'.  */
 #define IPC_CREAT	01000		/* Create key if key does not exist. */
@@ -43,34 +43,13 @@
 struct ipc_perm
   {
     __key_t __key;			/* Key.  */
-    long int uid;			/* Owner's user ID.  */
-    long int gid;			/* Owner's group ID.  */
-    long int cuid;			/* Creator's user ID.  */
-    long int cgid;			/* Creator's group ID.  */
-    unsigned long int mode;		/* Read/write permission.  */
+    unsigned int uid;			/* Owner's user ID.  */
+    unsigned int gid;			/* Owner's group ID.  */
+    unsigned int cuid;			/* Creator's user ID.  */
+    unsigned int cgid;			/* Creator's group ID.  */
+    unsigned int mode;			/* Read/write permission.  */
     unsigned short int __seq;		/* Sequence number.  */
+    unsigned short int __pad1;
+    unsigned long int __unused1;
+    unsigned long int __unused2;
   };
-
-
-__BEGIN_DECLS
-
-/* The actual system call: all functions are multiplexed by this.  */
-extern int __ipc (int __call, int __first, int __second, int __third,
-		  void *__ptr) __THROW;
-
-__END_DECLS
-
-#ifdef __USE_GNU
-/* The codes for the functions to use the multiplexer `__ipc'.  */
-# define IPCOP_semop	 1
-# define IPCOP_semget	 2
-# define IPCOP_semctl	 3
-# define IPCOP_msgsnd	11
-# define IPCOP_msgrcv	12
-# define IPCOP_msgget	13
-# define IPCOP_msgctl	14
-# define IPCOP_shmat	21
-# define IPCOP_shmdt	22
-# define IPCOP_shmget	23
-# define IPCOP_shmctl	24
-#endif
diff -urN libc-cygnus/sysdeps/unix/sysv/linux/mips/bits/sem.h libc-mips/sysdeps/unix/sysv/linux/mips/bits/sem.h
--- libc-cygnus/sysdeps/unix/sysv/linux/mips/bits/sem.h	Wed Dec 31 21:00:00 1969
+++ libc-mips/sysdeps/unix/sysv/linux/mips/bits/sem.h	Sun Apr 29 21:07:14 2001
@@ -0,0 +1,85 @@
+/* Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _SYS_SEM_H
+# error "Never include <bits/sem.h> directly; use <sys/sem.h> instead."
+#endif
+
+#include <sys/types.h>
+
+/* Flags for `semop'.  */
+#define SEM_UNDO	0x1000		/* undo the operation on exit */
+
+/* Commands for `semctl'.  */
+#define GETPID		11		/* get sempid */
+#define GETVAL		12		/* get semval */
+#define GETALL		13		/* get all semval's */
+#define GETNCNT		14		/* get semncnt */
+#define GETZCNT		15		/* get semzcnt */
+#define SETVAL		16		/* set semval */
+#define SETALL		17		/* set all semval's */
+
+
+/* Data structure describing a set of semaphores.  */
+struct semid_ds
+{
+  struct ipc_perm sem_perm;		/* operation permission struct */
+  __time_t sem_otime;			/* last semop() time */
+  __time_t sem_ctime;			/* last time changed by semctl() */
+  unsigned long int sem_nsems;		/* number of semaphores in set */
+  unsigned long int __unused1;
+  unsigned long int __unused2;
+};
+
+/* The user should define a union like the following to use it for arguments
+   for `semctl'.
+
+   union semun
+   {
+     int val;				<= value for SETVAL
+     struct semid_ds *buf;		<= buffer for IPC_STAT & IPC_SET
+     unsigned short int *array;		<= array for GETALL & SETALL
+     struct seminfo *__buf;		<= buffer for IPC_INFO
+   };
+
+   Previous versions of this file used to define this union but this is
+   incorrect.  One can test the macro _SEM_SEMUN_UNDEFINED to see whether
+   one must define the union or not.  */
+#define _SEM_SEMUN_UNDEFINED	1
+
+#ifdef __USE_MISC
+
+/* ipcs ctl cmds */
+# define SEM_STAT 18
+# define SEM_INFO 19
+
+struct  seminfo
+{
+  int semmap;
+  int semmni;
+  int semmns;
+  int semmnu;
+  int semmsl;
+  int semopm;
+  int semume;
+  int semusz;
+  int semvmx;
+  int semaem;
+};
+
+#endif /* __USE_MISC */
diff -urN libc-cygnus/sysdeps/unix/sysv/linux/mips/bits/shm.h libc-mips/sysdeps/unix/sysv/linux/mips/bits/shm.h
--- libc-cygnus/sysdeps/unix/sysv/linux/mips/bits/shm.h	Sun Apr 29 20:42:52 2001
+++ libc-mips/sysdeps/unix/sysv/linux/mips/bits/shm.h	Sun Apr 29 21:11:06 2001
@@ -20,7 +20,7 @@
 # error "Never include <bits/shm.h> directly; use <sys/shm.h> instead."
 #endif
 
-#include <sys/types.h>
+#include <bits/types.h>
 
 /* Permission flag for shmget.  */
 #define SHM_R		0400		/* or S_IRUGO from <linux/stat.h> */
@@ -36,20 +36,22 @@
 #define SHM_UNLOCK	12		/* unlock segment (root only) */

+/* Type to count number of attaches.  */
+typedef unsigned long int shmatt_t;
+
 /* Data structure describing a set of semaphores.  */
 struct shmid_ds
   {
     struct ipc_perm shm_perm;		/* operation permission struct */
-    int shm_segsz;			/* size of segment in bytes */
+    size_t shm_segsz;			/* size of segment in bytes */
     __time_t shm_atime;			/* time of last shmat() */
     __time_t shm_dtime;			/* time of last shmdt() */
     __time_t shm_ctime;			/* time of last change by shmctl() */
-    long int shm_cpid;			/* pid of creator */
-    long int shm_lpid;			/* pid of last shmop */
-    unsigned short int shm_nattch;	/* number of current attaches */
-    unsigned short int __shm_npages;	/* size of segment (pages) */
-    unsigned long int *__unbounded __shm_pages;	/* array of ptrs to frames -> SHMMAX */
-    struct vm_area_struct *__unbounded __attaches; /* descriptors for attaches */
+    __pid_t shm_cpid;			/* pid of creator */
+    __pid_t shm_lpid;			/* pid of last shmop */
+    shmatt_t shm_nattch;		/* number of current attaches */
+    unsigned long int __unused1;
+    unsigned long int __unused2;
   };
 
 #ifdef __USE_MISC
@@ -62,23 +64,27 @@
 # define SHM_DEST	01000	/* segment will be destroyed on last detach */
 # define SHM_LOCKED	02000   /* segment will not be swapped */
 
-struct	shminfo
+struct shminfo
   {
-    int shmmax;
-    int shmmin;
-    int shmmni;
-    int shmseg;
-    int shmall;
+    unsigned long int shmmax;
+    unsigned long int shmmin;
+    unsigned long int shmmni;
+    unsigned long int shmseg;
+    unsigned long int shmall;
+    unsigned long int __unused1;
+    unsigned long int __unused2;
+    unsigned long int __unused3;
+    unsigned long int __unused4;
   };
 
 struct shm_info
   {
-    int   used_ids;
-    ulong shm_tot;	/* total allocated shm */
-    ulong shm_rss;	/* total resident shm */
-    ulong shm_swp;	/* total swapped shm */
-    ulong swap_attempts;
-    ulong swap_successes;
+    int used_ids;
+    unsigned long int shm_tot;  /* total allocated shm */
+    unsigned long int shm_rss;  /* total resident shm */
+    unsigned long int shm_swp;  /* total swapped shm */
+    unsigned long int swap_attempts;
+    unsigned long int swap_successes;
   };
 
 #endif /* __USE_MISC */