git: e92b9a9eaa64 - main - linux(4): Add a helper to copyout getsockopt value

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Sat, 28 May 2022 20:53:17 UTC
The branch main has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=e92b9a9eaa646bc1037af2a838270c43ea607d55

commit e92b9a9eaa646bc1037af2a838270c43ea607d55
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2022-05-28 20:30:22 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-05-28 20:30:22 +0000

    linux(4): Add a helper to copyout getsockopt value
    
    For getsockopt(), optlen is a value-result argument, which is modified
    on return to indicate the actual size of the value returned.
    For some cases this was missed, fixed.
    
    MFC after:              2 weeks
---
 sys/compat/linux/linux_socket.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 8aa425bc14c0..0c003cd5729f 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -1924,6 +1924,18 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
 	return (error);
 }
 
+static int
+linux_sockopt_copyout(struct thread *td, void *val, socklen_t len,
+    struct linux_getsockopt_args *args)
+{
+	int error;
+
+	error = copyout(val, PTRIN(args->optval), len);
+	if (error == 0)
+		error = copyout(&len, PTRIN(args->optlen), sizeof(len));
+	return (error);
+}
+
 static int
 linux_getsockopt_so_peergroups(struct thread *td,
     struct linux_getsockopt_args *args)
@@ -1976,13 +1988,11 @@ linux_getsockopt_so_peersec(struct thread *td,
 		return (error);
 	}
 
-	error = copyout(SECURITY_CONTEXT_STRING,
-	    PTRIN(args->optval), sizeof(SECURITY_CONTEXT_STRING));
-	if (error == 0)
-		error = copyout(&len, PTRIN(args->optlen), sizeof(len));
-	return (error);
+	return (linux_sockopt_copyout(td, SECURITY_CONTEXT_STRING,
+	    len, args));
 }
 
+
 int
 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 {
@@ -2021,8 +2031,8 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 				return (error);
 			linux_tv.tv_sec = tv.tv_sec;
 			linux_tv.tv_usec = tv.tv_usec;
-			return (copyout(&linux_tv, PTRIN(args->optval),
-			    sizeof(linux_tv)));
+			return (linux_sockopt_copyout(td, &linux_tv,
+			    sizeof(linux_tv), args));
 			/* NOTREACHED */
 		case LOCAL_PEERCRED:
 			if (args->optlen < sizeof(lxu))
@@ -2040,7 +2050,8 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 			lxu.pid = xu.cr_pid;
 			lxu.uid = xu.cr_uid;
 			lxu.gid = xu.cr_gid;
-			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
+			return (linux_sockopt_copyout(td, &lxu,
+			    sizeof(lxu), args));
 			/* NOTREACHED */
 		case SO_ERROR:
 			len = sizeof(newval);
@@ -2049,7 +2060,8 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 			if (error != 0)
 				return (error);
 			newval = -bsd_to_linux_errno(newval);
-			return (copyout(&newval, PTRIN(args->optval), len));
+			return (linux_sockopt_copyout(td, &newval,
+			    len, args));
 			/* NOTREACHED */
 		case SO_DOMAIN:
 			len = sizeof(newval);
@@ -2060,7 +2072,8 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 			newval = bsd_to_linux_domain(newval);
 			if (newval == -1)
 				return (ENOPROTOOPT);
-			return (copyout(&newval, PTRIN(args->optval), len));
+			return (linux_sockopt_copyout(td, &newval,
+			    len, args));
 			/* NOTREACHED */
 		default:
 			break;