The bsd_to_linux_sockaddr() and linux_to_bsd_sockaddr() functions alter the userspace sockaddr to convert the format between linux and BSD versions. If the sockaddr is shared between concurrent syscalls or the pages are unwritable these functions will fail. Code should either be altered to perform the transformation purely in the kernel or at a minimum, copyout_map should be used to allocated a new location for the transformed sockaddr.
Another related issue is: The function 'linux_getsockname' in 'linux_socket.c' calls 'bsd_to_linux_sockaddr', and it calls 'bsd_to_linux_domain' to convert 'sa_family' from BSD domain to Linux domain. But after calling 'bsd_to_linux_sockaddr', 'linux_sa_put' is called, and it calls 'bsd_to_linux_domain' to convert 'sa_family' from BSD domain to Linux domain again. But the 'sa_family' has already been converted. Since the value of AF_INTE6 and LINUX_AF_INET6 is different, and converting twice will cause issue. Test Case below: get_sock_name_case.c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> int main() { int sock; int len = sizeof(struct sockaddr_in6); struct sockaddr_in6 add; if ((sock=socket(AF_INET6, SOCK_STREAM, 0)) < 0) { perror("sock"); return 1; } memset(&add, 0, len); add.sin6_family = AF_INET6; add.sin6_port = htons(10000); printf("bind address type:%d-port:%d\n", add.sin6_family, ntohs(add.sin6_port)); if (bind(sock, (struct sockaddr *)&add, len)<0) { perror("bind"); return 1; } memset(&add, 0, len); getsockname(sock, (struct sockaddr *)&add, &len); printf("getsockname address type:%d-port:%d\n", add.sin6_family, ntohs(add.sin6_port)); return 0; } result: case in linux user@~/:uname -a Linux CentOS 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux user@~/:cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) bind address type:10-port:10000 getsockname address type:10-port:10000 case in freebsd [user@host ~]# uname -a FreeBSD host 12.0-RELEASE FreeBSD 12.0-RELEASE #94 308a36af9(master)-dirty: Mon Feb 25 16:33:41 CST 2019 KERNCONF amd64 [user@host ~]# ./case bind address type:10-port:10000 getsockname address type:3-port:10000
A commit references this bug: Author: dchagin Date: Mon May 13 17:48:17 UTC 2019 New revision: 347533 URL: https://svnweb.freebsd.org/changeset/base/347533 Log: Our bsd_to_linux_sockaddr() and linux_to_bsd_sockaddr() functions alter the userspace sockaddr to convert the format between linux and BSD versions. That's the minimum 3 of copyin/copyout operations for one syscall. Also some syscall uses linux_sa_put() and linux_getsockaddr() when load sockaddr to userspace or from userspace accordingly. To avoid this chaos, especially converting sockaddr in the userspace, rewrite these 4 functions to convert sockaddr only in kernel and leave only 2 of this functions. Also in order to reduce duplication between MD parts of the Linuxulator put struct sockaddr conversion functions that are MI out into linux_common module. PR: 232920 MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D20157 Changes: head/sys/compat/linux/linux.c head/sys/compat/linux/linux.h head/sys/compat/linux/linux_common.h head/sys/compat/linux/linux_socket.c head/sys/compat/linux/linux_socket.h head/sys/modules/linux_common/Makefile
Should this PR be kept open? I note that there was no MFC.
(In reply to Mark Johnston from comment #3) will mfc it soon
A commit references this bug: Author: trasz Date: Mon Aug 24 15:45:43 UTC 2020 New revision: 364693 URL: https://svnweb.freebsd.org/changeset/base/364693 Log: MFC r347533 by dchagin: Our bsd_to_linux_sockaddr() and linux_to_bsd_sockaddr() functions alter the userspace sockaddr to convert the format between linux and BSD versions. That's the minimum 3 of copyin/copyout operations for one syscall. Also some syscall uses linux_sa_put() and linux_getsockaddr() when load sockaddr to userspace or from userspace accordingly. To avoid this chaos, especially converting sockaddr in the userspace, rewrite these 4 functions to convert sockaddr only in kernel and leave only 2 of this functions. Also in order to reduce duplication between MD parts of the Linuxulator put struct sockaddr conversion functions that are MI out into linux_common module. PR: 232920 Changes: _U stable/12/ stable/12/sys/compat/linux/linux.c stable/12/sys/compat/linux/linux.h stable/12/sys/compat/linux/linux_common.h stable/12/sys/compat/linux/linux_socket.c stable/12/sys/compat/linux/linux_socket.h stable/12/sys/modules/linux_common/Makefile