--- orig-linux_socket.c 2021-11-08 00:00:00 +0000 +++ work-linux_socket.c 2021-11-09 00:00:00 +0000 @@ -890,11 +890,49 @@ UIO_USERSPACE)); } +static int +linux_sa_put(struct osockaddr *osa) +{ + struct osockaddr sa; + int error, bdom; + + /* + * Only read/write the osockaddr family part, the rest is + * not changed. + */ + error = copyin(osa, &sa, sizeof(sa.sa_family)); + if (error != 0) + return (error); + + bdom = bsd_to_linux_domain(sa.sa_family); + if (bdom == -1) + return (EINVAL); + + sa.sa_family = bdom; + return (copyout(&sa, osa, sizeof(sa.sa_family))); +} + +static int +old_bsd_to_linux_sockaddr(struct sockaddr *arg) +{ + struct sockaddr sa; + size_t sa_len = sizeof(struct sockaddr); + int error, bdom; + + if ((error = copyin(arg, &sa, sa_len))) + return (error); + + bdom = bsd_to_linux_domain(sa.sa_family); + if (bdom == -1) + return (EAFNOSUPPORT); + + *(u_short *)&sa = bdom; + return (copyout(&sa, arg, sa_len)); +} + int linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) { - struct l_sockaddr *lsa; - struct sockaddr *sa; struct msghdr msg; struct iovec aiov; int error, fromlen; @@ -906,14 +944,11 @@ return (error); if (fromlen < 0) return (EINVAL); - sa = malloc(fromlen, M_SONAME, M_WAITOK); - } else { - fromlen = 0; - sa = NULL; - } + msg.msg_namelen = fromlen; + } else + msg.msg_namelen = 0; - msg.msg_name = sa; - msg.msg_namelen = fromlen; + msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from); msg.msg_iov = &aiov; msg.msg_iovlen = 1; aiov.iov_base = PTRIN(args->buf); @@ -921,23 +956,23 @@ msg.msg_control = 0; msg.msg_flags = linux_to_bsd_msg_flags(args->flags); - error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL); + error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL); if (error != 0) - goto out; + return (error); if (PTRIN(args->from) != NULL) { - error = bsd_to_linux_sockaddr(sa, &lsa, msg.msg_namelen); - if (error == 0) - error = copyout(lsa, PTRIN(args->from), - msg.msg_namelen); - free(lsa, M_SONAME); + error = old_bsd_to_linux_sockaddr((struct sockaddr *)PTRIN(args->from)); + if (error != 0) + return (error); + + error = linux_sa_put((struct osockaddr *) + PTRIN(args->from)); } - if (error == 0 && PTRIN(args->fromlen) != NULL) + if (PTRIN(args->fromlen) != NULL) error = copyout(&msg.msg_namelen, PTRIN(args->fromlen), sizeof(msg.msg_namelen)); -out: - free(sa, M_SONAME); + return (error); }