فهرست منبع

work around wrong kernel type for sem_nsems member of struct semid_ds

rejecting invalid values for n is fine even in the case where a new
sem will not be created, since the kernel does its range checks on n
even in this case as well.

by default, the kernel will bound the limit well below USHRT_MAX
anyway, but it's presumably possible that an administrator could
override this limit and break things.
Rich Felker 11 سال پیش
والد
کامیت
062f40ef3e
2فایلهای تغییر یافته به همراه16 افزوده شده و 1 حذف شده
  1. 9 1
      include/sys/sem.h
  2. 7 0
      src/ipc/semget.c

+ 9 - 1
include/sys/sem.h

@@ -25,13 +25,21 @@ extern "C" {
 #define SETVAL		16
 #define SETALL		17
 
+#include <endian.h>
+
 struct semid_ds {
 	struct ipc_perm sem_perm;
 	long sem_otime;
 	unsigned long __unused1;
 	long sem_ctime;
 	unsigned long __unused2;
-	unsigned long sem_nsems;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	unsigned short sem_nsems;
+	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
+#else
+	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
+	unsigned short sem_nsems;
+#endif
 	unsigned long __unused3;
 	unsigned long __unused4;
 };

+ 7 - 0
src/ipc/semget.c

@@ -1,9 +1,16 @@
 #include <sys/sem.h>
+#include <limits.h>
+#include <errno.h>
 #include "syscall.h"
 #include "ipc.h"
 
 int semget(key_t key, int n, int fl)
 {
+	/* The kernel uses the wrong type for the sem_nsems member
+	 * of struct semid_ds, and thus might not check that the
+	 * n fits in the correct (per POSIX) userspace type, so
+	 * we have to check here. */
+	if (n > USHRT_MAX) return __syscall_ret(-EINVAL);
 #ifdef SYS_semget
 	return syscall(SYS_semget, key, n, fl);
 #else