Bug 149168 - [linux] [patch] Linux sendmsg / recvmsg / etc fixes for pulseaudio
Summary: [linux] [patch] Linux sendmsg / recvmsg / etc fixes for pulseaudio
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Andriy Gapon
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-01 05:30 UTC by john
Modified: 2011-04-09 10:40 UTC (History)
0 users

See Also:


Attachments
file.diff (10.92 KB, patch)
2010-08-01 05:30 UTC, john
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description john 2010-08-01 05:30:04 UTC
The enclosed lightly tested patch extends the Linux emulation
so that pulseaudio runs.  Specifically tested:

  a) Fedora 10 paplay (client) talking to FreeBSD 8.1 pulseaudio (server)
     over both TCP and UNIX domain sockets.

  b) FreeBSD 8.1 paplay (client) talking to Fedora 10 pulseaudio (server)
     over both TCP and UNIX domain sockets.

  c) Fedora 10 paplay (client) talking to Fedora 10 pulseaudio (server)
     over both TCP and UNIX domain sockets.

Changes:

  1) Implement NO-OP stubs for capget, capset, prctl PR_GET_KEEPCAPS,
     and prctl PR_SET_KEEPCAPS so that the pulseaudio server will
     start.

  2) Added SCM_CREDS support to sendmsg and recvmsg.

  3) Modify sendmsg to ignore control messages if not using UNIX
     domain sockets.

Fix: Patch attached with submission follows:
How-To-Repeat: Install the Fedora 10 pulseaudio client / server software and try
using paplay.
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2010-08-03 01:11:26 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-emulation

Over to maintainer(s).
Comment 2 Andriy Gapon freebsd_committer freebsd_triage 2011-02-07 21:43:12 UTC
John,
couple of comments for the patch:

1. What is a reason for "msg_controllen skipped" ?  Is this a proper 
solution or some hacking remnants?

2. amd64 counterparts of changes in i386 arch code are missing.  Those 
should be trivial to add.

Roman,
do you have additional comments which I might have forgotten?

Thanks!
-- 
Andriy Gapon
Comment 3 john 2011-02-08 05:28:29 UTC
>  1. What is a reason for "msg_controllen skipped" ?  Is this a proper 
> solution or some hacking remnants?

It's in the spirit of /* msg_flags skipped */.

Since the BSD and LINUX control messages are potentially different
sizes (e.g. the cred structure used by SCM_CREDS is different between
the two operating system) you can't just copy msg_controllen.
linux_recvmsg fills in the proper value after it has parse / converted
the control messages.

For consistency it would probably be nice if this was also reflected
in linux_to_bsd_msghdr / linux_sendmsg.  I'm happy to address this
issue, though it existed prior to my patch so I don't know if you
want me to just bundle the necessary changes into an updated version
of my patch for kern/149168 or if you want it addressed as in separate
patch.

> 2. amd64 counterparts of changes in i386 arch code are missing.  Those 
> should be trivial to add.

Yep ... the original patch probably should have had a comment to the effect:

  a) The amd64 counterparts of the changes in the i386 arch code are not
     supplied since I don't have a way of testing amd64 changes and I
     try to avoid supplying untested code.

  b) The changes should be trivial to implement by someone who has an
     amd64 environment.

-- John
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 4 Roman Divacky freebsd_committer freebsd_triage 2011-02-08 07:57:51 UTC
you also want to modify syscalls.master instead of the script
generated .h files

On Mon, Feb 07, 2011 at 04:43:12PM -0500, Andriy Gapon wrote:
> 
> John,
> couple of comments for the patch:
> 
> 1. What is a reason for "msg_controllen skipped" ?  Is this a proper 
> solution or some hacking remnants?
> 
> 2. amd64 counterparts of changes in i386 arch code are missing.  Those 
> should be trivial to add.
> 
> Roman,
> do you have additional comments which I might have forgotten?
> 
> Thanks!
> -- 
> Andriy Gapon
Comment 5 john 2011-02-09 22:04:45 UTC
> you also want to modify syscalls.master instead of the script
> generated .h files

Thanks for pointing that out.

I can see about putting together a tweaked version of the patch this weekend.

-- John
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 6 john 2011-02-13 06:59:43 UTC
Enclosed is a slightly tweaked and lightly tested version.

Changes from previous:

  1) Modify linux/syscalls.master in i386 & amd64 instead of mucking a
     generated file.

  2) For symmetry also ignore msg_controllen in linux_to_bsd_msghdr.

-- John
-----------------------8<----------------------------8<------------------
--- ./compat/linux/linux_misc.h.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_misc.h	2011-02-12 22:36:57.000000000 -0500
@@ -37,6 +37,8 @@
 					 * Second arg is a ptr to return the
 					 * signal.
 					 */
+#define	LINUX_PR_GET_KEEPCAPS	7	/* Get drop capabilities on setuid */
+#define	LINUX_PR_SET_KEEPCAPS	8	/* Set drop capabilities on setuid */
 #define	LINUX_PR_SET_NAME	15	/* Set process name. */
 #define	LINUX_PR_GET_NAME	16	/* Get process name. */
 
--- ./compat/linux/linux_misc.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_misc.c	2011-02-12 22:36:57.000000000 -0500
@@ -1733,6 +1733,87 @@ linux_exit_group(struct thread *td, stru
 	return (0);
 }
 
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+struct l_user_cap_header {
+	l_int	version;
+	l_int	pid;
+};
+
+struct l_user_cap_data {
+	l_int	effective;
+	l_int	permitted;
+	l_int	inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (! args->hdrp)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	if (args->datap) {
+		bzero (&lucd, sizeof(lucd));
+		error = copyout(&lucd, args->datap, sizeof(lucd));
+	}
+
+	return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (! args->hdrp || ! args->datap)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	error = copyin(args->datap, &lucd, sizeof(lucd));
+	if (error != 0)
+		return (error);
+
+	if (lucd.effective || lucd.permitted || lucd.inheritable)
+		return (EPERM);
+
+	return (0);
+}
+
 int
 linux_prctl(struct thread *td, struct linux_prctl_args *args)
 {
@@ -1766,6 +1847,11 @@ linux_prctl(struct thread *td, struct li
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
 		break;
+	case LINUX_PR_GET_KEEPCAPS:
+		td->td_retval[0] = 0;
+		break;
+	case LINUX_PR_SET_KEEPCAPS:
+		break;
 	case LINUX_PR_SET_NAME:
 		/*
 		 * To be on the safe side we need to make sure to not
--- ./compat/linux/linux_socket.h.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_socket.h	2011-02-12 22:36:57.000000000 -0500
@@ -53,6 +53,7 @@
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
+#define LINUX_SCM_CREDENTIALS   0x02
 
 /* Ancilliary data object information macros */
 
--- ./compat/linux/linux_socket.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_socket.c	2011-02-13 00:22:58.000000000 -0500
@@ -433,6 +433,8 @@ linux_to_bsd_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case LINUX_SCM_RIGHTS:
 		return (SCM_RIGHTS);
+	case LINUX_SCM_CREDENTIALS:
+		return (SCM_CREDS);
 	}
 	return (-1);
 }
@@ -444,6 +446,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case SCM_RIGHTS:
 		return (LINUX_SCM_RIGHTS);
+	case SCM_CREDS:
+		return (LINUX_SCM_CREDENTIALS);
 	}
 	return (-1);
 }
@@ -459,7 +463,7 @@ linux_to_bsd_msghdr(struct msghdr *bhdr,
 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
-	bhdr->msg_controllen	= lhdr->msg_controllen;
+	/* msg_controllen skipped */
 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
 	return (0);
 }
@@ -472,7 +476,7 @@ bsd_to_linux_msghdr(const struct msghdr 
 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
-	lhdr->msg_controllen	= bhdr->msg_controllen;
+	/* msg_controllen skipped */
 	/* msg_flags skipped */
 	return (0);
 }
@@ -1092,6 +1096,7 @@ static int
 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 {
 	struct cmsghdr *cmsg;
+	struct cmsgcred cmcred;
 	struct mbuf *control;
 	struct msghdr msg;
 	struct l_cmsghdr linux_cmsg;
@@ -1099,15 +1104,14 @@ linux_sendmsg(struct thread *td, struct 
 	struct l_msghdr linux_msg;
 	struct iovec *iov;
 	socklen_t datalen;
+	struct sockaddr *sa;
+	sa_family_t sa_family;
 	void *data;
 	int error;
 
 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
 	if (error)
 		return (error);
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
-		return (error);
 
 	/*
 	 * Some Linux applications (ping) define a non-NULL control data
@@ -1116,8 +1120,12 @@ linux_sendmsg(struct thread *td, struct 
 	 * order to handle this case.  This should be checked, but allows the
 	 * Linux ping to work.
 	 */
-	if (msg.msg_control != NULL && msg.msg_controllen == 0)
-		msg.msg_control = NULL;
+	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
+		linux_msg.msg_control = PTROUT(NULL);
+
+	error = linux_to_bsd_msghdr(&msg, &linux_msg);
+	if (error)
+		return (error);
 
 #ifdef COMPAT_LINUX32
 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
@@ -1128,13 +1136,21 @@ linux_sendmsg(struct thread *td, struct 
 	if (error)
 		return (error);
 
-	if (msg.msg_control != NULL) {
+	control = NULL;
+	cmsg = NULL;
+
+	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
+		error = kern_getsockname(td, args->s, &sa, &datalen);
+		if (error)
+			goto bad;
+		sa_family = sa->sa_family;
+		free(sa, M_SONAME);
+
 		error = ENOBUFS;
 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
 		control = m_get(M_WAIT, MT_CONTROL);
 		if (control == NULL)
 			goto bad;
-		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
@@ -1147,18 +1163,46 @@ linux_sendmsg(struct thread *td, struct 
 				goto bad;
 
 			/*
-			 * Now we support only SCM_RIGHTS, so return EINVAL
-			 * in any other cmsg_type
+			 * Now we support only SCM_RIGHTS and SCM_CRED,
+			 * so return EINVAL in any other cmsg_type
 			 */
-			if ((cmsg->cmsg_type =
-			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
-				goto bad;
+			cmsg->cmsg_type =
+			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
 			cmsg->cmsg_level =
 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+			if (cmsg->cmsg_type == -1
+			    || cmsg->cmsg_level != SOL_SOCKET)
+				goto bad;
+
+			/*
+			 * Some applications (e.g. pulseaudio) attempt to
+			 * send ancillary data even if the underlying protocol
+			 * doesn't support it which is not allowed in the
+			 * FreeBSD system call interface.
+			 */
+			if (sa_family != AF_UNIX)
+				continue;
 
+			data = LINUX_CMSG_DATA(ptr_cmsg);
 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+
+			switch (cmsg->cmsg_type)
+			{
+			case SCM_RIGHTS:
+				break;
+
+			case SCM_CREDS:
+				data = &cmcred;
+				datalen = sizeof(cmcred);
+
+				/*
+				 * The lower levels will fill in the structure
+				 */
+				bzero(data, datalen);
+				break;
+			}
+
 			cmsg->cmsg_len = CMSG_LEN(datalen);
-			data = LINUX_CMSG_DATA(ptr_cmsg);
 
 			error = ENOBUFS;
 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
@@ -1166,9 +1210,11 @@ linux_sendmsg(struct thread *td, struct 
 			if (!m_append(control, datalen, (c_caddr_t) data))
 				goto bad;
 		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
-	} else {
-		control = NULL;
-		cmsg = NULL;
+
+		if (m_length(control, NULL) == 0) {
+			m_freem(control);
+			control = NULL;
+		}
 	}
 
 	msg.msg_iov = iov;
@@ -1193,9 +1239,11 @@ static int
 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 {
 	struct cmsghdr *cm;
+	struct cmsgcred *cmcred;
 	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
-	socklen_t datalen, outlen, clen;
+	struct l_ucred linux_ucred;
+	socklen_t datalen, outlen;
 	struct l_msghdr linux_msg;
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
@@ -1252,39 +1300,35 @@ linux_recvmsg(struct thread *td, struct 
 			goto bad;
 	}
 
-	if (control) {
+	outbuf = PTRIN(linux_msg.msg_control);
+	outlen = 0;
 
+	if (control) {
 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		outbuf = PTRIN(linux_msg.msg_control);
-		cm = mtod(control, struct cmsghdr *);
-		outlen = 0;
-		clen = control->m_len;
 
-		while (cm != NULL) {
+		msg.msg_control = mtod(control, struct cmsghdr *);
+		msg.msg_controllen = control->m_len;
+
+		cm = CMSG_FIRSTHDR(&msg);
 
-			if ((linux_cmsg->cmsg_type =
-			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
+		while (cm != NULL) {
+			linux_cmsg->cmsg_type =
+			    bsd_to_linux_cmsg_type(cm->cmsg_type);
+			linux_cmsg->cmsg_level =
+			    bsd_to_linux_sockopt_level(cm->cmsg_level);
+			if (linux_cmsg->cmsg_type == -1
+			    || cm->cmsg_level != SOL_SOCKET)
 			{
 				error = EINVAL;
 				goto bad;
 			}
+
 			data = CMSG_DATA(cm);
 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 
-			switch (linux_cmsg->cmsg_type)
+			switch (cm->cmsg_type)
 			{
-			case LINUX_SCM_RIGHTS:
-				if (outlen + LINUX_CMSG_LEN(datalen) >
-				    linux_msg.msg_controllen) {
-					if (outlen == 0) {
-						error = EMSGSIZE;
-						goto bad;
-					} else {
-						linux_msg.msg_flags |=
-						    LINUX_MSG_CTRUNC;
-						goto out;
-					}
-				}
+			case SCM_RIGHTS:
 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
@@ -1295,11 +1339,40 @@ linux_recvmsg(struct thread *td, struct 
 					}
 				}
 				break;
+
+			case SCM_CREDS:
+				/*
+				 * Currently LOCAL_CREDS is never in
+				 * effect for Linux so no need to worry
+				 * about sockcred
+				 */
+				if (datalen != sizeof (*cmcred)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				cmcred = (struct cmsgcred *)data;
+				bzero(&linux_ucred, sizeof(linux_ucred));
+				linux_ucred.pid = cmcred->cmcred_pid;
+				linux_ucred.uid = cmcred->cmcred_uid;
+				linux_ucred.gid = cmcred->cmcred_gid;
+				data = &linux_ucred;
+				datalen = sizeof(linux_ucred);
+				break;
+			}
+
+			if (outlen + LINUX_CMSG_LEN(datalen) >
+			    linux_msg.msg_controllen) {
+				if (outlen == 0) {
+					error = EMSGSIZE;
+					goto bad;
+				} else {
+					linux_msg.msg_flags |=
+					    LINUX_MSG_CTRUNC;
+					goto out;
+				}
 			}
 
 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
-			linux_cmsg->cmsg_level =
-			    bsd_to_linux_sockopt_level(cm->cmsg_level);
 
 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
 			if (error)
@@ -1312,18 +1385,13 @@ linux_recvmsg(struct thread *td, struct 
 
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
-			linux_msg.msg_controllen = outlen;
 
-			if (CMSG_SPACE(datalen) < clen) {
-				clen -= CMSG_SPACE(datalen);
-				cm = (struct cmsghdr *)
-				    ((caddr_t)cm + CMSG_SPACE(datalen));
-			} else
-				cm = NULL;
+			cm = CMSG_NXTHDR(&msg, cm);
 		}
 	}
 
 out:
+	linux_msg.msg_controllen = outlen;
 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
 
 bad:
--- ./i386/linux/linux_dummy.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./i386/linux/linux_dummy.c	2011-02-12 22:36:57.000000000 -0500
@@ -57,8 +57,6 @@ DUMMY(vm86);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);		/* different semantics */
 DUMMY(setfsuid);
 DUMMY(setfsgid);
--- ./i386/linux/syscalls.master.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./i386/linux/syscalls.master	2011-02-12 22:50:39.000000000 -0500
@@ -329,8 +329,8 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(void *hdrp, void *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(void *hdrp, const void *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
--- ./amd64/linux32/syscalls.master.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./amd64/linux32/syscalls.master	2011-02-12 22:50:35.000000000 -0500
@@ -327,8 +327,8 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(void *hdrp, void *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(void *hdrp, const void *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 7 Andriy Gapon freebsd_committer freebsd_triage 2011-02-26 18:13:02 UTC
on 13/02/2011 08:59 John Wehle said the following:
> Enclosed is a slightly tweaked and lightly tested version.
> 
> Changes from previous:
> 
>   1) Modify linux/syscalls.master in i386 & amd64 instead of mucking a
>      generated file.
> 
>   2) For symmetry also ignore msg_controllen in linux_to_bsd_msghdr.

The patch is still missing changes to sys/amd64/linux32/linux32_dummy.c, but
otherwise looks good.

-- 
Andriy Gapon
Comment 8 Andriy Gapon freebsd_committer freebsd_triage 2011-02-27 10:01:25 UTC
on 26/02/2011 20:13 Andriy Gapon said the following:
> on 13/02/2011 08:59 John Wehle said the following:
>> Enclosed is a slightly tweaked and lightly tested version.
>>
>> Changes from previous:
>>
>>   1) Modify linux/syscalls.master in i386 & amd64 instead of mucking a
>>      generated file.
>>
>>   2) For symmetry also ignore msg_controllen in linux_to_bsd_msghdr.
> 
> The patch is still missing changes to sys/amd64/linux32/linux32_dummy.c, but
> otherwise looks good.
> 

I wasn't right.
Unfortunately, with this patch (unlike its original version) linux skype no
longer connects to FreeBSD pulseaudio daemon for me on CURRENT/amd64.
So something important seems to have been lost or broken while making the
improvements.

-- 
Andriy Gapon
Comment 9 john 2011-02-28 07:57:26 UTC
> Unfortunately, with this patch (unlike its original version) linux skype no
> longer connects to FreeBSD pulseaudio daemon for me on CURRENT/amd64.
> So something important seems to have been lost or broken while making the
> improvements.

That's a bit strange.  The amd64 specific bits are for capget / capset
which are only used if you're running the Linux pulseaudio daemon,
they're not used by the client code so I don't suspect a problem
there.

The rest of the code works fine (at least under light use) on my
FreeBSD 8.2 i386 machine. The only changes between this patch and
the previous are:

  a) Mucking linux/syscalls.master in i386 & amd64 ... unlikely
     to be a problem.

  b) "Cosmetic" change to linux_to_bsd_msghdr / linux_sendmsg to
     also ignore msg_controllen.  The change was unnecessary and
     rather minor, however it made the msg_controllen handling
     more symmetrical.

     Not sure what would have work on the i386 and not amd64 in what
     I mucked. :-(

Are you sure the problem is with the later patch?  Did anything else
change in your environment?  Does paplay work?  If not, what does
paplay / pulseaudio daemon debug report?

I'm not setup with CURRENT or amd64 ... how do you want to proceed?
Do you want to provide access to a CURRENT/amd64 machine that I
can reboot / muck the kernel?  Do you want to debug this?  Should
I invest in setting up FreeBSD CURRENT/amd64 running under QEMU / Virtualbox?

Don't mean to be asking too many questions. :-)  Just interesting in
the game plan.

-- John
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 10 john 2011-02-28 08:04:41 UTC
> Not sure what would have work on the i386 and not amd64 in what
>  I mucked. :-(

Grumble ... of course after I send the message I think I see something.
Give me a couple of days to poke about and I'll get back to you with
an update.

-- John
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 11 john 2011-03-08 07:32:09 UTC
Enclosed is yet another slightly tweaked and lightly tested version.

I made a bootable amd64 drive which mirrors my existing i386 system
so I was able to test these changes on both amd64 and i386.

Changes from previous:

  1) Include changes to amd64/linux32/linux32_dummy.c.

  2) Use PTRIN in LINUX_CMSG_FIRSTHDR and LINUX_CMSG_NXTHDR so
     linux_socket.c compiles without complaints on amd64.

  3) Invoke LINUX_CMSG_NXTHDR with the correct variable (basically
     I missed a place in my last round of changes).

Notes:

  1) This has been tested on both i386 and amd64 with Fedora 10 paplay
     (client) talking to FreeBSD 8.2 pulseaudio (server) over both TCP
     and UNIX domain sockets.

  2) PulseAudio generates the socket name slightly differently between
     FreeBSD and Linux.  When using UNIX domain sockets please set
     PULSE_SERVER prior to invoking the client application.  E.g.:

       setenv PULSE_SERVER unix:/tmp/pulse-J1eO0ABCS0DM/native

     where /tmp/pulse-J1eO0ABCS0DM/native is the name of the FreeBSD
     PulseAudio socket.  Someone knowledgeable may be able to muck

       /usr/compat/linux/etc/pulse/client.conf

     so this is not necessary.

-- John
-----------------------8<----------------------------8<------------------
--- ./compat/linux/linux_misc.h.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_misc.h	2011-02-26 22:41:49.000000000 -0500
@@ -37,6 +37,8 @@
 					 * Second arg is a ptr to return the
 					 * signal.
 					 */
+#define	LINUX_PR_GET_KEEPCAPS	7	/* Get drop capabilities on setuid */
+#define	LINUX_PR_SET_KEEPCAPS	8	/* Set drop capabilities on setuid */
 #define	LINUX_PR_SET_NAME	15	/* Set process name. */
 #define	LINUX_PR_GET_NAME	16	/* Get process name. */
 
--- ./compat/linux/linux_misc.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_misc.c	2011-02-26 22:41:49.000000000 -0500
@@ -1733,6 +1733,87 @@ linux_exit_group(struct thread *td, stru
 	return (0);
 }
 
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+struct l_user_cap_header {
+	l_int	version;
+	l_int	pid;
+};
+
+struct l_user_cap_data {
+	l_int	effective;
+	l_int	permitted;
+	l_int	inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (! args->hdrp)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	if (args->datap) {
+		bzero (&lucd, sizeof(lucd));
+		error = copyout(&lucd, args->datap, sizeof(lucd));
+	}
+
+	return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (! args->hdrp || ! args->datap)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	error = copyin(args->datap, &lucd, sizeof(lucd));
+	if (error != 0)
+		return (error);
+
+	if (lucd.effective || lucd.permitted || lucd.inheritable)
+		return (EPERM);
+
+	return (0);
+}
+
 int
 linux_prctl(struct thread *td, struct linux_prctl_args *args)
 {
@@ -1766,6 +1847,11 @@ linux_prctl(struct thread *td, struct li
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
 		break;
+	case LINUX_PR_GET_KEEPCAPS:
+		td->td_retval[0] = 0;
+		break;
+	case LINUX_PR_SET_KEEPCAPS:
+		break;
 	case LINUX_PR_SET_NAME:
 		/*
 		 * To be on the safe side we need to make sure to not
--- ./compat/linux/linux_socket.h.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_socket.h	2011-03-07 23:40:31.000000000 -0500
@@ -53,6 +53,7 @@
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
+#define LINUX_SCM_CREDENTIALS   0x02
 
 /* Ancilliary data object information macros */
 
@@ -66,13 +67,14 @@
 #define LINUX_CMSG_FIRSTHDR(msg) \
 				((msg)->msg_controllen >= \
 				    sizeof(struct l_cmsghdr) ? \
-				    (struct l_cmsghdr *)((msg)->msg_control) : \
+				    (struct l_cmsghdr *) \
+				        PTRIN((msg)->msg_control) : \
 				    (struct l_cmsghdr *)(NULL))
 #define LINUX_CMSG_NXTHDR(msg, cmsg) \
 				((((char *)(cmsg) + \
 				    LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \
 				    sizeof(*(cmsg))) > \
-				    (((char *)(msg)->msg_control) + \
+				    (((char *)PTRIN((msg)->msg_control)) + \
 				    (msg)->msg_controllen)) ? \
 				    (struct l_cmsghdr *) NULL : \
 				    (struct l_cmsghdr *)((char *)(cmsg) + \
--- ./compat/linux/linux_socket.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_socket.c	2011-03-07 23:38:21.000000000 -0500
@@ -433,6 +433,8 @@ linux_to_bsd_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case LINUX_SCM_RIGHTS:
 		return (SCM_RIGHTS);
+	case LINUX_SCM_CREDENTIALS:
+		return (SCM_CREDS);
 	}
 	return (-1);
 }
@@ -444,6 +446,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case SCM_RIGHTS:
 		return (LINUX_SCM_RIGHTS);
+	case SCM_CREDS:
+		return (LINUX_SCM_CREDENTIALS);
 	}
 	return (-1);
 }
@@ -459,7 +463,7 @@ linux_to_bsd_msghdr(struct msghdr *bhdr,
 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
-	bhdr->msg_controllen	= lhdr->msg_controllen;
+	/* msg_controllen skipped */
 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
 	return (0);
 }
@@ -472,7 +476,7 @@ bsd_to_linux_msghdr(const struct msghdr 
 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
-	lhdr->msg_controllen	= bhdr->msg_controllen;
+	/* msg_controllen skipped */
 	/* msg_flags skipped */
 	return (0);
 }
@@ -1092,6 +1096,7 @@ static int
 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 {
 	struct cmsghdr *cmsg;
+	struct cmsgcred cmcred;
 	struct mbuf *control;
 	struct msghdr msg;
 	struct l_cmsghdr linux_cmsg;
@@ -1099,15 +1104,14 @@ linux_sendmsg(struct thread *td, struct 
 	struct l_msghdr linux_msg;
 	struct iovec *iov;
 	socklen_t datalen;
+	struct sockaddr *sa;
+	sa_family_t sa_family;
 	void *data;
 	int error;
 
 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
 	if (error)
 		return (error);
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
-		return (error);
 
 	/*
 	 * Some Linux applications (ping) define a non-NULL control data
@@ -1116,8 +1120,12 @@ linux_sendmsg(struct thread *td, struct 
 	 * order to handle this case.  This should be checked, but allows the
 	 * Linux ping to work.
 	 */
-	if (msg.msg_control != NULL && msg.msg_controllen == 0)
-		msg.msg_control = NULL;
+	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
+		linux_msg.msg_control = PTROUT(NULL);
+
+	error = linux_to_bsd_msghdr(&msg, &linux_msg);
+	if (error)
+		return (error);
 
 #ifdef COMPAT_LINUX32
 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
@@ -1128,13 +1136,21 @@ linux_sendmsg(struct thread *td, struct 
 	if (error)
 		return (error);
 
-	if (msg.msg_control != NULL) {
+	control = NULL;
+	cmsg = NULL;
+
+	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
+		error = kern_getsockname(td, args->s, &sa, &datalen);
+		if (error)
+			goto bad;
+		sa_family = sa->sa_family;
+		free(sa, M_SONAME);
+
 		error = ENOBUFS;
 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
 		control = m_get(M_WAIT, MT_CONTROL);
 		if (control == NULL)
 			goto bad;
-		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
@@ -1147,28 +1163,58 @@ linux_sendmsg(struct thread *td, struct 
 				goto bad;
 
 			/*
-			 * Now we support only SCM_RIGHTS, so return EINVAL
-			 * in any other cmsg_type
+			 * Now we support only SCM_RIGHTS and SCM_CRED,
+			 * so return EINVAL in any other cmsg_type
 			 */
-			if ((cmsg->cmsg_type =
-			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
-				goto bad;
+			cmsg->cmsg_type =
+			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
 			cmsg->cmsg_level =
 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+			if (cmsg->cmsg_type == -1
+			    || cmsg->cmsg_level != SOL_SOCKET)
+				goto bad;
+
+			/*
+			 * Some applications (e.g. pulseaudio) attempt to
+			 * send ancillary data even if the underlying protocol
+			 * doesn't support it which is not allowed in the
+			 * FreeBSD system call interface.
+			 */
+			if (sa_family != AF_UNIX)
+				continue;
 
+			data = LINUX_CMSG_DATA(ptr_cmsg);
 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+
+			switch (cmsg->cmsg_type)
+			{
+			case SCM_RIGHTS:
+				break;
+
+			case SCM_CREDS:
+				data = &cmcred;
+				datalen = sizeof(cmcred);
+
+				/*
+				 * The lower levels will fill in the structure
+				 */
+				bzero(data, datalen);
+				break;
+			}
+
 			cmsg->cmsg_len = CMSG_LEN(datalen);
-			data = LINUX_CMSG_DATA(ptr_cmsg);
 
 			error = ENOBUFS;
 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
 				goto bad;
 			if (!m_append(control, datalen, (c_caddr_t) data))
 				goto bad;
-		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
-	} else {
-		control = NULL;
-		cmsg = NULL;
+		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
+
+		if (m_length(control, NULL) == 0) {
+			m_freem(control);
+			control = NULL;
+		}
 	}
 
 	msg.msg_iov = iov;
@@ -1193,9 +1239,11 @@ static int
 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 {
 	struct cmsghdr *cm;
+	struct cmsgcred *cmcred;
 	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
-	socklen_t datalen, outlen, clen;
+	struct l_ucred linux_ucred;
+	socklen_t datalen, outlen;
 	struct l_msghdr linux_msg;
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
@@ -1252,39 +1300,35 @@ linux_recvmsg(struct thread *td, struct 
 			goto bad;
 	}
 
-	if (control) {
+	outbuf = PTRIN(linux_msg.msg_control);
+	outlen = 0;
 
+	if (control) {
 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		outbuf = PTRIN(linux_msg.msg_control);
-		cm = mtod(control, struct cmsghdr *);
-		outlen = 0;
-		clen = control->m_len;
 
-		while (cm != NULL) {
+		msg.msg_control = mtod(control, struct cmsghdr *);
+		msg.msg_controllen = control->m_len;
+
+		cm = CMSG_FIRSTHDR(&msg);
 
-			if ((linux_cmsg->cmsg_type =
-			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
+		while (cm != NULL) {
+			linux_cmsg->cmsg_type =
+			    bsd_to_linux_cmsg_type(cm->cmsg_type);
+			linux_cmsg->cmsg_level =
+			    bsd_to_linux_sockopt_level(cm->cmsg_level);
+			if (linux_cmsg->cmsg_type == -1
+			    || cm->cmsg_level != SOL_SOCKET)
 			{
 				error = EINVAL;
 				goto bad;
 			}
+
 			data = CMSG_DATA(cm);
 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 
-			switch (linux_cmsg->cmsg_type)
+			switch (cm->cmsg_type)
 			{
-			case LINUX_SCM_RIGHTS:
-				if (outlen + LINUX_CMSG_LEN(datalen) >
-				    linux_msg.msg_controllen) {
-					if (outlen == 0) {
-						error = EMSGSIZE;
-						goto bad;
-					} else {
-						linux_msg.msg_flags |=
-						    LINUX_MSG_CTRUNC;
-						goto out;
-					}
-				}
+			case SCM_RIGHTS:
 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
@@ -1295,11 +1339,40 @@ linux_recvmsg(struct thread *td, struct 
 					}
 				}
 				break;
+
+			case SCM_CREDS:
+				/*
+				 * Currently LOCAL_CREDS is never in
+				 * effect for Linux so no need to worry
+				 * about sockcred
+				 */
+				if (datalen != sizeof (*cmcred)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				cmcred = (struct cmsgcred *)data;
+				bzero(&linux_ucred, sizeof(linux_ucred));
+				linux_ucred.pid = cmcred->cmcred_pid;
+				linux_ucred.uid = cmcred->cmcred_uid;
+				linux_ucred.gid = cmcred->cmcred_gid;
+				data = &linux_ucred;
+				datalen = sizeof(linux_ucred);
+				break;
+			}
+
+			if (outlen + LINUX_CMSG_LEN(datalen) >
+			    linux_msg.msg_controllen) {
+				if (outlen == 0) {
+					error = EMSGSIZE;
+					goto bad;
+				} else {
+					linux_msg.msg_flags |=
+					    LINUX_MSG_CTRUNC;
+					goto out;
+				}
 			}
 
 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
-			linux_cmsg->cmsg_level =
-			    bsd_to_linux_sockopt_level(cm->cmsg_level);
 
 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
 			if (error)
@@ -1312,18 +1385,13 @@ linux_recvmsg(struct thread *td, struct 
 
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
-			linux_msg.msg_controllen = outlen;
 
-			if (CMSG_SPACE(datalen) < clen) {
-				clen -= CMSG_SPACE(datalen);
-				cm = (struct cmsghdr *)
-				    ((caddr_t)cm + CMSG_SPACE(datalen));
-			} else
-				cm = NULL;
+			cm = CMSG_NXTHDR(&msg, cm);
 		}
 	}
 
 out:
+	linux_msg.msg_controllen = outlen;
 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
 
 bad:
--- ./i386/linux/linux_dummy.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./i386/linux/linux_dummy.c	2011-02-26 22:41:49.000000000 -0500
@@ -57,8 +57,6 @@ DUMMY(vm86);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);		/* different semantics */
 DUMMY(setfsuid);
 DUMMY(setfsgid);
--- ./i386/linux/syscalls.master.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./i386/linux/syscalls.master	2011-02-26 22:41:49.000000000 -0500
@@ -329,8 +329,8 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(void *hdrp, void *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(void *hdrp, const void *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
--- ./amd64/linux32/linux32_dummy.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./amd64/linux32/linux32_dummy.c	2011-03-07 23:36:02.000000000 -0500
@@ -54,8 +54,6 @@ DUMMY(sysfs);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);
--- ./amd64/linux32/syscalls.master.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./amd64/linux32/syscalls.master	2011-02-26 22:41:49.000000000 -0500
@@ -327,8 +327,8 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(void *hdrp, void *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(void *hdrp, const void *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 12 Andriy Gapon freebsd_committer freebsd_triage 2011-03-10 09:54:31 UTC
on 08/03/2011 09:32 John Wehle said the following:
> Enclosed is yet another slightly tweaked and lightly tested version.
> 
> I made a bootable amd64 drive which mirrors my existing i386 system
> so I was able to test these changes on both amd64 and i386.
> 
> Changes from previous:
> 
>   1) Include changes to amd64/linux32/linux32_dummy.c.
> 
>   2) Use PTRIN in LINUX_CMSG_FIRSTHDR and LINUX_CMSG_NXTHDR so
>      linux_socket.c compiles without complaints on amd64.
> 
>   3) Invoke LINUX_CMSG_NXTHDR with the correct variable (basically
>      I missed a place in my last round of changes).

Thanks a lot!  This patch works as expected for me.
Unless anybody objects or wants to hold this patch for further reviewing I will
try to commit it this coming weekend.

> Notes:
> 
>   1) This has been tested on both i386 and amd64 with Fedora 10 paplay
>      (client) talking to FreeBSD 8.2 pulseaudio (server) over both TCP
>      and UNIX domain sockets.
> 
>   2) PulseAudio generates the socket name slightly differently between
>      FreeBSD and Linux.  When using UNIX domain sockets please set
>      PULSE_SERVER prior to invoking the client application.  E.g.:
> 
>        setenv PULSE_SERVER unix:/tmp/pulse-J1eO0ABCS0DM/native
> 
>      where /tmp/pulse-J1eO0ABCS0DM/native is the name of the FreeBSD
>      PulseAudio socket.  Someone knowledgeable may be able to muck
> 
>        /usr/compat/linux/etc/pulse/client.conf
> 
>      so this is not necessary.

Looks like the pulseaudio developers changed their mind about the separator
somewhere between versions 0.9.14 and 0.9.21.  If we could find a more recent
package for f10 that would help.  Not sure if a package from later fedora
versions would work.

-- 
Andriy Gapon
Comment 13 john 2011-03-21 05:27:41 UTC
Enclosed is yet another slightly tweaked and lightly tested version.

Changes from previous:

  1) Address some style issues.

  2) Add additional comments.

Notes:

  1) This has been tested on both i386 and amd64 with Fedora 10 paplay
     (client) talking to FreeBSD 8.2 pulseaudio (server) over both TCP
     and UNIX domain sockets.

-- John
-----------------------8<----------------------------8<------------------
--- ./compat/linux/linux_misc.h.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_misc.h	2011-03-07 23:54:17.000000000 -0500
@@ -37,6 +37,8 @@
 					 * Second arg is a ptr to return the
 					 * signal.
 					 */
+#define	LINUX_PR_GET_KEEPCAPS	7	/* Get drop capabilities on setuid */
+#define	LINUX_PR_SET_KEEPCAPS	8	/* Set drop capabilities on setuid */
 #define	LINUX_PR_SET_NAME	15	/* Set process name. */
 #define	LINUX_PR_GET_NAME	16	/* Get process name. */
 
--- ./compat/linux/linux_misc.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_misc.c	2011-03-18 00:02:48.000000000 -0400
@@ -1733,6 +1733,100 @@ linux_exit_group(struct thread *td, stru
 	return (0);
 }
 
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+struct l_user_cap_header {
+	l_int	version;
+	l_int	pid;
+};
+
+struct l_user_cap_data {
+	l_int	effective;
+	l_int	permitted;
+	l_int	inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	if (args->datap) {
+		/*
+		 * The current implementation doesn't support setting
+		 * a capability (it's essentially a stub) so indicate
+		 * that no capabilities are currently set or available
+		 * to request.
+		 */
+		bzero (&lucd, sizeof(lucd));
+		error = copyout(&lucd, args->datap, sizeof(lucd));
+	}
+
+	return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL || args->datap == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	error = copyin(args->datap, &lucd, sizeof(lucd));
+	if (error != 0)
+		return (error);
+
+	/* We currently don't support setting any capabilities. */
+	if (lucd.effective || lucd.permitted || lucd.inheritable) {
+		linux_msg(td,
+			  "capset effective=0x%x, permitted=0x%x, "
+			  "inheritable=0x%x is not implemented",
+			  (int)lucd.effective, (int)lucd.permitted,
+			  (int)lucd.inheritable);
+		return (EPERM);
+	}
+
+	return (0);
+}
+
 int
 linux_prctl(struct thread *td, struct linux_prctl_args *args)
 {
@@ -1766,6 +1860,21 @@ linux_prctl(struct thread *td, struct li
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
 		break;
+	case LINUX_PR_GET_KEEPCAPS:
+		/*
+		 * Indicate that we always clear the effective and
+		 * permitted capability sets when the user id becomes
+		 * non-zero (actually the capability sets are simply
+		 * always zero in the current implementation).
+		 */
+		td->td_retval[0] = 0;
+		break;
+	case LINUX_PR_SET_KEEPCAPS:
+		/*
+		 * Ignore requests to keep the effective and permitted
+		 * capability sets when the user id becomes non-zero.
+		 */
+		break;
 	case LINUX_PR_SET_NAME:
 		/*
 		 * To be on the safe side we need to make sure to not
--- ./compat/linux/linux_socket.h.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_socket.h	2011-03-07 23:54:17.000000000 -0500
@@ -53,6 +53,7 @@
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
+#define LINUX_SCM_CREDENTIALS   0x02
 
 /* Ancilliary data object information macros */
 
@@ -66,13 +67,14 @@
 #define LINUX_CMSG_FIRSTHDR(msg) \
 				((msg)->msg_controllen >= \
 				    sizeof(struct l_cmsghdr) ? \
-				    (struct l_cmsghdr *)((msg)->msg_control) : \
+				    (struct l_cmsghdr *) \
+				        PTRIN((msg)->msg_control) : \
 				    (struct l_cmsghdr *)(NULL))
 #define LINUX_CMSG_NXTHDR(msg, cmsg) \
 				((((char *)(cmsg) + \
 				    LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \
 				    sizeof(*(cmsg))) > \
-				    (((char *)(msg)->msg_control) + \
+				    (((char *)PTRIN((msg)->msg_control)) + \
 				    (msg)->msg_controllen)) ? \
 				    (struct l_cmsghdr *) NULL : \
 				    (struct l_cmsghdr *)((char *)(cmsg) + \
--- ./compat/linux/linux_socket.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./compat/linux/linux_socket.c	2011-03-17 23:35:37.000000000 -0400
@@ -433,6 +433,8 @@ linux_to_bsd_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case LINUX_SCM_RIGHTS:
 		return (SCM_RIGHTS);
+	case LINUX_SCM_CREDENTIALS:
+		return (SCM_CREDS);
 	}
 	return (-1);
 }
@@ -444,6 +446,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case SCM_RIGHTS:
 		return (LINUX_SCM_RIGHTS);
+	case SCM_CREDS:
+		return (LINUX_SCM_CREDENTIALS);
 	}
 	return (-1);
 }
@@ -459,7 +463,16 @@ linux_to_bsd_msghdr(struct msghdr *bhdr,
 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
-	bhdr->msg_controllen	= lhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
 	return (0);
 }
@@ -472,7 +485,16 @@ bsd_to_linux_msghdr(const struct msghdr 
 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
-	lhdr->msg_controllen	= bhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	/* msg_flags skipped */
 	return (0);
 }
@@ -1092,6 +1114,7 @@ static int
 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 {
 	struct cmsghdr *cmsg;
+	struct cmsgcred cmcred;
 	struct mbuf *control;
 	struct msghdr msg;
 	struct l_cmsghdr linux_cmsg;
@@ -1099,15 +1122,14 @@ linux_sendmsg(struct thread *td, struct 
 	struct l_msghdr linux_msg;
 	struct iovec *iov;
 	socklen_t datalen;
+	struct sockaddr *sa;
+	sa_family_t sa_family;
 	void *data;
 	int error;
 
 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
 	if (error)
 		return (error);
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
-		return (error);
 
 	/*
 	 * Some Linux applications (ping) define a non-NULL control data
@@ -1116,8 +1138,12 @@ linux_sendmsg(struct thread *td, struct 
 	 * order to handle this case.  This should be checked, but allows the
 	 * Linux ping to work.
 	 */
-	if (msg.msg_control != NULL && msg.msg_controllen == 0)
-		msg.msg_control = NULL;
+	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
+		linux_msg.msg_control = PTROUT(NULL);
+
+	error = linux_to_bsd_msghdr(&msg, &linux_msg);
+	if (error)
+		return (error);
 
 #ifdef COMPAT_LINUX32
 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
@@ -1128,13 +1154,21 @@ linux_sendmsg(struct thread *td, struct 
 	if (error)
 		return (error);
 
-	if (msg.msg_control != NULL) {
+	control = NULL;
+	cmsg = NULL;
+
+	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
+		error = kern_getsockname(td, args->s, &sa, &datalen);
+		if (error)
+			goto bad;
+		sa_family = sa->sa_family;
+		free(sa, M_SONAME);
+
 		error = ENOBUFS;
 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
 		control = m_get(M_WAIT, MT_CONTROL);
 		if (control == NULL)
 			goto bad;
-		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
@@ -1147,28 +1181,58 @@ linux_sendmsg(struct thread *td, struct 
 				goto bad;
 
 			/*
-			 * Now we support only SCM_RIGHTS, so return EINVAL
-			 * in any other cmsg_type
+			 * Now we support only SCM_RIGHTS and SCM_CRED,
+			 * so return EINVAL in any other cmsg_type
 			 */
-			if ((cmsg->cmsg_type =
-			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
-				goto bad;
+			cmsg->cmsg_type =
+			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
 			cmsg->cmsg_level =
 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+			if (cmsg->cmsg_type == -1
+			    || cmsg->cmsg_level != SOL_SOCKET)
+				goto bad;
 
+			/*
+			 * Some applications (e.g. pulseaudio) attempt to
+			 * send ancillary data even if the underlying protocol
+			 * doesn't support it which is not allowed in the
+			 * FreeBSD system call interface.
+			 */
+			if (sa_family != AF_UNIX)
+				continue;
+
+			data = LINUX_CMSG_DATA(ptr_cmsg);
 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+
+			switch (cmsg->cmsg_type)
+			{
+			case SCM_RIGHTS:
+				break;
+
+			case SCM_CREDS:
+				data = &cmcred;
+				datalen = sizeof(cmcred);
+
+				/*
+				 * The lower levels will fill in the structure
+				 */
+				bzero(data, datalen);
+				break;
+			}
+
 			cmsg->cmsg_len = CMSG_LEN(datalen);
-			data = LINUX_CMSG_DATA(ptr_cmsg);
 
 			error = ENOBUFS;
 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
 				goto bad;
 			if (!m_append(control, datalen, (c_caddr_t) data))
 				goto bad;
-		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
-	} else {
-		control = NULL;
-		cmsg = NULL;
+		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
+
+		if (m_length(control, NULL) == 0) {
+			m_freem(control);
+			control = NULL;
+		}
 	}
 
 	msg.msg_iov = iov;
@@ -1193,9 +1257,11 @@ static int
 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 {
 	struct cmsghdr *cm;
+	struct cmsgcred *cmcred;
 	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
-	socklen_t datalen, outlen, clen;
+	struct l_ucred linux_ucred;
+	socklen_t datalen, outlen;
 	struct l_msghdr linux_msg;
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
@@ -1252,39 +1318,35 @@ linux_recvmsg(struct thread *td, struct 
 			goto bad;
 	}
 
-	if (control) {
+	outbuf = PTRIN(linux_msg.msg_control);
+	outlen = 0;
 
+	if (control) {
 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		outbuf = PTRIN(linux_msg.msg_control);
-		cm = mtod(control, struct cmsghdr *);
-		outlen = 0;
-		clen = control->m_len;
 
-		while (cm != NULL) {
+		msg.msg_control = mtod(control, struct cmsghdr *);
+		msg.msg_controllen = control->m_len;
+
+		cm = CMSG_FIRSTHDR(&msg);
 
-			if ((linux_cmsg->cmsg_type =
-			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
+		while (cm != NULL) {
+			linux_cmsg->cmsg_type =
+			    bsd_to_linux_cmsg_type(cm->cmsg_type);
+			linux_cmsg->cmsg_level =
+			    bsd_to_linux_sockopt_level(cm->cmsg_level);
+			if (linux_cmsg->cmsg_type == -1
+			    || cm->cmsg_level != SOL_SOCKET)
 			{
 				error = EINVAL;
 				goto bad;
 			}
+
 			data = CMSG_DATA(cm);
 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 
-			switch (linux_cmsg->cmsg_type)
+			switch (cm->cmsg_type)
 			{
-			case LINUX_SCM_RIGHTS:
-				if (outlen + LINUX_CMSG_LEN(datalen) >
-				    linux_msg.msg_controllen) {
-					if (outlen == 0) {
-						error = EMSGSIZE;
-						goto bad;
-					} else {
-						linux_msg.msg_flags |=
-						    LINUX_MSG_CTRUNC;
-						goto out;
-					}
-				}
+			case SCM_RIGHTS:
 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
@@ -1295,11 +1357,40 @@ linux_recvmsg(struct thread *td, struct 
 					}
 				}
 				break;
+
+			case SCM_CREDS:
+				/*
+				 * Currently LOCAL_CREDS is never in
+				 * effect for Linux so no need to worry
+				 * about sockcred
+				 */
+				if (datalen != sizeof (*cmcred)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				cmcred = (struct cmsgcred *)data;
+				bzero(&linux_ucred, sizeof(linux_ucred));
+				linux_ucred.pid = cmcred->cmcred_pid;
+				linux_ucred.uid = cmcred->cmcred_uid;
+				linux_ucred.gid = cmcred->cmcred_gid;
+				data = &linux_ucred;
+				datalen = sizeof(linux_ucred);
+				break;
+			}
+
+			if (outlen + LINUX_CMSG_LEN(datalen) >
+			    linux_msg.msg_controllen) {
+				if (outlen == 0) {
+					error = EMSGSIZE;
+					goto bad;
+				} else {
+					linux_msg.msg_flags |=
+					    LINUX_MSG_CTRUNC;
+					goto out;
+				}
 			}
 
 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
-			linux_cmsg->cmsg_level =
-			    bsd_to_linux_sockopt_level(cm->cmsg_level);
 
 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
 			if (error)
@@ -1312,18 +1403,13 @@ linux_recvmsg(struct thread *td, struct 
 
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
-			linux_msg.msg_controllen = outlen;
 
-			if (CMSG_SPACE(datalen) < clen) {
-				clen -= CMSG_SPACE(datalen);
-				cm = (struct cmsghdr *)
-				    ((caddr_t)cm + CMSG_SPACE(datalen));
-			} else
-				cm = NULL;
+			cm = CMSG_NXTHDR(&msg, cm);
 		}
 	}
 
 out:
+	linux_msg.msg_controllen = outlen;
 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
 
 bad:
--- ./i386/linux/linux_dummy.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./i386/linux/linux_dummy.c	2011-03-07 23:54:17.000000000 -0500
@@ -57,8 +57,6 @@ DUMMY(vm86);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);		/* different semantics */
 DUMMY(setfsuid);
 DUMMY(setfsgid);
--- ./i386/linux/syscalls.master.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./i386/linux/syscalls.master	2011-03-17 23:46:17.000000000 -0400
@@ -329,8 +329,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
--- ./amd64/linux32/linux32_dummy.c.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./amd64/linux32/linux32_dummy.c	2011-03-07 23:54:17.000000000 -0500
@@ -54,8 +54,6 @@ DUMMY(sysfs);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);
--- ./amd64/linux32/syscalls.master.ORIGINAL	2010-12-21 12:09:25.000000000 -0500
+++ ./amd64/linux32/syscalls.master	2011-03-17 23:47:06.000000000 -0400
@@ -327,8 +327,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------
Comment 14 dfilter service freebsd_committer freebsd_triage 2011-03-26 10:52:06 UTC
Author: avg
Date: Sat Mar 26 10:51:56 2011
New Revision: 220028
URL: http://svn.freebsd.org/changeset/base/220028

Log:
  linux compat: add non-dummy capget and capset system calls
  
  PR:		kern/149168
  Submitted by:	John Wehle <john@feith.com>
  Reviewed by:	netchild
  MFC after:	2 weeks

Modified:
  head/sys/amd64/linux32/syscalls.master
  head/sys/i386/linux/syscalls.master

Modified: head/sys/amd64/linux32/syscalls.master
==============================================================================
--- head/sys/amd64/linux32/syscalls.master	Sat Mar 26 10:47:17 2011	(r220027)
+++ head/sys/amd64/linux32/syscalls.master	Sat Mar 26 10:51:56 2011	(r220028)
@@ -326,8 +326,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }

Modified: head/sys/i386/linux/syscalls.master
==============================================================================
--- head/sys/i386/linux/syscalls.master	Sat Mar 26 10:47:17 2011	(r220027)
+++ head/sys/i386/linux/syscalls.master	Sat Mar 26 10:51:56 2011	(r220028)
@@ -328,8 +328,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 15 dfilter service freebsd_committer freebsd_triage 2011-03-26 10:59:38 UTC
Author: avg
Date: Sat Mar 26 10:59:24 2011
New Revision: 220030
URL: http://svn.freebsd.org/changeset/base/220030

Log:
  linux compat: add non-dummy capget and capset system calls, regenerate
  
  And drop dummy definitions for those system calls.
  This may transiently break the build.
  
  PR:		kern/149168
  Submitted by:	John Wehle <john@feith.com>
  Reviewed by:	netchild
  MFC after:	2 weeks

Modified:
  head/sys/amd64/linux32/linux32_dummy.c
  head/sys/amd64/linux32/linux32_proto.h
  head/sys/amd64/linux32/linux32_syscall.h
  head/sys/amd64/linux32/linux32_syscalls.c
  head/sys/amd64/linux32/linux32_sysent.c
  head/sys/amd64/linux32/linux32_systrace_args.c
  head/sys/i386/linux/linux_dummy.c
  head/sys/i386/linux/linux_proto.h
  head/sys/i386/linux/linux_syscall.h
  head/sys/i386/linux/linux_syscalls.c
  head/sys/i386/linux/linux_sysent.c
  head/sys/i386/linux/linux_systrace_args.c

Modified: head/sys/amd64/linux32/linux32_dummy.c
==============================================================================
--- head/sys/amd64/linux32/linux32_dummy.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/amd64/linux32/linux32_dummy.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -54,8 +54,6 @@ DUMMY(sysfs);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);

Modified: head/sys/amd64/linux32/linux32_proto.h
==============================================================================
--- head/sys/amd64/linux32/linux32_proto.h	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/amd64/linux32/linux32_proto.h	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -589,10 +589,12 @@ struct linux_getcwd_args {
 	char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)];
 };
 struct linux_capget_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_capset_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_sigaltstack_args {
 	char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)];

Modified: head/sys/amd64/linux32/linux32_syscall.h
==============================================================================
--- head/sys/amd64/linux32/linux32_syscall.h	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/amd64/linux32/linux32_syscall.h	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 #define	LINUX_SYS_exit	1

Modified: head/sys/amd64/linux32/linux32_syscalls.c
==============================================================================
--- head/sys/amd64/linux32/linux32_syscalls.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/amd64/linux32/linux32_syscalls.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 const char *linux_syscallnames[] = {

Modified: head/sys/amd64/linux32/linux32_sysent.c
==============================================================================
--- head/sys/amd64/linux32/linux32_sysent.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/amd64/linux32/linux32_sysent.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 #include "opt_compat.h"
@@ -203,8 +203,8 @@ struct sysent linux_sysent[] = {
 	{ AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC },	/* 181 = linux_pwrite */
 	{ AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC },	/* 182 = linux_chown16 */
 	{ AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0, SY_THR_STATIC },	/* 183 = linux_getcwd */
-	{ 0, (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 184 = linux_capget */
-	{ 0, (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 185 = linux_capset */
+	{ AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 184 = linux_capget */
+	{ AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 185 = linux_capset */
 	{ AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },	/* 186 = linux_sigaltstack */
 	{ 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC },	/* 187 = linux_sendfile */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 188 = getpmsg */

Modified: head/sys/amd64/linux32/linux32_systrace_args.c
==============================================================================
--- head/sys/amd64/linux32/linux32_systrace_args.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/amd64/linux32/linux32_systrace_args.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -1284,12 +1284,18 @@ systrace_args(int sysnum, void *params, 
 	}
 	/* linux_capget */
 	case 184: {
-		*n_args = 0;
+		struct linux_capget_args *p = params;
+		uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */
+		uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */
+		*n_args = 2;
 		break;
 	}
 	/* linux_capset */
 	case 185: {
-		*n_args = 0;
+		struct linux_capset_args *p = params;
+		uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */
+		uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */
+		*n_args = 2;
 		break;
 	}
 	/* linux_sigaltstack */
@@ -4051,9 +4057,29 @@ systrace_setargdesc(int sysnum, int ndx,
 		break;
 	/* linux_capget */
 	case 184:
+		switch(ndx) {
+		case 0:
+			p = "struct l_user_cap_header *";
+			break;
+		case 1:
+			p = "struct l_user_cap_data *";
+			break;
+		default:
+			break;
+		};
 		break;
 	/* linux_capset */
 	case 185:
+		switch(ndx) {
+		case 0:
+			p = "struct l_user_cap_header *";
+			break;
+		case 1:
+			p = "struct l_user_cap_data *";
+			break;
+		default:
+			break;
+		};
 		break;
 	/* linux_sigaltstack */
 	case 186:

Modified: head/sys/i386/linux/linux_dummy.c
==============================================================================
--- head/sys/i386/linux/linux_dummy.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/i386/linux/linux_dummy.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -57,8 +57,6 @@ DUMMY(vm86);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);		/* different semantics */
 DUMMY(setfsuid);
 DUMMY(setfsgid);

Modified: head/sys/i386/linux/linux_proto.h
==============================================================================
--- head/sys/i386/linux/linux_proto.h	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/i386/linux/linux_proto.h	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -586,10 +586,12 @@ struct linux_getcwd_args {
 	char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)];
 };
 struct linux_capget_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_capset_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_sigaltstack_args {
 	char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)];

Modified: head/sys/i386/linux/linux_syscall.h
==============================================================================
--- head/sys/i386/linux/linux_syscall.h	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/i386/linux/linux_syscall.h	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 #define	LINUX_SYS_exit	1

Modified: head/sys/i386/linux/linux_syscalls.c
==============================================================================
--- head/sys/i386/linux/linux_syscalls.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/i386/linux/linux_syscalls.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 const char *linux_syscallnames[] = {

Modified: head/sys/i386/linux/linux_sysent.c
==============================================================================
--- head/sys/i386/linux/linux_sysent.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/i386/linux/linux_sysent.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 219559 2011-03-12 08:51:43Z avg 
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 220028 2011-03-26 10:51:56Z avg 
  */
 
 #include <sys/param.h>
@@ -202,8 +202,8 @@ struct sysent linux_sysent[] = {
 	{ AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0, SY_THR_STATIC },	/* 181 = linux_pwrite */
 	{ AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0, 0, SY_THR_STATIC },	/* 182 = linux_chown16 */
 	{ AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0, SY_THR_STATIC },	/* 183 = linux_getcwd */
-	{ 0, (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 184 = linux_capget */
-	{ 0, (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 185 = linux_capset */
+	{ AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 184 = linux_capget */
+	{ AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0, SY_THR_STATIC },	/* 185 = linux_capset */
 	{ AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC },	/* 186 = linux_sigaltstack */
 	{ 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC },	/* 187 = linux_sendfile */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },			/* 188 = getpmsg */

Modified: head/sys/i386/linux/linux_systrace_args.c
==============================================================================
--- head/sys/i386/linux/linux_systrace_args.c	Sat Mar 26 10:52:37 2011	(r220029)
+++ head/sys/i386/linux/linux_systrace_args.c	Sat Mar 26 10:59:24 2011	(r220030)
@@ -1327,12 +1327,18 @@ systrace_args(int sysnum, void *params, 
 	}
 	/* linux_capget */
 	case 184: {
-		*n_args = 0;
+		struct linux_capget_args *p = params;
+		uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */
+		uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */
+		*n_args = 2;
 		break;
 	}
 	/* linux_capset */
 	case 185: {
-		*n_args = 0;
+		struct linux_capset_args *p = params;
+		uarg[0] = (intptr_t) p->hdrp; /* struct l_user_cap_header * */
+		uarg[1] = (intptr_t) p->datap; /* struct l_user_cap_data * */
+		*n_args = 2;
 		break;
 	}
 	/* linux_sigaltstack */
@@ -4203,9 +4209,29 @@ systrace_setargdesc(int sysnum, int ndx,
 		break;
 	/* linux_capget */
 	case 184:
+		switch(ndx) {
+		case 0:
+			p = "struct l_user_cap_header *";
+			break;
+		case 1:
+			p = "struct l_user_cap_data *";
+			break;
+		default:
+			break;
+		};
 		break;
 	/* linux_capset */
 	case 185:
+		switch(ndx) {
+		case 0:
+			p = "struct l_user_cap_header *";
+			break;
+		case 1:
+			p = "struct l_user_cap_data *";
+			break;
+		default:
+			break;
+		};
 		break;
 	/* linux_sigaltstack */
 	case 186:
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 16 dfilter service freebsd_committer freebsd_triage 2011-03-26 11:06:08 UTC
Author: avg
Date: Sat Mar 26 11:05:53 2011
New Revision: 220031
URL: http://svn.freebsd.org/changeset/base/220031

Log:
  linux compat: improve and fix sendmsg/recvmsg compatibility
  
  - implement baseic stubs for capget, capset, prctl PR_GET_KEEPCAPS
    and prctl PR_SET_KEEPCAPS.
  - add SCM_CREDS support to sendmsg and recvmsg
  - modify sendmsg to ignore control messages if not using UNIX
    domain sockets
  
  This should allow linux pulse audio daemon and client work on FreeBSD
  and interoperate with native counter-parts modulo the differences in
  pulseaudio versions.
  
  PR:		kern/149168
  Submitted by:	John Wehle <john@feith.com>
  Reviewed by:	netchild
  MFC after:	2 weeks

Modified:
  head/sys/compat/linux/linux_misc.c
  head/sys/compat/linux/linux_misc.h
  head/sys/compat/linux/linux_socket.c
  head/sys/compat/linux/linux_socket.h

Modified: head/sys/compat/linux/linux_misc.c
==============================================================================
--- head/sys/compat/linux/linux_misc.c	Sat Mar 26 10:59:24 2011	(r220030)
+++ head/sys/compat/linux/linux_misc.c	Sat Mar 26 11:05:53 2011	(r220031)
@@ -1679,6 +1679,100 @@ linux_exit_group(struct thread *td, stru
 	return (0);
 }
 
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+struct l_user_cap_header {
+	l_int	version;
+	l_int	pid;
+};
+
+struct l_user_cap_data {
+	l_int	effective;
+	l_int	permitted;
+	l_int	inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	if (args->datap) {
+		/*
+		 * The current implementation doesn't support setting
+		 * a capability (it's essentially a stub) so indicate
+		 * that no capabilities are currently set or available
+		 * to request.
+		 */
+		bzero (&lucd, sizeof(lucd));
+		error = copyout(&lucd, args->datap, sizeof(lucd));
+	}
+
+	return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL || args->datap == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	error = copyin(args->datap, &lucd, sizeof(lucd));
+	if (error != 0)
+		return (error);
+
+	/* We currently don't support setting any capabilities. */
+	if (lucd.effective || lucd.permitted || lucd.inheritable) {
+		linux_msg(td,
+			  "capset effective=0x%x, permitted=0x%x, "
+			  "inheritable=0x%x is not implemented",
+			  (int)lucd.effective, (int)lucd.permitted,
+			  (int)lucd.inheritable);
+		return (EPERM);
+	}
+
+	return (0);
+}
+
 int
 linux_prctl(struct thread *td, struct linux_prctl_args *args)
 {
@@ -1712,6 +1806,21 @@ linux_prctl(struct thread *td, struct li
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
 		break;
+	case LINUX_PR_GET_KEEPCAPS:
+		/*
+		 * Indicate that we always clear the effective and
+		 * permitted capability sets when the user id becomes
+		 * non-zero (actually the capability sets are simply
+		 * always zero in the current implementation).
+		 */
+		td->td_retval[0] = 0;
+		break;
+	case LINUX_PR_SET_KEEPCAPS:
+		/*
+		 * Ignore requests to keep the effective and permitted
+		 * capability sets when the user id becomes non-zero.
+		 */
+		break;
 	case LINUX_PR_SET_NAME:
 		/*
 		 * To be on the safe side we need to make sure to not

Modified: head/sys/compat/linux/linux_misc.h
==============================================================================
--- head/sys/compat/linux/linux_misc.h	Sat Mar 26 10:59:24 2011	(r220030)
+++ head/sys/compat/linux/linux_misc.h	Sat Mar 26 11:05:53 2011	(r220031)
@@ -37,6 +37,8 @@
 					 * Second arg is a ptr to return the
 					 * signal.
 					 */
+#define	LINUX_PR_GET_KEEPCAPS	7	/* Get drop capabilities on setuid */
+#define	LINUX_PR_SET_KEEPCAPS	8	/* Set drop capabilities on setuid */
 #define	LINUX_PR_SET_NAME	15	/* Set process name. */
 #define	LINUX_PR_GET_NAME	16	/* Get process name. */
 

Modified: head/sys/compat/linux/linux_socket.c
==============================================================================
--- head/sys/compat/linux/linux_socket.c	Sat Mar 26 10:59:24 2011	(r220030)
+++ head/sys/compat/linux/linux_socket.c	Sat Mar 26 11:05:53 2011	(r220031)
@@ -433,6 +433,8 @@ linux_to_bsd_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case LINUX_SCM_RIGHTS:
 		return (SCM_RIGHTS);
+	case LINUX_SCM_CREDENTIALS:
+		return (SCM_CREDS);
 	}
 	return (-1);
 }
@@ -444,6 +446,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case SCM_RIGHTS:
 		return (LINUX_SCM_RIGHTS);
+	case SCM_CREDS:
+		return (LINUX_SCM_CREDENTIALS);
 	}
 	return (-1);
 }
@@ -459,7 +463,16 @@ linux_to_bsd_msghdr(struct msghdr *bhdr,
 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
-	bhdr->msg_controllen	= lhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
 	return (0);
 }
@@ -472,7 +485,16 @@ bsd_to_linux_msghdr(const struct msghdr 
 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
-	lhdr->msg_controllen	= bhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	/* msg_flags skipped */
 	return (0);
 }
@@ -1092,6 +1114,7 @@ static int
 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 {
 	struct cmsghdr *cmsg;
+	struct cmsgcred cmcred;
 	struct mbuf *control;
 	struct msghdr msg;
 	struct l_cmsghdr linux_cmsg;
@@ -1099,15 +1122,14 @@ linux_sendmsg(struct thread *td, struct 
 	struct l_msghdr linux_msg;
 	struct iovec *iov;
 	socklen_t datalen;
+	struct sockaddr *sa;
+	sa_family_t sa_family;
 	void *data;
 	int error;
 
 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
 	if (error)
 		return (error);
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
-		return (error);
 
 	/*
 	 * Some Linux applications (ping) define a non-NULL control data
@@ -1116,8 +1138,12 @@ linux_sendmsg(struct thread *td, struct 
 	 * order to handle this case.  This should be checked, but allows the
 	 * Linux ping to work.
 	 */
-	if (msg.msg_control != NULL && msg.msg_controllen == 0)
-		msg.msg_control = NULL;
+	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
+		linux_msg.msg_control = PTROUT(NULL);
+
+	error = linux_to_bsd_msghdr(&msg, &linux_msg);
+	if (error)
+		return (error);
 
 #ifdef COMPAT_LINUX32
 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
@@ -1128,13 +1154,21 @@ linux_sendmsg(struct thread *td, struct 
 	if (error)
 		return (error);
 
-	if (msg.msg_control != NULL) {
+	control = NULL;
+	cmsg = NULL;
+
+	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
+		error = kern_getsockname(td, args->s, &sa, &datalen);
+		if (error)
+			goto bad;
+		sa_family = sa->sa_family;
+		free(sa, M_SONAME);
+
 		error = ENOBUFS;
 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
 		control = m_get(M_WAIT, MT_CONTROL);
 		if (control == NULL)
 			goto bad;
-		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
@@ -1147,28 +1181,58 @@ linux_sendmsg(struct thread *td, struct 
 				goto bad;
 
 			/*
-			 * Now we support only SCM_RIGHTS, so return EINVAL
-			 * in any other cmsg_type
+			 * Now we support only SCM_RIGHTS and SCM_CRED,
+			 * so return EINVAL in any other cmsg_type
 			 */
-			if ((cmsg->cmsg_type =
-			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
-				goto bad;
+			cmsg->cmsg_type =
+			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
 			cmsg->cmsg_level =
 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+			if (cmsg->cmsg_type == -1
+			    || cmsg->cmsg_level != SOL_SOCKET)
+				goto bad;
 
+			/*
+			 * Some applications (e.g. pulseaudio) attempt to
+			 * send ancillary data even if the underlying protocol
+			 * doesn't support it which is not allowed in the
+			 * FreeBSD system call interface.
+			 */
+			if (sa_family != AF_UNIX)
+				continue;
+
+			data = LINUX_CMSG_DATA(ptr_cmsg);
 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+
+			switch (cmsg->cmsg_type)
+			{
+			case SCM_RIGHTS:
+				break;
+
+			case SCM_CREDS:
+				data = &cmcred;
+				datalen = sizeof(cmcred);
+
+				/*
+				 * The lower levels will fill in the structure
+				 */
+				bzero(data, datalen);
+				break;
+			}
+
 			cmsg->cmsg_len = CMSG_LEN(datalen);
-			data = LINUX_CMSG_DATA(ptr_cmsg);
 
 			error = ENOBUFS;
 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
 				goto bad;
 			if (!m_append(control, datalen, (c_caddr_t) data))
 				goto bad;
-		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
-	} else {
-		control = NULL;
-		cmsg = NULL;
+		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
+
+		if (m_length(control, NULL) == 0) {
+			m_freem(control);
+			control = NULL;
+		}
 	}
 
 	msg.msg_iov = iov;
@@ -1193,9 +1257,11 @@ static int
 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 {
 	struct cmsghdr *cm;
+	struct cmsgcred *cmcred;
 	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
-	socklen_t datalen, outlen, clen;
+	struct l_ucred linux_ucred;
+	socklen_t datalen, outlen;
 	struct l_msghdr linux_msg;
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
@@ -1252,39 +1318,35 @@ linux_recvmsg(struct thread *td, struct 
 			goto bad;
 	}
 
-	if (control) {
+	outbuf = PTRIN(linux_msg.msg_control);
+	outlen = 0;
 
+	if (control) {
 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		outbuf = PTRIN(linux_msg.msg_control);
-		cm = mtod(control, struct cmsghdr *);
-		outlen = 0;
-		clen = control->m_len;
 
-		while (cm != NULL) {
+		msg.msg_control = mtod(control, struct cmsghdr *);
+		msg.msg_controllen = control->m_len;
+
+		cm = CMSG_FIRSTHDR(&msg);
 
-			if ((linux_cmsg->cmsg_type =
-			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
+		while (cm != NULL) {
+			linux_cmsg->cmsg_type =
+			    bsd_to_linux_cmsg_type(cm->cmsg_type);
+			linux_cmsg->cmsg_level =
+			    bsd_to_linux_sockopt_level(cm->cmsg_level);
+			if (linux_cmsg->cmsg_type == -1
+			    || cm->cmsg_level != SOL_SOCKET)
 			{
 				error = EINVAL;
 				goto bad;
 			}
+
 			data = CMSG_DATA(cm);
 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 
-			switch (linux_cmsg->cmsg_type)
+			switch (cm->cmsg_type)
 			{
-			case LINUX_SCM_RIGHTS:
-				if (outlen + LINUX_CMSG_LEN(datalen) >
-				    linux_msg.msg_controllen) {
-					if (outlen == 0) {
-						error = EMSGSIZE;
-						goto bad;
-					} else {
-						linux_msg.msg_flags |=
-						    LINUX_MSG_CTRUNC;
-						goto out;
-					}
-				}
+			case SCM_RIGHTS:
 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
@@ -1295,11 +1357,40 @@ linux_recvmsg(struct thread *td, struct 
 					}
 				}
 				break;
+
+			case SCM_CREDS:
+				/*
+				 * Currently LOCAL_CREDS is never in
+				 * effect for Linux so no need to worry
+				 * about sockcred
+				 */
+				if (datalen != sizeof (*cmcred)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				cmcred = (struct cmsgcred *)data;
+				bzero(&linux_ucred, sizeof(linux_ucred));
+				linux_ucred.pid = cmcred->cmcred_pid;
+				linux_ucred.uid = cmcred->cmcred_uid;
+				linux_ucred.gid = cmcred->cmcred_gid;
+				data = &linux_ucred;
+				datalen = sizeof(linux_ucred);
+				break;
+			}
+
+			if (outlen + LINUX_CMSG_LEN(datalen) >
+			    linux_msg.msg_controllen) {
+				if (outlen == 0) {
+					error = EMSGSIZE;
+					goto bad;
+				} else {
+					linux_msg.msg_flags |=
+					    LINUX_MSG_CTRUNC;
+					goto out;
+				}
 			}
 
 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
-			linux_cmsg->cmsg_level =
-			    bsd_to_linux_sockopt_level(cm->cmsg_level);
 
 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
 			if (error)
@@ -1312,18 +1403,13 @@ linux_recvmsg(struct thread *td, struct 
 
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
-			linux_msg.msg_controllen = outlen;
 
-			if (CMSG_SPACE(datalen) < clen) {
-				clen -= CMSG_SPACE(datalen);
-				cm = (struct cmsghdr *)
-				    ((caddr_t)cm + CMSG_SPACE(datalen));
-			} else
-				cm = NULL;
+			cm = CMSG_NXTHDR(&msg, cm);
 		}
 	}
 
 out:
+	linux_msg.msg_controllen = outlen;
 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
 
 bad:

Modified: head/sys/compat/linux/linux_socket.h
==============================================================================
--- head/sys/compat/linux/linux_socket.h	Sat Mar 26 10:59:24 2011	(r220030)
+++ head/sys/compat/linux/linux_socket.h	Sat Mar 26 11:05:53 2011	(r220031)
@@ -53,6 +53,7 @@
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
+#define LINUX_SCM_CREDENTIALS   0x02
 
 /* Ancilliary data object information macros */
 
@@ -66,13 +67,14 @@
 #define LINUX_CMSG_FIRSTHDR(msg) \
 				((msg)->msg_controllen >= \
 				    sizeof(struct l_cmsghdr) ? \
-				    (struct l_cmsghdr *)((msg)->msg_control) : \
+				    (struct l_cmsghdr *) \
+				        PTRIN((msg)->msg_control) : \
 				    (struct l_cmsghdr *)(NULL))
 #define LINUX_CMSG_NXTHDR(msg, cmsg) \
 				((((char *)(cmsg) + \
 				    LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \
 				    sizeof(*(cmsg))) > \
-				    (((char *)(msg)->msg_control) + \
+				    (((char *)PTRIN((msg)->msg_control)) + \
 				    (msg)->msg_controllen)) ? \
 				    (struct l_cmsghdr *) NULL : \
 				    (struct l_cmsghdr *)((char *)(cmsg) + \
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 17 Andriy Gapon freebsd_committer freebsd_triage 2011-04-02 09:11:02 UTC
State Changed
From-To: open->patched

The patch is committed to head. 


Comment 18 Andriy Gapon freebsd_committer freebsd_triage 2011-04-02 09:11:02 UTC
Responsible Changed
From-To: freebsd-emulation->avg

I am handling this PR.
Comment 19 dfilter service freebsd_committer freebsd_triage 2011-04-09 09:29:22 UTC
Author: avg
Date: Sat Apr  9 08:29:07 2011
New Revision: 220466
URL: http://svn.freebsd.org/changeset/base/220466

Log:
  MFC r220028: linux compat: add non-dummy capget and capset system calls
  
  PR:		kern/149168

Modified:
  stable/8/sys/amd64/linux32/syscalls.master
  stable/8/sys/i386/linux/syscalls.master
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/amd64/linux32/syscalls.master
==============================================================================
--- stable/8/sys/amd64/linux32/syscalls.master	Sat Apr  9 07:42:25 2011	(r220465)
+++ stable/8/sys/amd64/linux32/syscalls.master	Sat Apr  9 08:29:07 2011	(r220466)
@@ -326,8 +326,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }

Modified: stable/8/sys/i386/linux/syscalls.master
==============================================================================
--- stable/8/sys/i386/linux/syscalls.master	Sat Apr  9 07:42:25 2011	(r220465)
+++ stable/8/sys/i386/linux/syscalls.master	Sat Apr  9 08:29:07 2011	(r220466)
@@ -328,8 +328,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 20 dfilter service freebsd_committer freebsd_triage 2011-04-09 09:32:05 UTC
Author: avg
Date: Sat Apr  9 08:31:50 2011
New Revision: 220467
URL: http://svn.freebsd.org/changeset/base/220467

Log:
  Regen for r220466
  
  PR:		kern/149168

Modified:
  stable/8/sys/amd64/linux32/linux32_proto.h
  stable/8/sys/amd64/linux32/linux32_syscall.h
  stable/8/sys/amd64/linux32/linux32_sysent.c
  stable/8/sys/i386/linux/linux_proto.h
  stable/8/sys/i386/linux/linux_syscall.h
  stable/8/sys/i386/linux/linux_sysent.c

Modified: stable/8/sys/amd64/linux32/linux32_proto.h
==============================================================================
--- stable/8/sys/amd64/linux32/linux32_proto.h	Sat Apr  9 08:29:07 2011	(r220466)
+++ stable/8/sys/amd64/linux32/linux32_proto.h	Sat Apr  9 08:31:50 2011	(r220467)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/8/sys/amd64/linux32/syscalls.master 219171 2011-03-02 06:23:19Z dchagin 
+ * created from FreeBSD: stable/8/sys/amd64/linux32/syscalls.master 220466 2011-04-09 08:29:07Z avg 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -589,10 +589,12 @@ struct linux_getcwd_args {
 	char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)];
 };
 struct linux_capget_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_capset_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_sigaltstack_args {
 	char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)];

Modified: stable/8/sys/amd64/linux32/linux32_syscall.h
==============================================================================
--- stable/8/sys/amd64/linux32/linux32_syscall.h	Sat Apr  9 08:29:07 2011	(r220466)
+++ stable/8/sys/amd64/linux32/linux32_syscall.h	Sat Apr  9 08:31:50 2011	(r220467)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/8/sys/amd64/linux32/syscalls.master 219171 2011-03-02 06:23:19Z dchagin 
+ * created from FreeBSD: stable/8/sys/amd64/linux32/syscalls.master 220466 2011-04-09 08:29:07Z avg 
  */
 
 #define	LINUX_SYS_exit	1

Modified: stable/8/sys/amd64/linux32/linux32_sysent.c
==============================================================================
--- stable/8/sys/amd64/linux32/linux32_sysent.c	Sat Apr  9 08:29:07 2011	(r220466)
+++ stable/8/sys/amd64/linux32/linux32_sysent.c	Sat Apr  9 08:31:50 2011	(r220467)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/8/sys/amd64/linux32/syscalls.master 219171 2011-03-02 06:23:19Z dchagin 
+ * created from FreeBSD: stable/8/sys/amd64/linux32/syscalls.master 220466 2011-04-09 08:29:07Z avg 
  */
 
 #include "opt_compat.h"
@@ -203,8 +203,8 @@ struct sysent linux_sysent[] = {
 	{ AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0 },	/* 181 = linux_pwrite */
 	{ AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0, 0 },	/* 182 = linux_chown16 */
 	{ AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0 },	/* 183 = linux_getcwd */
-	{ 0, (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0 },	/* 184 = linux_capget */
-	{ 0, (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0 },	/* 185 = linux_capset */
+	{ AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0 },	/* 184 = linux_capget */
+	{ AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0 },	/* 185 = linux_capset */
 	{ AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0 },	/* 186 = linux_sigaltstack */
 	{ 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0 },	/* 187 = linux_sendfile */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0 },			/* 188 = getpmsg */

Modified: stable/8/sys/i386/linux/linux_proto.h
==============================================================================
--- stable/8/sys/i386/linux/linux_proto.h	Sat Apr  9 08:29:07 2011	(r220466)
+++ stable/8/sys/i386/linux/linux_proto.h	Sat Apr  9 08:31:50 2011	(r220467)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/8/sys/i386/linux/syscalls.master 219171 2011-03-02 06:23:19Z dchagin 
+ * created from FreeBSD: stable/8/sys/i386/linux/syscalls.master 220466 2011-04-09 08:29:07Z avg 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -586,10 +586,12 @@ struct linux_getcwd_args {
 	char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)];
 };
 struct linux_capget_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_capset_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_sigaltstack_args {
 	char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)];

Modified: stable/8/sys/i386/linux/linux_syscall.h
==============================================================================
--- stable/8/sys/i386/linux/linux_syscall.h	Sat Apr  9 08:29:07 2011	(r220466)
+++ stable/8/sys/i386/linux/linux_syscall.h	Sat Apr  9 08:31:50 2011	(r220467)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/8/sys/i386/linux/syscalls.master 219171 2011-03-02 06:23:19Z dchagin 
+ * created from FreeBSD: stable/8/sys/i386/linux/syscalls.master 220466 2011-04-09 08:29:07Z avg 
  */
 
 #define	LINUX_SYS_exit	1

Modified: stable/8/sys/i386/linux/linux_sysent.c
==============================================================================
--- stable/8/sys/i386/linux/linux_sysent.c	Sat Apr  9 08:29:07 2011	(r220466)
+++ stable/8/sys/i386/linux/linux_sysent.c	Sat Apr  9 08:31:50 2011	(r220467)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/8/sys/i386/linux/syscalls.master 219171 2011-03-02 06:23:19Z dchagin 
+ * created from FreeBSD: stable/8/sys/i386/linux/syscalls.master 220466 2011-04-09 08:29:07Z avg 
  */
 
 #include <sys/param.h>
@@ -202,8 +202,8 @@ struct sysent linux_sysent[] = {
 	{ AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0, 0 },	/* 181 = linux_pwrite */
 	{ AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0, 0 },	/* 182 = linux_chown16 */
 	{ AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0, 0 },	/* 183 = linux_getcwd */
-	{ 0, (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0 },	/* 184 = linux_capget */
-	{ 0, (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0 },	/* 185 = linux_capset */
+	{ AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0, 0 },	/* 184 = linux_capget */
+	{ AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0, 0 },	/* 185 = linux_capset */
 	{ AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0, 0 },	/* 186 = linux_sigaltstack */
 	{ 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0, 0 },	/* 187 = linux_sendfile */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0 },			/* 188 = getpmsg */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 21 dfilter service freebsd_committer freebsd_triage 2011-04-09 09:44:06 UTC
Author: avg
Date: Sat Apr  9 08:43:57 2011
New Revision: 220468
URL: http://svn.freebsd.org/changeset/base/220468

Log:
  MFC r220030: drop dummy definitions
  
  PR:		kern/149168

Modified:
  stable/8/sys/amd64/linux32/linux32_dummy.c
  stable/8/sys/i386/linux/linux_dummy.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/amd64/linux32/linux32_dummy.c
==============================================================================
--- stable/8/sys/amd64/linux32/linux32_dummy.c	Sat Apr  9 08:31:50 2011	(r220467)
+++ stable/8/sys/amd64/linux32/linux32_dummy.c	Sat Apr  9 08:43:57 2011	(r220468)
@@ -54,8 +54,6 @@ DUMMY(sysfs);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);
 DUMMY(setfsuid);
 DUMMY(setfsgid);

Modified: stable/8/sys/i386/linux/linux_dummy.c
==============================================================================
--- stable/8/sys/i386/linux/linux_dummy.c	Sat Apr  9 08:31:50 2011	(r220467)
+++ stable/8/sys/i386/linux/linux_dummy.c	Sat Apr  9 08:43:57 2011	(r220468)
@@ -57,8 +57,6 @@ DUMMY(vm86);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);		/* different semantics */
 DUMMY(setfsuid);
 DUMMY(setfsgid);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 22 dfilter service freebsd_committer freebsd_triage 2011-04-09 09:52:33 UTC
Author: avg
Date: Sat Apr  9 08:52:22 2011
New Revision: 220469
URL: http://svn.freebsd.org/changeset/base/220469

Log:
  MFC r220031: linux compat: improve and fix sendmsg/recvmsg compatibility
  
  PR:		kern/149168

Modified:
  stable/8/sys/compat/linux/linux_misc.c
  stable/8/sys/compat/linux/linux_misc.h
  stable/8/sys/compat/linux/linux_socket.c
  stable/8/sys/compat/linux/linux_socket.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/compat/linux/linux_misc.c
==============================================================================
--- stable/8/sys/compat/linux/linux_misc.c	Sat Apr  9 08:43:57 2011	(r220468)
+++ stable/8/sys/compat/linux/linux_misc.c	Sat Apr  9 08:52:22 2011	(r220469)
@@ -1679,6 +1679,100 @@ linux_exit_group(struct thread *td, stru
 	return (0);
 }
 
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+struct l_user_cap_header {
+	l_int	version;
+	l_int	pid;
+};
+
+struct l_user_cap_data {
+	l_int	effective;
+	l_int	permitted;
+	l_int	inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	if (args->datap) {
+		/*
+		 * The current implementation doesn't support setting
+		 * a capability (it's essentially a stub) so indicate
+		 * that no capabilities are currently set or available
+		 * to request.
+		 */
+		bzero (&lucd, sizeof(lucd));
+		error = copyout(&lucd, args->datap, sizeof(lucd));
+	}
+
+	return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL || args->datap == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	error = copyin(args->datap, &lucd, sizeof(lucd));
+	if (error != 0)
+		return (error);
+
+	/* We currently don't support setting any capabilities. */
+	if (lucd.effective || lucd.permitted || lucd.inheritable) {
+		linux_msg(td,
+			  "capset effective=0x%x, permitted=0x%x, "
+			  "inheritable=0x%x is not implemented",
+			  (int)lucd.effective, (int)lucd.permitted,
+			  (int)lucd.inheritable);
+		return (EPERM);
+	}
+
+	return (0);
+}
+
 int
 linux_prctl(struct thread *td, struct linux_prctl_args *args)
 {
@@ -1712,6 +1806,21 @@ linux_prctl(struct thread *td, struct li
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
 		break;
+	case LINUX_PR_GET_KEEPCAPS:
+		/*
+		 * Indicate that we always clear the effective and
+		 * permitted capability sets when the user id becomes
+		 * non-zero (actually the capability sets are simply
+		 * always zero in the current implementation).
+		 */
+		td->td_retval[0] = 0;
+		break;
+	case LINUX_PR_SET_KEEPCAPS:
+		/*
+		 * Ignore requests to keep the effective and permitted
+		 * capability sets when the user id becomes non-zero.
+		 */
+		break;
 	case LINUX_PR_SET_NAME:
 		/*
 		 * To be on the safe side we need to make sure to not

Modified: stable/8/sys/compat/linux/linux_misc.h
==============================================================================
--- stable/8/sys/compat/linux/linux_misc.h	Sat Apr  9 08:43:57 2011	(r220468)
+++ stable/8/sys/compat/linux/linux_misc.h	Sat Apr  9 08:52:22 2011	(r220469)
@@ -37,6 +37,8 @@
 					 * Second arg is a ptr to return the
 					 * signal.
 					 */
+#define	LINUX_PR_GET_KEEPCAPS	7	/* Get drop capabilities on setuid */
+#define	LINUX_PR_SET_KEEPCAPS	8	/* Set drop capabilities on setuid */
 #define	LINUX_PR_SET_NAME	15	/* Set process name. */
 #define	LINUX_PR_GET_NAME	16	/* Get process name. */
 

Modified: stable/8/sys/compat/linux/linux_socket.c
==============================================================================
--- stable/8/sys/compat/linux/linux_socket.c	Sat Apr  9 08:43:57 2011	(r220468)
+++ stable/8/sys/compat/linux/linux_socket.c	Sat Apr  9 08:52:22 2011	(r220469)
@@ -433,6 +433,8 @@ linux_to_bsd_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case LINUX_SCM_RIGHTS:
 		return (SCM_RIGHTS);
+	case LINUX_SCM_CREDENTIALS:
+		return (SCM_CREDS);
 	}
 	return (-1);
 }
@@ -444,6 +446,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case SCM_RIGHTS:
 		return (LINUX_SCM_RIGHTS);
+	case SCM_CREDS:
+		return (LINUX_SCM_CREDENTIALS);
 	}
 	return (-1);
 }
@@ -459,7 +463,16 @@ linux_to_bsd_msghdr(struct msghdr *bhdr,
 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
-	bhdr->msg_controllen	= lhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
 	return (0);
 }
@@ -472,7 +485,16 @@ bsd_to_linux_msghdr(const struct msghdr 
 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
-	lhdr->msg_controllen	= bhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	/* msg_flags skipped */
 	return (0);
 }
@@ -1092,6 +1114,7 @@ static int
 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 {
 	struct cmsghdr *cmsg;
+	struct cmsgcred cmcred;
 	struct mbuf *control;
 	struct msghdr msg;
 	struct l_cmsghdr linux_cmsg;
@@ -1099,15 +1122,14 @@ linux_sendmsg(struct thread *td, struct 
 	struct l_msghdr linux_msg;
 	struct iovec *iov;
 	socklen_t datalen;
+	struct sockaddr *sa;
+	sa_family_t sa_family;
 	void *data;
 	int error;
 
 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
 	if (error)
 		return (error);
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
-		return (error);
 
 	/*
 	 * Some Linux applications (ping) define a non-NULL control data
@@ -1116,8 +1138,12 @@ linux_sendmsg(struct thread *td, struct 
 	 * order to handle this case.  This should be checked, but allows the
 	 * Linux ping to work.
 	 */
-	if (msg.msg_control != NULL && msg.msg_controllen == 0)
-		msg.msg_control = NULL;
+	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
+		linux_msg.msg_control = PTROUT(NULL);
+
+	error = linux_to_bsd_msghdr(&msg, &linux_msg);
+	if (error)
+		return (error);
 
 #ifdef COMPAT_LINUX32
 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
@@ -1128,13 +1154,21 @@ linux_sendmsg(struct thread *td, struct 
 	if (error)
 		return (error);
 
-	if (msg.msg_control != NULL) {
+	control = NULL;
+	cmsg = NULL;
+
+	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
+		error = kern_getsockname(td, args->s, &sa, &datalen);
+		if (error)
+			goto bad;
+		sa_family = sa->sa_family;
+		free(sa, M_SONAME);
+
 		error = ENOBUFS;
 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
 		control = m_get(M_WAIT, MT_CONTROL);
 		if (control == NULL)
 			goto bad;
-		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
@@ -1147,28 +1181,58 @@ linux_sendmsg(struct thread *td, struct 
 				goto bad;
 
 			/*
-			 * Now we support only SCM_RIGHTS, so return EINVAL
-			 * in any other cmsg_type
+			 * Now we support only SCM_RIGHTS and SCM_CRED,
+			 * so return EINVAL in any other cmsg_type
 			 */
-			if ((cmsg->cmsg_type =
-			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
-				goto bad;
+			cmsg->cmsg_type =
+			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
 			cmsg->cmsg_level =
 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+			if (cmsg->cmsg_type == -1
+			    || cmsg->cmsg_level != SOL_SOCKET)
+				goto bad;
 
+			/*
+			 * Some applications (e.g. pulseaudio) attempt to
+			 * send ancillary data even if the underlying protocol
+			 * doesn't support it which is not allowed in the
+			 * FreeBSD system call interface.
+			 */
+			if (sa_family != AF_UNIX)
+				continue;
+
+			data = LINUX_CMSG_DATA(ptr_cmsg);
 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+
+			switch (cmsg->cmsg_type)
+			{
+			case SCM_RIGHTS:
+				break;
+
+			case SCM_CREDS:
+				data = &cmcred;
+				datalen = sizeof(cmcred);
+
+				/*
+				 * The lower levels will fill in the structure
+				 */
+				bzero(data, datalen);
+				break;
+			}
+
 			cmsg->cmsg_len = CMSG_LEN(datalen);
-			data = LINUX_CMSG_DATA(ptr_cmsg);
 
 			error = ENOBUFS;
 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
 				goto bad;
 			if (!m_append(control, datalen, (c_caddr_t) data))
 				goto bad;
-		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
-	} else {
-		control = NULL;
-		cmsg = NULL;
+		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
+
+		if (m_length(control, NULL) == 0) {
+			m_freem(control);
+			control = NULL;
+		}
 	}
 
 	msg.msg_iov = iov;
@@ -1193,9 +1257,11 @@ static int
 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 {
 	struct cmsghdr *cm;
+	struct cmsgcred *cmcred;
 	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
-	socklen_t datalen, outlen, clen;
+	struct l_ucred linux_ucred;
+	socklen_t datalen, outlen;
 	struct l_msghdr linux_msg;
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
@@ -1252,39 +1318,35 @@ linux_recvmsg(struct thread *td, struct 
 			goto bad;
 	}
 
-	if (control) {
+	outbuf = PTRIN(linux_msg.msg_control);
+	outlen = 0;
 
+	if (control) {
 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		outbuf = PTRIN(linux_msg.msg_control);
-		cm = mtod(control, struct cmsghdr *);
-		outlen = 0;
-		clen = control->m_len;
 
-		while (cm != NULL) {
+		msg.msg_control = mtod(control, struct cmsghdr *);
+		msg.msg_controllen = control->m_len;
+
+		cm = CMSG_FIRSTHDR(&msg);
 
-			if ((linux_cmsg->cmsg_type =
-			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
+		while (cm != NULL) {
+			linux_cmsg->cmsg_type =
+			    bsd_to_linux_cmsg_type(cm->cmsg_type);
+			linux_cmsg->cmsg_level =
+			    bsd_to_linux_sockopt_level(cm->cmsg_level);
+			if (linux_cmsg->cmsg_type == -1
+			    || cm->cmsg_level != SOL_SOCKET)
 			{
 				error = EINVAL;
 				goto bad;
 			}
+
 			data = CMSG_DATA(cm);
 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 
-			switch (linux_cmsg->cmsg_type)
+			switch (cm->cmsg_type)
 			{
-			case LINUX_SCM_RIGHTS:
-				if (outlen + LINUX_CMSG_LEN(datalen) >
-				    linux_msg.msg_controllen) {
-					if (outlen == 0) {
-						error = EMSGSIZE;
-						goto bad;
-					} else {
-						linux_msg.msg_flags |=
-						    LINUX_MSG_CTRUNC;
-						goto out;
-					}
-				}
+			case SCM_RIGHTS:
 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
@@ -1295,11 +1357,40 @@ linux_recvmsg(struct thread *td, struct 
 					}
 				}
 				break;
+
+			case SCM_CREDS:
+				/*
+				 * Currently LOCAL_CREDS is never in
+				 * effect for Linux so no need to worry
+				 * about sockcred
+				 */
+				if (datalen != sizeof (*cmcred)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				cmcred = (struct cmsgcred *)data;
+				bzero(&linux_ucred, sizeof(linux_ucred));
+				linux_ucred.pid = cmcred->cmcred_pid;
+				linux_ucred.uid = cmcred->cmcred_uid;
+				linux_ucred.gid = cmcred->cmcred_gid;
+				data = &linux_ucred;
+				datalen = sizeof(linux_ucred);
+				break;
+			}
+
+			if (outlen + LINUX_CMSG_LEN(datalen) >
+			    linux_msg.msg_controllen) {
+				if (outlen == 0) {
+					error = EMSGSIZE;
+					goto bad;
+				} else {
+					linux_msg.msg_flags |=
+					    LINUX_MSG_CTRUNC;
+					goto out;
+				}
 			}
 
 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
-			linux_cmsg->cmsg_level =
-			    bsd_to_linux_sockopt_level(cm->cmsg_level);
 
 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
 			if (error)
@@ -1312,18 +1403,13 @@ linux_recvmsg(struct thread *td, struct 
 
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
-			linux_msg.msg_controllen = outlen;
 
-			if (CMSG_SPACE(datalen) < clen) {
-				clen -= CMSG_SPACE(datalen);
-				cm = (struct cmsghdr *)
-				    ((caddr_t)cm + CMSG_SPACE(datalen));
-			} else
-				cm = NULL;
+			cm = CMSG_NXTHDR(&msg, cm);
 		}
 	}
 
 out:
+	linux_msg.msg_controllen = outlen;
 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
 
 bad:

Modified: stable/8/sys/compat/linux/linux_socket.h
==============================================================================
--- stable/8/sys/compat/linux/linux_socket.h	Sat Apr  9 08:43:57 2011	(r220468)
+++ stable/8/sys/compat/linux/linux_socket.h	Sat Apr  9 08:52:22 2011	(r220469)
@@ -53,6 +53,7 @@
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
+#define LINUX_SCM_CREDENTIALS   0x02
 
 /* Ancilliary data object information macros */
 
@@ -66,13 +67,14 @@
 #define LINUX_CMSG_FIRSTHDR(msg) \
 				((msg)->msg_controllen >= \
 				    sizeof(struct l_cmsghdr) ? \
-				    (struct l_cmsghdr *)((msg)->msg_control) : \
+				    (struct l_cmsghdr *) \
+				        PTRIN((msg)->msg_control) : \
 				    (struct l_cmsghdr *)(NULL))
 #define LINUX_CMSG_NXTHDR(msg, cmsg) \
 				((((char *)(cmsg) + \
 				    LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \
 				    sizeof(*(cmsg))) > \
-				    (((char *)(msg)->msg_control) + \
+				    (((char *)PTRIN((msg)->msg_control)) + \
 				    (msg)->msg_controllen)) ? \
 				    (struct l_cmsghdr *) NULL : \
 				    (struct l_cmsghdr *)((char *)(cmsg) + \
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 23 dfilter service freebsd_committer freebsd_triage 2011-04-09 10:13:26 UTC
Author: avg
Date: Sat Apr  9 09:12:44 2011
New Revision: 220471
URL: http://svn.freebsd.org/changeset/base/220471

Log:
  MFC r220028: linux compat: add non-dummy capget and capset system calls
  
  PR:		kern/149168

Modified:
  stable/7/sys/amd64/linux32/syscalls.master
  stable/7/sys/i386/linux/syscalls.master
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/amd64/linux32/syscalls.master
==============================================================================
--- stable/7/sys/amd64/linux32/syscalls.master	Sat Apr  9 09:07:31 2011	(r220470)
+++ stable/7/sys/amd64/linux32/syscalls.master	Sat Apr  9 09:12:44 2011	(r220471)
@@ -327,8 +327,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }

Modified: stable/7/sys/i386/linux/syscalls.master
==============================================================================
--- stable/7/sys/i386/linux/syscalls.master	Sat Apr  9 09:07:31 2011	(r220470)
+++ stable/7/sys/i386/linux/syscalls.master	Sat Apr  9 09:12:44 2011	(r220471)
@@ -329,8 +329,10 @@
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
 				    l_ulong bufsize); }
-184	AUE_CAPGET	STD	{ int linux_capget(void); }
-185	AUE_CAPSET	STD	{ int linux_capset(void); }
+184	AUE_CAPGET	STD	{ int linux_capget(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
+185	AUE_CAPSET	STD	{ int linux_capset(struct l_user_cap_header *hdrp, \
+				    struct l_user_cap_data *datap); }
 186	AUE_NULL	STD	{ int linux_sigaltstack(l_stack_t *uss, \
 				    l_stack_t *uoss); }
 187	AUE_SENDFILE	STD	{ int linux_sendfile(void); }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 24 dfilter service freebsd_committer freebsd_triage 2011-04-09 10:20:21 UTC
Author: avg
Date: Sat Apr  9 09:20:11 2011
New Revision: 220472
URL: http://svn.freebsd.org/changeset/base/220472

Log:
  Regen after r220471
  
  PR:		kern/149168

Modified:
  stable/7/sys/amd64/linux32/linux32_proto.h
  stable/7/sys/amd64/linux32/linux32_syscall.h
  stable/7/sys/amd64/linux32/linux32_sysent.c
  stable/7/sys/i386/linux/linux_proto.h
  stable/7/sys/i386/linux/linux_syscall.h
  stable/7/sys/i386/linux/linux_sysent.c

Modified: stable/7/sys/amd64/linux32/linux32_proto.h
==============================================================================
--- stable/7/sys/amd64/linux32/linux32_proto.h	Sat Apr  9 09:12:44 2011	(r220471)
+++ stable/7/sys/amd64/linux32/linux32_proto.h	Sat Apr  9 09:20:11 2011	(r220472)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/7/sys/amd64/linux32/syscalls.master 194400 2009-06-17 21:12:32Z dchagin 
+ * created from FreeBSD: stable/7/sys/amd64/linux32/syscalls.master 220471 2011-04-09 09:12:44Z avg 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -585,10 +585,12 @@ struct linux_getcwd_args {
 	char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)];
 };
 struct linux_capget_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_capset_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_sigaltstack_args {
 	char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)];

Modified: stable/7/sys/amd64/linux32/linux32_syscall.h
==============================================================================
--- stable/7/sys/amd64/linux32/linux32_syscall.h	Sat Apr  9 09:12:44 2011	(r220471)
+++ stable/7/sys/amd64/linux32/linux32_syscall.h	Sat Apr  9 09:20:11 2011	(r220472)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/7/sys/amd64/linux32/syscalls.master 194400 2009-06-17 21:12:32Z dchagin 
+ * created from FreeBSD: stable/7/sys/amd64/linux32/syscalls.master 220471 2011-04-09 09:12:44Z avg 
  */
 
 #define	LINUX_SYS_exit	1

Modified: stable/7/sys/amd64/linux32/linux32_sysent.c
==============================================================================
--- stable/7/sys/amd64/linux32/linux32_sysent.c	Sat Apr  9 09:12:44 2011	(r220471)
+++ stable/7/sys/amd64/linux32/linux32_sysent.c	Sat Apr  9 09:20:11 2011	(r220472)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/7/sys/amd64/linux32/syscalls.master 194400 2009-06-17 21:12:32Z dchagin 
+ * created from FreeBSD: stable/7/sys/amd64/linux32/syscalls.master 220471 2011-04-09 09:12:44Z avg 
  */
 
 #include "opt_compat.h"
@@ -203,8 +203,8 @@ struct sysent linux_sysent[] = {
 	{ AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0 },	/* 181 = linux_pwrite */
 	{ AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0 },	/* 182 = linux_chown16 */
 	{ AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0 },	/* 183 = linux_getcwd */
-	{ 0, (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0 },	/* 184 = linux_capget */
-	{ 0, (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0 },	/* 185 = linux_capset */
+	{ AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0 },	/* 184 = linux_capget */
+	{ AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0 },	/* 185 = linux_capset */
 	{ AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0 },	/* 186 = linux_sigaltstack */
 	{ 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0 },	/* 187 = linux_sendfile */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 },			/* 188 = getpmsg */

Modified: stable/7/sys/i386/linux/linux_proto.h
==============================================================================
--- stable/7/sys/i386/linux/linux_proto.h	Sat Apr  9 09:12:44 2011	(r220471)
+++ stable/7/sys/i386/linux/linux_proto.h	Sat Apr  9 09:20:11 2011	(r220472)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/7/sys/i386/linux/syscalls.master 191820 2009-05-05 14:53:58Z dchagin 
+ * created from FreeBSD: stable/7/sys/i386/linux/syscalls.master 220471 2011-04-09 09:12:44Z avg 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -582,10 +582,12 @@ struct linux_getcwd_args {
 	char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)];
 };
 struct linux_capget_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_capset_args {
-	register_t dummy;
+	char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)];
+	char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)];
 };
 struct linux_sigaltstack_args {
 	char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)];

Modified: stable/7/sys/i386/linux/linux_syscall.h
==============================================================================
--- stable/7/sys/i386/linux/linux_syscall.h	Sat Apr  9 09:12:44 2011	(r220471)
+++ stable/7/sys/i386/linux/linux_syscall.h	Sat Apr  9 09:20:11 2011	(r220472)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/7/sys/i386/linux/syscalls.master 191820 2009-05-05 14:53:58Z dchagin 
+ * created from FreeBSD: stable/7/sys/i386/linux/syscalls.master 220471 2011-04-09 09:12:44Z avg 
  */
 
 #define	LINUX_SYS_exit	1

Modified: stable/7/sys/i386/linux/linux_sysent.c
==============================================================================
--- stable/7/sys/i386/linux/linux_sysent.c	Sat Apr  9 09:12:44 2011	(r220471)
+++ stable/7/sys/i386/linux/linux_sysent.c	Sat Apr  9 09:20:11 2011	(r220472)
@@ -3,7 +3,7 @@
  *
  * DO NOT EDIT-- this file is automatically generated.
  * $FreeBSD$
- * created from FreeBSD: stable/7/sys/i386/linux/syscalls.master 191820 2009-05-05 14:53:58Z dchagin 
+ * created from FreeBSD: stable/7/sys/i386/linux/syscalls.master 220471 2011-04-09 09:12:44Z avg 
  */
 
 #include <sys/param.h>
@@ -202,8 +202,8 @@ struct sysent linux_sysent[] = {
 	{ AS(linux_pwrite_args), (sy_call_t *)linux_pwrite, AUE_PWRITE, NULL, 0, 0 },	/* 181 = linux_pwrite */
 	{ AS(linux_chown16_args), (sy_call_t *)linux_chown16, AUE_CHOWN, NULL, 0, 0 },	/* 182 = linux_chown16 */
 	{ AS(linux_getcwd_args), (sy_call_t *)linux_getcwd, AUE_GETCWD, NULL, 0, 0 },	/* 183 = linux_getcwd */
-	{ 0, (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0 },	/* 184 = linux_capget */
-	{ 0, (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0 },	/* 185 = linux_capset */
+	{ AS(linux_capget_args), (sy_call_t *)linux_capget, AUE_CAPGET, NULL, 0, 0 },	/* 184 = linux_capget */
+	{ AS(linux_capset_args), (sy_call_t *)linux_capset, AUE_CAPSET, NULL, 0, 0 },	/* 185 = linux_capset */
 	{ AS(linux_sigaltstack_args), (sy_call_t *)linux_sigaltstack, AUE_NULL, NULL, 0, 0 },	/* 186 = linux_sigaltstack */
 	{ 0, (sy_call_t *)linux_sendfile, AUE_SENDFILE, NULL, 0, 0 },	/* 187 = linux_sendfile */
 	{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0 },			/* 188 = getpmsg */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 25 dfilter service freebsd_committer freebsd_triage 2011-04-09 10:27:20 UTC
Author: avg
Date: Sat Apr  9 09:27:11 2011
New Revision: 220473
URL: http://svn.freebsd.org/changeset/base/220473

Log:
  MFC r220030: drop dummy definitions
  
  PR:		kern/149168

Modified:
  stable/7/sys/amd64/linux32/linux32_dummy.c
  stable/7/sys/i386/linux/linux_dummy.c
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/amd64/linux32/linux32_dummy.c
==============================================================================
--- stable/7/sys/amd64/linux32/linux32_dummy.c	Sat Apr  9 09:20:11 2011	(r220472)
+++ stable/7/sys/amd64/linux32/linux32_dummy.c	Sat Apr  9 09:27:11 2011	(r220473)
@@ -54,8 +54,6 @@ DUMMY(sysfs);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);
 DUMMY(truncate64);
 DUMMY(setfsuid);

Modified: stable/7/sys/i386/linux/linux_dummy.c
==============================================================================
--- stable/7/sys/i386/linux/linux_dummy.c	Sat Apr  9 09:20:11 2011	(r220472)
+++ stable/7/sys/i386/linux/linux_dummy.c	Sat Apr  9 09:27:11 2011	(r220473)
@@ -57,8 +57,6 @@ DUMMY(vm86);
 DUMMY(query_module);
 DUMMY(nfsservctl);
 DUMMY(rt_sigqueueinfo);
-DUMMY(capget);
-DUMMY(capset);
 DUMMY(sendfile);		/* different semantics */
 DUMMY(truncate64);
 DUMMY(setfsuid);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 26 Andriy Gapon freebsd_committer freebsd_triage 2011-04-09 10:33:56 UTC
State Changed
From-To: patched->closed

The code is in all supported branches now.
Comment 27 dfilter service freebsd_committer freebsd_triage 2011-04-09 10:33:56 UTC
Author: avg
Date: Sat Apr  9 09:33:36 2011
New Revision: 220474
URL: http://svn.freebsd.org/changeset/base/220474

Log:
  MFC r220031: linux compat: improve and fix sendmsg/recvmsg compatibility
  
  PR:		kern/149168

Modified:
  stable/7/sys/compat/linux/linux_misc.c
  stable/7/sys/compat/linux/linux_misc.h
  stable/7/sys/compat/linux/linux_socket.c
  stable/7/sys/compat/linux/linux_socket.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/compat/linux/linux_misc.c
==============================================================================
--- stable/7/sys/compat/linux/linux_misc.c	Sat Apr  9 09:27:11 2011	(r220473)
+++ stable/7/sys/compat/linux/linux_misc.c	Sat Apr  9 09:33:36 2011	(r220474)
@@ -1633,6 +1633,100 @@ linux_exit_group(struct thread *td, stru
 	return (0);
 }
 
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+struct l_user_cap_header {
+	l_int	version;
+	l_int	pid;
+};
+
+struct l_user_cap_data {
+	l_int	effective;
+	l_int	permitted;
+	l_int	inheritable;
+};
+
+int
+linux_capget(struct thread *td, struct linux_capget_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	if (args->datap) {
+		/*
+		 * The current implementation doesn't support setting
+		 * a capability (it's essentially a stub) so indicate
+		 * that no capabilities are currently set or available
+		 * to request.
+		 */
+		bzero (&lucd, sizeof(lucd));
+		error = copyout(&lucd, args->datap, sizeof(lucd));
+	}
+
+	return (error);
+}
+
+int
+linux_capset(struct thread *td, struct linux_capset_args *args)
+{
+	struct l_user_cap_header luch;
+	struct l_user_cap_data lucd;
+	int error;
+
+	if (args->hdrp == NULL || args->datap == NULL)
+		return (EFAULT);
+
+	error = copyin(args->hdrp, &luch, sizeof(luch));
+	if (error != 0)
+		return (error);
+
+	if (luch.version != _LINUX_CAPABILITY_VERSION) {
+		luch.version = _LINUX_CAPABILITY_VERSION;
+		error = copyout(&luch, args->hdrp, sizeof(luch));
+		if (error)
+			return (error);
+		return (EINVAL);
+	}
+
+	if (luch.pid)
+		return (EPERM);
+
+	error = copyin(args->datap, &lucd, sizeof(lucd));
+	if (error != 0)
+		return (error);
+
+	/* We currently don't support setting any capabilities. */
+	if (lucd.effective || lucd.permitted || lucd.inheritable) {
+		linux_msg(td,
+			  "capset effective=0x%x, permitted=0x%x, "
+			  "inheritable=0x%x is not implemented",
+			  (int)lucd.effective, (int)lucd.permitted,
+			  (int)lucd.inheritable);
+		return (EPERM);
+	}
+
+	return (0);
+}
+
 int
 linux_prctl(struct thread *td, struct linux_prctl_args *args)
 {
@@ -1666,6 +1760,21 @@ linux_prctl(struct thread *td, struct li
 		    (void *)(register_t)args->arg2,
 		    sizeof(pdeath_signal));
 		break;
+	case LINUX_PR_GET_KEEPCAPS:
+		/*
+		 * Indicate that we always clear the effective and
+		 * permitted capability sets when the user id becomes
+		 * non-zero (actually the capability sets are simply
+		 * always zero in the current implementation).
+		 */
+		td->td_retval[0] = 0;
+		break;
+	case LINUX_PR_SET_KEEPCAPS:
+		/*
+		 * Ignore requests to keep the effective and permitted
+		 * capability sets when the user id becomes non-zero.
+		 */
+		break;
 	case LINUX_PR_SET_NAME:
 		/*
 		 * To be on the safe side we need to make sure to not

Modified: stable/7/sys/compat/linux/linux_misc.h
==============================================================================
--- stable/7/sys/compat/linux/linux_misc.h	Sat Apr  9 09:27:11 2011	(r220473)
+++ stable/7/sys/compat/linux/linux_misc.h	Sat Apr  9 09:33:36 2011	(r220474)
@@ -37,6 +37,8 @@
 					 * Second arg is a ptr to return the
 					 * signal.
 					 */
+#define	LINUX_PR_GET_KEEPCAPS	7	/* Get drop capabilities on setuid */
+#define	LINUX_PR_SET_KEEPCAPS	8	/* Set drop capabilities on setuid */
 #define	LINUX_PR_SET_NAME	15	/* Set process name. */
 #define	LINUX_PR_GET_NAME	16	/* Get process name. */
 

Modified: stable/7/sys/compat/linux/linux_socket.c
==============================================================================
--- stable/7/sys/compat/linux/linux_socket.c	Sat Apr  9 09:27:11 2011	(r220473)
+++ stable/7/sys/compat/linux/linux_socket.c	Sat Apr  9 09:33:36 2011	(r220474)
@@ -431,6 +431,8 @@ linux_to_bsd_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case LINUX_SCM_RIGHTS:
 		return (SCM_RIGHTS);
+	case LINUX_SCM_CREDENTIALS:
+		return (SCM_CREDS);
 	}
 	return (-1);
 }
@@ -442,6 +444,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
 	switch (cmsg_type) {
 	case SCM_RIGHTS:
 		return (LINUX_SCM_RIGHTS);
+	case SCM_CREDS:
+		return (LINUX_SCM_CREDENTIALS);
 	}
 	return (-1);
 }
@@ -459,7 +463,16 @@ linux_to_bsd_msghdr(struct msghdr *bhdr,
 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
-	bhdr->msg_controllen	= lhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
 	return (0);
 }
@@ -472,7 +485,16 @@ bsd_to_linux_msghdr(const struct msghdr 
 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
-	lhdr->msg_controllen	= bhdr->msg_controllen;
+
+	/*
+	 * msg_controllen is skipped since BSD and LINUX control messages
+	 * are potentially different sizes (e.g. the cred structure used
+	 * by SCM_CREDS is different between the two operating system).
+	 *
+	 * The caller can set it (if necessary) after converting all the
+	 * control messages.
+	 */
+
 	/* msg_flags skipped */
 	return (0);
 }
@@ -1034,6 +1056,7 @@ static int
 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 {
 	struct cmsghdr *cmsg;
+	struct cmsgcred cmcred;
 	struct mbuf *control;
 	struct msghdr msg;
 	struct l_cmsghdr linux_cmsg;
@@ -1041,15 +1064,14 @@ linux_sendmsg(struct thread *td, struct 
 	struct l_msghdr linux_msg;
 	struct iovec *iov;
 	socklen_t datalen;
+	struct sockaddr *sa;
+	sa_family_t sa_family;
 	void *data;
 	int error;
 
 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
 	if (error)
 		return (error);
-	error = linux_to_bsd_msghdr(&msg, &linux_msg);
-	if (error)
-		return (error);
 
 	/*
 	 * Some Linux applications (ping) define a non-NULL control data
@@ -1058,8 +1080,12 @@ linux_sendmsg(struct thread *td, struct 
 	 * order to handle this case.  This should be checked, but allows the
 	 * Linux ping to work.
 	 */
-	if (msg.msg_control != NULL && msg.msg_controllen == 0)
-		msg.msg_control = NULL;
+	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
+		linux_msg.msg_control = PTROUT(NULL);
+
+	error = linux_to_bsd_msghdr(&msg, &linux_msg);
+	if (error)
+		return (error);
 
 #ifdef COMPAT_LINUX32
 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
@@ -1070,13 +1096,21 @@ linux_sendmsg(struct thread *td, struct 
 	if (error)
 		return (error);
 
-	if (msg.msg_control != NULL) {
+	control = NULL;
+	cmsg = NULL;
+
+	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
+		error = kern_getsockname(td, args->s, &sa, &datalen);
+		if (error)
+			goto bad;
+		sa_family = sa->sa_family;
+		free(sa, M_SONAME);
+
 		error = ENOBUFS;
 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
 		control = m_get(M_WAIT, MT_CONTROL);
 		if (control == NULL)
 			goto bad;
-		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
 
 		do {
 			error = copyin(ptr_cmsg, &linux_cmsg,
@@ -1089,28 +1123,58 @@ linux_sendmsg(struct thread *td, struct 
 				goto bad;
 
 			/*
-			 * Now we support only SCM_RIGHTS, so return EINVAL
-			 * in any other cmsg_type
+			 * Now we support only SCM_RIGHTS and SCM_CRED,
+			 * so return EINVAL in any other cmsg_type
 			 */
-			if ((cmsg->cmsg_type =
-			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
-				goto bad;
+			cmsg->cmsg_type =
+			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
 			cmsg->cmsg_level =
 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
+			if (cmsg->cmsg_type == -1
+			    || cmsg->cmsg_level != SOL_SOCKET)
+				goto bad;
 
+			/*
+			 * Some applications (e.g. pulseaudio) attempt to
+			 * send ancillary data even if the underlying protocol
+			 * doesn't support it which is not allowed in the
+			 * FreeBSD system call interface.
+			 */
+			if (sa_family != AF_UNIX)
+				continue;
+
+			data = LINUX_CMSG_DATA(ptr_cmsg);
 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
+
+			switch (cmsg->cmsg_type)
+			{
+			case SCM_RIGHTS:
+				break;
+
+			case SCM_CREDS:
+				data = &cmcred;
+				datalen = sizeof(cmcred);
+
+				/*
+				 * The lower levels will fill in the structure
+				 */
+				bzero(data, datalen);
+				break;
+			}
+
 			cmsg->cmsg_len = CMSG_LEN(datalen);
-			data = LINUX_CMSG_DATA(ptr_cmsg);
 
 			error = ENOBUFS;
 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
 				goto bad;
 			if (!m_append(control, datalen, (c_caddr_t) data))
 				goto bad;
-		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
-	} else {
-		control = NULL;
-		cmsg = NULL;
+		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
+
+		if (m_length(control, NULL) == 0) {
+			m_freem(control);
+			control = NULL;
+		}
 	}
 
 	msg.msg_iov = iov;
@@ -1135,9 +1199,11 @@ static int
 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 {
 	struct cmsghdr *cm;
+	struct cmsgcred *cmcred;
 	struct msghdr msg;
 	struct l_cmsghdr *linux_cmsg = NULL;
-	socklen_t datalen, outlen, clen;
+	struct l_ucred linux_ucred;
+	socklen_t datalen, outlen;
 	struct l_msghdr linux_msg;
 	struct iovec *iov, *uiov;
 	struct mbuf *control = NULL;
@@ -1194,39 +1260,35 @@ linux_recvmsg(struct thread *td, struct 
 			goto bad;
 	}
 
-	if (control) {
+	outbuf = PTRIN(linux_msg.msg_control);
+	outlen = 0;
 
+	if (control) {
 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
-		outbuf = PTRIN(linux_msg.msg_control);
-		cm = mtod(control, struct cmsghdr *);
-		outlen = 0;
-		clen = control->m_len;
 
-		while (cm != NULL) {
+		msg.msg_control = mtod(control, struct cmsghdr *);
+		msg.msg_controllen = control->m_len;
+
+		cm = CMSG_FIRSTHDR(&msg);
 
-			if ((linux_cmsg->cmsg_type =
-			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
+		while (cm != NULL) {
+			linux_cmsg->cmsg_type =
+			    bsd_to_linux_cmsg_type(cm->cmsg_type);
+			linux_cmsg->cmsg_level =
+			    bsd_to_linux_sockopt_level(cm->cmsg_level);
+			if (linux_cmsg->cmsg_type == -1
+			    || cm->cmsg_level != SOL_SOCKET)
 			{
 				error = EINVAL;
 				goto bad;
 			}
+
 			data = CMSG_DATA(cm);
 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 
-			switch (linux_cmsg->cmsg_type)
+			switch (cm->cmsg_type)
 			{
-			case LINUX_SCM_RIGHTS:
-				if (outlen + LINUX_CMSG_LEN(datalen) >
-				    linux_msg.msg_controllen) {
-					if (outlen == 0) {
-						error = EMSGSIZE;
-						goto bad;
-					} else {
-						linux_msg.msg_flags |=
-						    LINUX_MSG_CTRUNC;
-						goto out;
-					}
-				}
+			case SCM_RIGHTS:
 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
 					fds = datalen / sizeof(int);
 					fdp = data;
@@ -1237,11 +1299,40 @@ linux_recvmsg(struct thread *td, struct 
 					}
 				}
 				break;
+
+			case SCM_CREDS:
+				/*
+				 * Currently LOCAL_CREDS is never in
+				 * effect for Linux so no need to worry
+				 * about sockcred
+				 */
+				if (datalen != sizeof (*cmcred)) {
+					error = EMSGSIZE;
+					goto bad;
+				}
+				cmcred = (struct cmsgcred *)data;
+				bzero(&linux_ucred, sizeof(linux_ucred));
+				linux_ucred.pid = cmcred->cmcred_pid;
+				linux_ucred.uid = cmcred->cmcred_uid;
+				linux_ucred.gid = cmcred->cmcred_gid;
+				data = &linux_ucred;
+				datalen = sizeof(linux_ucred);
+				break;
+			}
+
+			if (outlen + LINUX_CMSG_LEN(datalen) >
+			    linux_msg.msg_controllen) {
+				if (outlen == 0) {
+					error = EMSGSIZE;
+					goto bad;
+				} else {
+					linux_msg.msg_flags |=
+					    LINUX_MSG_CTRUNC;
+					goto out;
+				}
 			}
 
 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
-			linux_cmsg->cmsg_level =
-			    bsd_to_linux_sockopt_level(cm->cmsg_level);
 
 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
 			if (error)
@@ -1254,18 +1345,13 @@ linux_recvmsg(struct thread *td, struct 
 
 			outbuf += LINUX_CMSG_ALIGN(datalen);
 			outlen += LINUX_CMSG_LEN(datalen);
-			linux_msg.msg_controllen = outlen;
 
-			if (CMSG_SPACE(datalen) < clen) {
-				clen -= CMSG_SPACE(datalen);
-				cm = (struct cmsghdr *)
-				    ((caddr_t)cm + CMSG_SPACE(datalen));
-			} else
-				cm = NULL;
+			cm = CMSG_NXTHDR(&msg, cm);
 		}
 	}
 
 out:
+	linux_msg.msg_controllen = outlen;
 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
 
 bad:

Modified: stable/7/sys/compat/linux/linux_socket.h
==============================================================================
--- stable/7/sys/compat/linux/linux_socket.h	Sat Apr  9 09:27:11 2011	(r220473)
+++ stable/7/sys/compat/linux/linux_socket.h	Sat Apr  9 09:33:36 2011	(r220474)
@@ -53,6 +53,7 @@
 /* Socket-level control message types */
 
 #define LINUX_SCM_RIGHTS	0x01
+#define LINUX_SCM_CREDENTIALS   0x02
 
 /* Ancilliary data object information macros */
 
@@ -66,13 +67,14 @@
 #define LINUX_CMSG_FIRSTHDR(msg) \
 				((msg)->msg_controllen >= \
 				    sizeof(struct l_cmsghdr) ? \
-				    (struct l_cmsghdr *)((msg)->msg_control) : \
+				    (struct l_cmsghdr *) \
+				        PTRIN((msg)->msg_control) : \
 				    (struct l_cmsghdr *)(NULL))
 #define LINUX_CMSG_NXTHDR(msg, cmsg) \
 				((((char *)(cmsg) + \
 				    LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \
 				    sizeof(*(cmsg))) > \
-				    (((char *)(msg)->msg_control) + \
+				    (((char *)PTRIN((msg)->msg_control)) + \
 				    (msg)->msg_controllen)) ? \
 				    (struct l_cmsghdr *) NULL : \
 				    (struct l_cmsghdr *)((char *)(cmsg) + \
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"