svn commit: r362833 - head/sys/compat/linux

Edward Tomasz Napierala trasz at FreeBSD.org
Wed Jul 1 10:37:08 UTC 2020


Author: trasz
Date: Wed Jul  1 10:37:08 2020
New Revision: 362833
URL: https://svnweb.freebsd.org/changeset/base/362833

Log:
  Rework linux accept(2).  This makes the code flow easier to follow,
  and fixes a bug where calling accept(2) could result in closing fd 0.
  
  Note that the code still contains a number of problems: it makes
  assumptions about l_sockaddr_in being the same as sockaddr_in,
  the EFAULT-related code looks like it doesn't work at all, and the
  socket type check is racy.  Those will be addressed later on;
  I'm trying to work in small steps to avoid breaking one thing while
  fixing another.
  
  It fixes Redis, among other things.
  
  Reviewed by:	kib
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D25461

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

Modified: head/sys/compat/linux/linux_socket.c
==============================================================================
--- head/sys/compat/linux/linux_socket.c	Wed Jul  1 09:35:33 2020	(r362832)
+++ head/sys/compat/linux/linux_socket.c	Wed Jul  1 10:37:08 2020	(r362833)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/capsicum.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
+#include <sys/filedesc.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
@@ -611,17 +612,19 @@ linux_accept_common(struct thread *td, int s, l_uintpt
 {
 	struct l_sockaddr *lsa;
 	struct sockaddr *sa;
-	struct file *fp;
+	struct file *fp, *fp1;
 	int bflags, len;
 	struct socket *so;
 	int error, error1;
 
 	bflags = 0;
+	fp = NULL;
+	sa = NULL;
+
 	error = linux_set_socket_flags(flags, &bflags);
 	if (error != 0)
 		return (error);
 
-	sa = NULL;
 	if (PTRIN(addr) == NULL) {
 		len = 0;
 		error = kern_accept4(td, s, NULL, NULL, bflags, NULL);
@@ -632,48 +635,54 @@ linux_accept_common(struct thread *td, int s, l_uintpt
 		if (len < 0)
 			return (EINVAL);
 		error = kern_accept4(td, s, &sa, &len, bflags, &fp);
-		if (error == 0)
-			fdrop(fp, td);
 	}
 
+	/*
+	 * Translate errno values into ones used by Linux.
+	 */
 	if (error != 0) {
 		/*
 		 * XXX. This is wrong, different sockaddr structures
 		 * have different sizes.
 		 */
-		if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
-		{
-			error = EINVAL;
-			goto out;
-		}
-		if (error == EINVAL) {
-			error1 = getsock_cap(td, s, &cap_accept_rights, &fp, NULL, NULL);
+		switch (error) {
+		case EFAULT:
+			if (namelen != sizeof(struct sockaddr_in))
+				error = EINVAL;
+			break;
+		case EINVAL:
+			error1 = getsock_cap(td, s, &cap_accept_rights, &fp1, NULL, NULL);
 			if (error1 != 0) {
 				error = error1;
-				goto out;
+				break;
 			}
-			so = fp->f_data;
+			so = fp1->f_data;
 			if (so->so_type == SOCK_DGRAM)
 				error = EOPNOTSUPP;
-			fdrop(fp, td);
+			fdrop(fp1, td);
+			break;
 		}
-		goto out;
+		return (error);
 	}
 
-	if (len != 0 && error == 0) {
+	if (len != 0) {
 		error = bsd_to_linux_sockaddr(sa, &lsa, len);
 		if (error == 0)
 			error = copyout(lsa, PTRIN(addr), len);
 		free(lsa, M_SONAME);
-	}
 
-	free(sa, M_SONAME);
+		/*
+		 * XXX: We should also copyout the len, shouldn't we?
+		 */
 
-out:
-	if (error != 0) {
-		(void)kern_close(td, td->td_retval[0]);
-		td->td_retval[0] = 0;
+		if (error != 0) {
+			fdclose(td, fp, td->td_retval[0]);
+			td->td_retval[0] = 0;
+		}
 	}
+	if (fp != NULL)
+		fdrop(fp, td);
+	free(sa, M_SONAME);
 	return (error);
 }
 


More information about the svn-src-all mailing list