diff options
author | dchagin <dchagin@FreeBSD.org> | 2009-05-19 09:10:53 +0000 |
---|---|---|
committer | dchagin <dchagin@FreeBSD.org> | 2009-05-19 09:10:53 +0000 |
commit | 56c9819821af0ba40bed6b1d2e8cfb2692657d9c (patch) | |
tree | 595f98e75dfc9b6e439550cc03bcf979bdeb732d /sys/compat/linux/linux_socket.c | |
parent | ab6b6454c05ae3b9fa623320d6f450dd224857f3 (diff) | |
download | FreeBSD-src-56c9819821af0ba40bed6b1d2e8cfb2692657d9c.zip FreeBSD-src-56c9819821af0ba40bed6b1d2e8cfb2692657d9c.tar.gz |
Validate user-supplied arguments values.
Args argument is a pointer to the structure located in user space in
which the socketcall arguments are packed. The structure must be
copied to the kernel instead of direct dereferencing.
Approved by: kib (mentor)
MFC after: 1 week
Diffstat (limited to 'sys/compat/linux/linux_socket.c')
-rw-r--r-- | sys/compat/linux/linux_socket.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 114a6d5..1ab5bdf 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -1467,11 +1467,38 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) return (error); } +/* Argument list sizes for linux_socketcall */ + +#define LINUX_AL(x) ((x) * sizeof(l_ulong)) + +static const unsigned char lxs_args[] = { + LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */, + LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */, + LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */, + LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */, + LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */, + LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */, + LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */, + LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */, + LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */ +}; + +#define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1 + int linux_socketcall(struct thread *td, struct linux_socketcall_args *args) { - void *arg = (void *)(intptr_t)args->args; + l_ulong a[6]; + void *arg; + int error; + + if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE) + return (EINVAL); + error = copyin(PTRIN(args->args), a, lxs_args[args->what]); + if (error) + return (error); + arg = a; switch (args->what) { case LINUX_SOCKET: return (linux_socket(td, arg)); |