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
This commit is contained in:
Dmitry Chagin 2022-05-28 23:30:22 +03:00
parent 3a99aac66f
commit e92b9a9eaa

View File

@ -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;