Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Mar 2017 17:07:16 +0000 (UTC)
From:      Dmitry Chagin <dchagin@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314866 - in head/sys: amd64/linux amd64/linux32 compat/linux i386/linux
Message-ID:  <201703071707.v27H7GVL058242@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dchagin
Date: Tue Mar  7 17:07:16 2017
New Revision: 314866
URL: https://svnweb.freebsd.org/changeset/base/314866

Log:
  Reduce code duplication between MD Linux code by moving SYSV IPC 64-bit
  related struct definitions out into the MI path.
  
  Invert the native ipc structs to the Linux ipc structs convesion logic.
  Since 64-bit variant of ipc structs has more precision convert native ipc
  structs to the 64-bit Linux ipc structs and then truncate 64-bit values
  into the non 64-bit if needed. Unlike Linux, return EOVERFLOW if the
  values do not fit.
  
  Fix SYSV IPC for 64-bit Linuxulator which never sets IPC_64 bit.
  
  MFC after:	1 month

Added:
  head/sys/compat/linux/linux_ipc64.h
     - copied, changed from r314865, head/sys/i386/linux/linux_ipc64.h
Deleted:
  head/sys/amd64/linux/linux_ipc64.h
  head/sys/amd64/linux32/linux32_ipc64.h
  head/sys/i386/linux/linux_ipc64.h
Modified:
  head/sys/amd64/linux/linux.h
  head/sys/amd64/linux32/linux.h
  head/sys/compat/linux/linux_ipc.c
  head/sys/i386/linux/linux.h

Modified: head/sys/amd64/linux/linux.h
==============================================================================
--- head/sys/amd64/linux/linux.h	Tue Mar  7 16:09:37 2017	(r314865)
+++ head/sys/amd64/linux/linux.h	Tue Mar  7 17:07:16 2017	(r314866)
@@ -69,7 +69,9 @@ typedef l_long		l_clock_t;
 typedef l_int		l_daddr_t;
 typedef l_ulong		l_dev_t;
 typedef l_uint		l_gid_t;
+typedef l_ushort	l_gid16_t;
 typedef l_uint		l_uid_t;
+typedef	l_ushort	l_uid16_t;
 typedef l_ulong		l_ino_t;
 typedef l_int		l_key_t;
 typedef l_long		l_loff_t;
@@ -381,16 +383,6 @@ union l_semun {
 	l_uintptr_t	__pad;
 };
 
-struct l_ipc_perm {
-	l_key_t		key;
-	l_uid_t		uid;
-	l_gid_t		gid;
-	l_uid_t		cuid;
-	l_gid_t		cgid;
-	l_ushort	mode;
-	l_ushort	seq;
-};
-
 /*
  * Socket defines
  */

Modified: head/sys/amd64/linux32/linux.h
==============================================================================
--- head/sys/amd64/linux32/linux.h	Tue Mar  7 16:09:37 2017	(r314865)
+++ head/sys/amd64/linux32/linux.h	Tue Mar  7 17:07:16 2017	(r314866)
@@ -474,16 +474,6 @@ union l_semun {
 	l_uintptr_t	__pad;
 } __packed;
 
-struct l_ipc_perm {
-	l_key_t		key;
-	l_uid16_t	uid;
-	l_gid16_t	gid;
-	l_uid16_t	cuid;
-	l_gid16_t	cgid;
-	l_ushort	mode;
-	l_ushort	seq;
-};
-
 /*
  * Socket defines
  */

Modified: head/sys/compat/linux/linux_ipc.c
==============================================================================
--- head/sys/compat/linux/linux_ipc.c	Tue Mar  7 16:09:37 2017	(r314865)
+++ head/sys/compat/linux/linux_ipc.c	Tue Mar  7 17:07:16 2017	(r314866)
@@ -44,15 +44,27 @@ __FBSDID("$FreeBSD$");
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
-#include <machine/../linux32/linux32_ipc64.h>
 #else
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
-#include <machine/../linux/linux_ipc64.h>
 #endif
 #include <compat/linux/linux_ipc.h>
+#include <compat/linux/linux_ipc64.h>
 #include <compat/linux/linux_util.h>
 
+/*
+ * old, pre 2.4 kernel
+ */
+struct l_ipc_perm {
+	l_key_t		key;
+	l_uid16_t	uid;
+	l_gid16_t	gid;
+	l_uid16_t	cuid;
+	l_gid16_t	cgid;
+	l_ushort	mode;
+	l_ushort	seq;
+};
+
 struct l_seminfo {
 	l_int semmap;
 	l_int semmni;
@@ -95,7 +107,7 @@ struct l_msginfo {
 };
 
 static void
-bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp)
+bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo64 *lpp)
 {
 
 	lpp->shmmax = bpp->shmmax;
@@ -109,16 +121,16 @@ static void
 bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
 {
 
-	lpp->used_ids = bpp->used_ids ;
-	lpp->shm_tot = bpp->shm_tot ;
-	lpp->shm_rss = bpp->shm_rss ;
-	lpp->shm_swp = bpp->shm_swp ;
-	lpp->swap_attempts = bpp->swap_attempts ;
-	lpp->swap_successes = bpp->swap_successes ;
+	lpp->used_ids = bpp->used_ids;
+	lpp->shm_tot = bpp->shm_tot;
+	lpp->shm_rss = bpp->shm_rss;
+	lpp->shm_swp = bpp->shm_swp;
+	lpp->swap_attempts = bpp->swap_attempts;
+	lpp->swap_successes = bpp->swap_successes;
 }
 
 static void
-linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp)
+linux_to_bsd_ipc_perm(struct l_ipc64_perm *lpp, struct ipc_perm *bpp)
 {
 
 	bpp->key = lpp->key;
@@ -131,7 +143,7 @@ linux_to_bsd_ipc_perm(struct l_ipc_perm 
 }
 
 static void
-bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp)
+bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc64_perm *lpp)
 {
 
 	lpp->key = bpp->key;
@@ -185,29 +197,27 @@ struct l_shmid_ds {
 };
 
 static void
-linux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp)
+linux_to_bsd_semid_ds(struct l_semid64_ds *lsp, struct semid_ds *bsp)
 {
 
 	linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
 	bsp->sem_otime = lsp->sem_otime;
 	bsp->sem_ctime = lsp->sem_ctime;
 	bsp->sem_nsems = lsp->sem_nsems;
-	bsp->sem_base = PTRIN(lsp->sem_base);
 }
 
 static void
-bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp)
+bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid64_ds *lsp)
 {
 
 	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
 	lsp->sem_otime = bsp->sem_otime;
 	lsp->sem_ctime = bsp->sem_ctime;
 	lsp->sem_nsems = bsp->sem_nsems;
-	lsp->sem_base = PTROUT(bsp->sem_base);
 }
 
 static void
-linux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp)
+linux_to_bsd_shmid_ds(struct l_shmid64_ds *lsp, struct shmid_ds *bsp)
 {
 
 	linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
@@ -221,28 +231,21 @@ linux_to_bsd_shmid_ds(struct l_shmid_ds 
 }
 
 static void
-bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp)
+bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid64_ds *lsp)
 {
 
 	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
-	if (bsp->shm_segsz > INT_MAX)
-		lsp->shm_segsz = INT_MAX;
-	else
-		lsp->shm_segsz = bsp->shm_segsz;
+	lsp->shm_segsz = bsp->shm_segsz;
 	lsp->shm_lpid = bsp->shm_lpid;
 	lsp->shm_cpid = bsp->shm_cpid;
-	if (bsp->shm_nattch > SHRT_MAX)
-		lsp->shm_nattch = SHRT_MAX;
-	else
-		lsp->shm_nattch = bsp->shm_nattch;
+	lsp->shm_nattch = bsp->shm_nattch;
 	lsp->shm_atime = bsp->shm_atime;
 	lsp->shm_dtime = bsp->shm_dtime;
 	lsp->shm_ctime = bsp->shm_ctime;
-	lsp->private3 = 0;
 }
 
 static void
-linux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp)
+linux_to_bsd_msqid_ds(struct l_msqid64_ds *lsp, struct msqid_ds *bsp)
 {
 
 	linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm);
@@ -257,7 +260,7 @@ linux_to_bsd_msqid_ds(struct l_msqid_ds 
 }
 
 static void
-bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp)
+bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid64_ds *lsp)
 {
 
 	bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm);
@@ -271,11 +274,10 @@ bsd_to_linux_msqid_ds(struct msqid_ds *b
 	lsp->msg_ctime = bsp->msg_ctime;
 }
 
-static void
-linux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out)
+static int
+linux_ipc64_perm_to_ipc_perm(struct l_ipc64_perm *in, struct l_ipc_perm *out)
 {
 
-	/* XXX: do we really need to do something here? */
 	out->key = in->key;
 	out->uid = in->uid;
 	out->gid = in->gid;
@@ -283,186 +285,222 @@ linux_ipc_perm_to_ipc64_perm(struct l_ip
 	out->cgid = in->cgid;
 	out->mode = in->mode;
 	out->seq = in->seq;
+
+	/* Linux does not check overflow */
+	if (out->uid != in->uid || out->gid != in->gid ||
+	    out->cuid != in->cuid || out->cgid != in->cgid ||
+	    out->mode != in->mode)
+		return (EOVERFLOW);
+	else
+		return (0);
 }
 
 static int
-linux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
+linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
 {
-	struct l_msqid64_ds linux_msqid64;
+	struct l_msqid_ds linux_msqid;
 	int error;
 
-	if (ver == LINUX_IPC_64) {
-		error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64));
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyin(uaddr, linux_msqid64, sizeof(*linux_msqid64)));
+	else {
+		error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid));
 		if (error != 0)
 			return (error);
 
-		bzero(linux_msqid, sizeof(*linux_msqid));
-
-		linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid;
-		linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid;
-		linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode;
+		bzero(linux_msqid64, sizeof(*linux_msqid64));
 
-		if (linux_msqid64.msg_qbytes > USHRT_MAX)
-			linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes;
+		linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid;
+		linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid;
+		linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode;
+		if (linux_msqid.msg_qbytes == 0)
+			linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes;
 		else
-			linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes;
-	} else
-		error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid));
-
-	return (error);
+			linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes;
+		return (0);
+	}
 }
 
 static int
-linux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
+linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
 {
-	struct l_msqid64_ds linux_msqid64;
+	struct l_msqid_ds linux_msqid;
+	int error;
 
-	if (ver == LINUX_IPC_64) {
-		bzero(&linux_msqid64, sizeof(linux_msqid64));
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyout(linux_msqid64, uaddr, sizeof(*linux_msqid64)));
+	else {
+		bzero(&linux_msqid, sizeof(linux_msqid));
 
-		linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm,
-		    &linux_msqid64.msg_perm);
+		error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm,
+		    &linux_msqid.msg_perm);
+		if (error != 0)
+			return (error);
 
-		linux_msqid64.msg_stime = linux_msqid->msg_stime;
-		linux_msqid64.msg_rtime = linux_msqid->msg_rtime;
-		linux_msqid64.msg_ctime = linux_msqid->msg_ctime;
+		linux_msqid.msg_stime = linux_msqid64->msg_stime;
+		linux_msqid.msg_rtime = linux_msqid64->msg_rtime;
+		linux_msqid.msg_ctime = linux_msqid64->msg_ctime;
 
-		if (linux_msqid->msg_cbytes == 0)
-			linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes;
+		if (linux_msqid64->msg_cbytes > USHRT_MAX)
+			linux_msqid.msg_cbytes = USHRT_MAX;
 		else
-			linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes;
-
-		linux_msqid64.msg_qnum = linux_msqid->msg_qnum;
-
-		if (linux_msqid->msg_qbytes == 0)
-			linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes;
+			linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes;
+		linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes;
+		if (linux_msqid64->msg_qnum > USHRT_MAX)
+			linux_msqid.msg_qnum = linux_msqid64->msg_qnum;
 		else
-			linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes;
-
-		linux_msqid64.msg_lspid = linux_msqid->msg_lspid;
-		linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid;
+			linux_msqid.msg_qnum = linux_msqid64->msg_qnum;
+		if (linux_msqid64->msg_qbytes > USHRT_MAX)
+			linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes;
+		else
+			linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes;
+		linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes;
+		linux_msqid.msg_lspid = linux_msqid64->msg_lspid;
+		linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid;
+
+		/* Linux does not check overflow */
+		if (linux_msqid.msg_stime != linux_msqid64->msg_stime ||
+		    linux_msqid.msg_rtime != linux_msqid64->msg_rtime ||
+		    linux_msqid.msg_ctime != linux_msqid64->msg_ctime)
+			return (EOVERFLOW);
 
-		return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64)));
-	} else
-		return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid)));
+		return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid)));
+	}
 }
 
 static int
-linux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
+linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
 {
-	struct l_semid64_ds linux_semid64;
+	struct l_semid_ds linux_semid;
 	int error;
 
-	if (ver == LINUX_IPC_64) {
-		error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64));
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyin(uaddr, linux_semid64, sizeof(*linux_semid64)));
+	else {
+		error = copyin(uaddr, &linux_semid, sizeof(linux_semid));
 		if (error != 0)
 			return (error);
 
-		bzero(linux_semid, sizeof(*linux_semid));
-
-		linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid;
-		linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid;
-		linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode;
-	} else
-		error = copyin(uaddr, linux_semid, sizeof(*linux_semid));
+		bzero(linux_semid64, sizeof(*linux_semid64));
 
-	return (error);
+		linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid;
+		linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid;
+		linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode;
+		return (0);
+	}
 }
 
 static int
-linux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
+linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
 {
-	struct l_semid64_ds linux_semid64;
+	struct l_semid_ds linux_semid;
+	int error;
+
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyout(linux_semid64, uaddr, sizeof(*linux_semid64)));
+	else {
+		bzero(&linux_semid, sizeof(linux_semid));
+
+		error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm,
+		    &linux_semid.sem_perm);
+		if (error != 0)
+			return (error);
 
-	if (ver == LINUX_IPC_64) {
-		bzero(&linux_semid64, sizeof(linux_semid64));
+		linux_semid.sem_otime = linux_semid64->sem_otime;
+		linux_semid.sem_ctime = linux_semid64->sem_ctime;
+		linux_semid.sem_nsems = linux_semid64->sem_nsems;
 
-		linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm,
-		    &linux_semid64.sem_perm);
+		/* Linux does not check overflow */
+		if (linux_semid.sem_otime != linux_semid64->sem_otime ||
+		    linux_semid.sem_ctime != linux_semid64->sem_ctime ||
+		    linux_semid.sem_nsems != linux_semid64->sem_nsems)
+			return (EOVERFLOW);
 
-		linux_semid64.sem_otime = linux_semid->sem_otime;
-		linux_semid64.sem_ctime = linux_semid->sem_ctime;
-		linux_semid64.sem_nsems = linux_semid->sem_nsems;
-
-		return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64)));
-	} else
-		return (copyout(linux_semid, uaddr, sizeof(*linux_semid)));
+		return (copyout(&linux_semid, uaddr, sizeof(linux_semid)));
+	}
 }
 
 static int
-linux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
+linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
 {
-	struct l_shmid64_ds linux_shmid64;
+	struct l_shmid_ds linux_shmid;
 	int error;
 
-	if (ver == LINUX_IPC_64) {
-		error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64));
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyin(uaddr, linux_shmid64, sizeof(*linux_shmid64)));
+	else {
+		error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid));
 		if (error != 0)
 			return (error);
 
-		bzero(linux_shmid, sizeof(*linux_shmid));
+		bzero(linux_shmid64, sizeof(*linux_shmid64));
 
-		linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid;
-		linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid;
-		linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode;
-	} else
-		error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid));
-
-	return (error);
+		linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid;
+		linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid;
+		linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode;
+		return (0);
+	}
 }
 
 static int
-linux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
+linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
 {
-	struct l_shmid64_ds linux_shmid64;
+	struct l_shmid_ds linux_shmid;
+	int error;
 
-	/*
-	 * XXX: This is backwards and loses information in shm_nattch
-	 * and shm_segsz.  We should probably either expose the BSD
-	 * shmid structure directly and convert it to either the
-	 * non-64 or 64 variant directly or the code should always
-	 * convert to the 64 variant and then truncate values into the
-	 * non-64 variant if needed since the 64 variant has more
-	 * precision.
-	 */
-	if (ver == LINUX_IPC_64) {
-		bzero(&linux_shmid64, sizeof(linux_shmid64));
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyout(linux_shmid64, uaddr, sizeof(*linux_shmid64)));
+	else {
+		bzero(&linux_shmid, sizeof(linux_shmid));
+
+		error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm,
+		    &linux_shmid.shm_perm);
+		if (error != 0)
+			return (error);
 
-		linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm,
-		    &linux_shmid64.shm_perm);
+		linux_shmid.shm_segsz = linux_shmid64->shm_segsz;
+		linux_shmid.shm_atime = linux_shmid64->shm_atime;
+		linux_shmid.shm_dtime = linux_shmid64->shm_dtime;
+		linux_shmid.shm_ctime = linux_shmid64->shm_ctime;
+		linux_shmid.shm_cpid = linux_shmid64->shm_cpid;
+		linux_shmid.shm_lpid = linux_shmid64->shm_lpid;
+		linux_shmid.shm_nattch = linux_shmid64->shm_nattch;
+
+		/* Linux does not check overflow */
+		if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz ||
+		    linux_shmid.shm_atime != linux_shmid64->shm_atime ||
+		    linux_shmid.shm_dtime != linux_shmid64->shm_dtime ||
+		    linux_shmid.shm_ctime != linux_shmid64->shm_ctime ||
+		    linux_shmid.shm_cpid != linux_shmid64->shm_cpid ||
+		    linux_shmid.shm_lpid != linux_shmid64->shm_lpid ||
+		    linux_shmid.shm_nattch != linux_shmid64->shm_nattch)
+			return (EOVERFLOW);
 
-		linux_shmid64.shm_segsz = linux_shmid->shm_segsz;
-		linux_shmid64.shm_atime = linux_shmid->shm_atime;
-		linux_shmid64.shm_dtime = linux_shmid->shm_dtime;
-		linux_shmid64.shm_ctime = linux_shmid->shm_ctime;
-		linux_shmid64.shm_cpid = linux_shmid->shm_cpid;
-		linux_shmid64.shm_lpid = linux_shmid->shm_lpid;
-		linux_shmid64.shm_nattch = linux_shmid->shm_nattch;
-
-		return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64)));
-	} else
-		return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid)));
+		return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid)));
+	}
 }
 
 static int
-linux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo,
+linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64,
     caddr_t uaddr)
 {
-	struct l_shminfo64 linux_shminfo64;
+	struct l_shminfo linux_shminfo;
 
-	if (ver == LINUX_IPC_64) {
-		bzero(&linux_shminfo64, sizeof(linux_shminfo64));
+	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
+		return (copyout(linux_shminfo64, uaddr,
+		    sizeof(*linux_shminfo64)));
+	else {
+		bzero(&linux_shminfo, sizeof(linux_shminfo));
+
+		linux_shminfo.shmmax = linux_shminfo64->shmmax;
+		linux_shminfo.shmmin = linux_shminfo64->shmmin;
+		linux_shminfo.shmmni = linux_shminfo64->shmmni;
+		linux_shminfo.shmseg = linux_shminfo64->shmseg;
+		linux_shminfo.shmall = linux_shminfo64->shmall;
 
-		linux_shminfo64.shmmax = linux_shminfo->shmmax;
-		linux_shminfo64.shmmin = linux_shminfo->shmmin;
-		linux_shminfo64.shmmni = linux_shminfo->shmmni;
-		linux_shminfo64.shmseg = linux_shminfo->shmseg;
-		linux_shminfo64.shmall = linux_shminfo->shmall;
-
-		return (copyout(&linux_shminfo64, uaddr,
-		    sizeof(linux_shminfo64)));
-	} else
-		return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo)));
+		return (copyout(&linux_shminfo, uaddr,
+		    sizeof(linux_shminfo)));
+	}
 }
 
 int
@@ -500,7 +538,7 @@ linux_semget(struct thread *td, struct l
 int
 linux_semctl(struct thread *td, struct linux_semctl_args *args)
 {
-	struct l_semid_ds linux_semid;
+	struct l_semid64_ds linux_semid64;
 	struct l_seminfo linux_seminfo;
 	struct semid_ds semid;
 	union semun semun;
@@ -530,29 +568,35 @@ linux_semctl(struct thread *td, struct l
 	case LINUX_IPC_SET:
 		cmd = IPC_SET;
 		error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
-		    &linux_semid, PTRIN(args->arg.buf));
+		    &linux_semid64, PTRIN(args->arg.buf));
 		if (error != 0)
 			return (error);
-		linux_to_bsd_semid_ds(&linux_semid, &semid);
+		linux_to_bsd_semid_ds(&linux_semid64, &semid);
 		semun.buf = &semid;
 		return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
 		    td->td_retval));
 	case LINUX_IPC_STAT:
+		cmd = IPC_STAT;
+		semun.buf = &semid;
+		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
+		    &rval);
+		if (error != 0)
+			return (error);
+		bsd_to_linux_semid_ds(&semid, &linux_semid64);
+		return (linux_semid_pushdown(args->cmd & LINUX_IPC_64,
+		    &linux_semid64, PTRIN(args->arg.buf)));
 	case LINUX_SEM_STAT:
-		if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT)
-			cmd = IPC_STAT;
-		else
-			cmd = SEM_STAT;
+		cmd = SEM_STAT;
 		semun.buf = &semid;
 		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
 		    &rval);
 		if (error != 0)
 			return (error);
-		bsd_to_linux_semid_ds(&semid, &linux_semid);
+		bsd_to_linux_semid_ds(&semid, &linux_semid64);
 		error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
-		    &linux_semid, PTRIN(args->arg.buf));
+		    &linux_semid64, PTRIN(args->arg.buf));
 		if (error == 0)
-			td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0;
+			td->td_retval[0] = rval;
 		return (error);
 	case LINUX_IPC_INFO:
 	case LINUX_SEM_INFO:
@@ -575,15 +619,18 @@ linux_semctl(struct thread *td, struct l
 		    PTRIN(args->arg.buf), sizeof(linux_seminfo));
 		if (error != 0)
 			return (error);
+		/*
+		 * TODO: Linux return the last assigned id, not the semmni.
+		 */
 		td->td_retval[0] = seminfo.semmni;
-		return (0);			/* No need for __semctl call */
+		return (0);
 	case LINUX_GETALL:
 		cmd = GETALL;
-		semun.val = args->arg.val;
+		semun.array = PTRIN(args->arg.array);
 		break;
 	case LINUX_SETALL:
 		cmd = SETALL;
-		semun.val = args->arg.val;
+		semun.array = PTRIN(args->arg.array);
 		break;
 	default:
 		linux_msg(td, "ipc type %d is not implemented",
@@ -649,7 +696,7 @@ int
 linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
 {
 	int error, bsd_cmd;
-	struct l_msqid_ds linux_msqid;
+	struct l_msqid64_ds linux_msqid64;
 	struct msqid_ds bsd_msqid;
 
 	bsd_cmd = args->cmd & ~LINUX_IPC_64;
@@ -689,10 +736,10 @@ linux_msgctl(struct thread *td, struct l
 
 	case LINUX_IPC_SET:
 		error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
-		    &linux_msqid, PTRIN(args->buf));
+		    &linux_msqid64, PTRIN(args->buf));
 		if (error != 0)
 			return (error);
-		linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid);
+		linux_to_bsd_msqid_ds(&linux_msqid64, &bsd_msqid);
 		break;
 
 	case LINUX_IPC_RMID:
@@ -705,14 +752,17 @@ linux_msgctl(struct thread *td, struct l
 	}
 
 	error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid);
-	if (error != 0)
+	if (error != 0) {
+		if (bsd_cmd == LINUX_IPC_RMID && error == EACCES)
+			return (EPERM);
 		if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
 			return (error);
+	}
 
 	if (bsd_cmd == LINUX_IPC_STAT) {
-		bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid);
+		bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid64);
 		return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
-		    &linux_msqid, PTRIN(args->buf)));
+		    &linux_msqid64, PTRIN(args->buf)));
 	}
 
 	return (0);
@@ -774,8 +824,8 @@ linux_shmget(struct thread *td, struct l
 int
 linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
 {
-	struct l_shmid_ds linux_shmid;
-	struct l_shminfo linux_shminfo;
+	struct l_shmid64_ds linux_shmid64;
+	struct l_shminfo64 linux_shminfo64;
 	struct l_shm_info linux_shm_info;
 	struct shmid_ds bsd_shmid;
 	int error;
@@ -791,10 +841,10 @@ linux_shmctl(struct thread *td, struct l
 		if (error != 0)
 			return (error);
 
-		bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo);
+		bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo64);
 
 		return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
-		    &linux_shminfo, PTRIN(args->buf)));
+		    &linux_shminfo64, PTRIN(args->buf)));
 	}
 
 	case LINUX_SHM_INFO: {
@@ -819,10 +869,10 @@ linux_shmctl(struct thread *td, struct l
 		if (error != 0)
 			return (error);
 
-		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
+		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64);
 
 		return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
-		    &linux_shmid, PTRIN(args->buf)));
+		    &linux_shmid64, PTRIN(args->buf)));
 
 	case LINUX_SHM_STAT:
 		/* Perform shmctl wanting removed segments lookup */
@@ -831,18 +881,18 @@ linux_shmctl(struct thread *td, struct l
 		if (error != 0)
 			return (error);
 
-		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
+		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64);
 
 		return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
-		    &linux_shmid, PTRIN(args->buf)));
+		    &linux_shmid64, PTRIN(args->buf)));
 
 	case LINUX_IPC_SET:
 		error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
-		    &linux_shmid, PTRIN(args->buf));
+		    &linux_shmid64, PTRIN(args->buf));
 		if (error != 0)
 			return (error);
 
-		linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
+		linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid);
 
 		/* Perform shmctl wanting removed segments lookup */
 		return (kern_shmctl(td, args->shmid, IPC_SET,
@@ -855,10 +905,10 @@ linux_shmctl(struct thread *td, struct l
 			buf = NULL;
 		else {
 			error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
-			    &linux_shmid, PTRIN(args->buf));
+			    &linux_shmid64, PTRIN(args->buf));
 			if (error != 0)
 				return (error);
-			linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
+			linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid);
 			buf = (void *)&bsd_shmid;
 		}
 		return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL));

Copied and modified: head/sys/compat/linux/linux_ipc64.h (from r314865, head/sys/i386/linux/linux_ipc64.h)
==============================================================================
--- head/sys/i386/linux/linux_ipc64.h	Tue Mar  7 16:09:37 2017	(r314865, copy source)
+++ head/sys/compat/linux/linux_ipc64.h	Tue Mar  7 17:07:16 2017	(r314866)
@@ -6,7 +6,7 @@
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer 
+ *    notice, this list of conditions and the following disclaimer
  *    in this position and unchanged.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
@@ -28,19 +28,19 @@
  * $FreeBSD$
  */
 
-#ifndef _I386_LINUX_LINUX_IPC64_H_
-#define	_I386_LINUX_LINUX_IPC64_H_
+#ifndef _LINUX_IPC64_H_
+#define	_LINUX_IPC64_H_
 
 /*
- * The ipc64_perm structure for i386 architecture.
+ * The generic ipc64_perm structure.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
  *
  * Pad space is left for:
- * - 32-bit mode_t and seq
+ * - 32-bit mode_t on architectures that only had 16 bit
+ * - 32-bit seq
  * - 2 miscellaneous 32-bit values
  */
-
 struct l_ipc64_perm
 {
 	l_key_t		key;
@@ -49,7 +49,8 @@ struct l_ipc64_perm
 	l_uid_t		cuid;
 	l_gid_t		cgid;
 	l_mode_t	mode;
-	l_ushort	__pad1;
+			/* pad if mode_t is ushort: */
+	unsigned char	__pad1[sizeof(l_int) - sizeof(l_mode_t)];
 	l_ushort	seq;
 	l_ushort	__pad2;
 	l_ulong		__unused1;
@@ -57,7 +58,7 @@ struct l_ipc64_perm
 };
 
 /*
- * The msqid64_ds structure for i386 architecture.
+ * The generic msqid64_ds structure fro x86 architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
  *
@@ -69,11 +70,17 @@ struct l_ipc64_perm
 struct l_msqid64_ds {
 	struct l_ipc64_perm msg_perm;
 	l_time_t	msg_stime;	/* last msgsnd time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
 	l_ulong		__unused1;
+#endif
 	l_time_t	msg_rtime;	/* last msgrcv time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
 	l_ulong		__unused2;
+#endif
 	l_time_t	msg_ctime;	/* last change time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
 	l_ulong		__unused3;
+#endif
 	l_ulong		msg_cbytes;	/* current number of bytes on queue */
 	l_ulong		msg_qnum;	/* number of messages in queue */
 	l_ulong		msg_qbytes;	/* max number of bytes on queue */
@@ -84,7 +91,7 @@ struct l_msqid64_ds {
 };
 
 /*
- * The semid64_ds structure for i386 architecture.
+ * The generic semid64_ds structure for x86 architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
  *
@@ -105,7 +112,7 @@ struct l_semid64_ds {
 };
 
 /*
- * The shmid64_ds structure for i386 architecture.
+ * The generic shmid64_ds structure for x86 architecture.
  * Note extra padding because this structure is passed back and forth
  * between kernel and user space.
  *
@@ -118,11 +125,17 @@ struct l_shmid64_ds {
 	struct l_ipc64_perm shm_perm;	/* operation perms */
 	l_size_t	shm_segsz;	/* size of segment (bytes) */
 	l_time_t	shm_atime;	/* last attach time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
 	l_ulong		__unused1;
+#endif
 	l_time_t	shm_dtime;	/* last detach time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
 	l_ulong		__unused2;
+#endif
 	l_time_t	shm_ctime;	/* last change time */
+#if !defined(__LP64__) || defined(COMPAT_LINUX32)
 	l_ulong		__unused3;
+#endif
 	l_pid_t		shm_cpid;	/* pid of creator */
 	l_pid_t		shm_lpid;	/* pid of last operator */
 	l_ulong		shm_nattch;	/* no. of current attaches */
@@ -131,15 +144,15 @@ struct l_shmid64_ds {
 };
 
 struct l_shminfo64 {
-	l_ulong   	shmmax;
-	l_ulong   	shmmin;
-	l_ulong   	shmmni;
-	l_ulong   	shmseg;
-	l_ulong   	shmall;
+	l_ulong		shmmax;
+	l_ulong		shmmin;
+	l_ulong		shmmni;
+	l_ulong		shmseg;
+	l_ulong		shmall;
 	l_ulong   	__unused1;
-	l_ulong   	__unused2;
-	l_ulong   	__unused3;
-	l_ulong   	__unused4;
+	l_ulong		__unused2;
+	l_ulong		__unused3;
+	l_ulong		__unused4;
 };
 
-#endif /* !_I386_LINUX_LINUX_IPC64_H_ */
+#endif /* !LINUX_IPC64_H_ */

Modified: head/sys/i386/linux/linux.h
==============================================================================
--- head/sys/i386/linux/linux.h	Tue Mar  7 16:09:37 2017	(r314865)
+++ head/sys/i386/linux/linux.h	Tue Mar  7 17:07:16 2017	(r314866)
@@ -453,16 +453,6 @@ union l_semun {
 	void		*__pad;
 };
 
-struct l_ipc_perm {
-	l_key_t		key;
-	l_uid16_t	uid;
-	l_gid16_t	gid;
-	l_uid16_t	cuid;
-	l_gid16_t	cgid;
-	l_ushort	mode;
-	l_ushort	seq;
-};
-
 /*
  * Socket defines
  */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703071707.v27H7GVL058242>