From d972eee1e7d12a787bf64c545caa54bbde6c780a Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 25 Sep 2014 21:07:19 +0000 Subject: [PATCH] Fix fcntl(2) compat32 after r270691. The copyin and copyout of the struct flock are done in the sys_fcntl(), which mean that compat32 used direct access to userland pointers. Move code from sys_fcntl() to new wrapper, kern_fcntl_freebsd(), which performs neccessary userland memory accesses, and use it from both native and compat32 fcntl syscalls. Reported by: jhibbits Sponsored by: The FreeBSD Foundation MFC after: 3 days --- sys/compat/freebsd32/freebsd32_misc.c | 4 +-- sys/kern/kern_descrip.c | 35 +++++++++++++++------------ sys/sys/syscallsubr.h | 1 + 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index fb8736cacf2d..d909a71ff270 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -2984,7 +2984,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) int freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap) { - intptr_t tmp; + long tmp; switch (uap->cmd) { /* @@ -3003,5 +3003,5 @@ freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap) tmp = uap->arg; break; } - return (kern_fcntl(td, uap->fd, uap->cmd, tmp)); + return (kern_fcntl_freebsd(td, uap->fd, uap->cmd, tmp)); } diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 4564eb87fea9..333faf246316 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -377,23 +377,28 @@ struct fcntl_args { /* ARGSUSED */ int sys_fcntl(struct thread *td, struct fcntl_args *uap) +{ + + return (kern_fcntl_freebsd(td, uap->fd, uap->cmd, uap->arg)); +} + +int +kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg) { struct flock fl; struct __oflock ofl; - intptr_t arg; + intptr_t arg1; int error; - int cmd; error = 0; - cmd = uap->cmd; - switch (uap->cmd) { + switch (cmd) { case F_OGETLK: case F_OSETLK: case F_OSETLKW: /* * Convert old flock structure to new. */ - error = copyin((void *)(intptr_t)uap->arg, &ofl, sizeof(ofl)); + error = copyin((void *)(intptr_t)arg, &ofl, sizeof(ofl)); fl.l_start = ofl.l_start; fl.l_len = ofl.l_len; fl.l_pid = ofl.l_pid; @@ -401,7 +406,7 @@ sys_fcntl(struct thread *td, struct fcntl_args *uap) fl.l_whence = ofl.l_whence; fl.l_sysid = 0; - switch (uap->cmd) { + switch (cmd) { case F_OGETLK: cmd = F_GETLK; break; @@ -412,33 +417,33 @@ sys_fcntl(struct thread *td, struct fcntl_args *uap) cmd = F_SETLKW; break; } - arg = (intptr_t)&fl; + arg1 = (intptr_t)&fl; break; case F_GETLK: case F_SETLK: case F_SETLKW: case F_SETLK_REMOTE: - error = copyin((void *)(intptr_t)uap->arg, &fl, sizeof(fl)); - arg = (intptr_t)&fl; + error = copyin((void *)(intptr_t)arg, &fl, sizeof(fl)); + arg1 = (intptr_t)&fl; break; default: - arg = uap->arg; + arg1 = arg; break; } if (error) return (error); - error = kern_fcntl(td, uap->fd, cmd, arg); + error = kern_fcntl(td, fd, cmd, arg1); if (error) return (error); - if (uap->cmd == F_OGETLK) { + if (cmd == F_OGETLK) { ofl.l_start = fl.l_start; ofl.l_len = fl.l_len; ofl.l_pid = fl.l_pid; ofl.l_type = fl.l_type; ofl.l_whence = fl.l_whence; - error = copyout(&ofl, (void *)(intptr_t)uap->arg, sizeof(ofl)); - } else if (uap->cmd == F_GETLK) { - error = copyout(&fl, (void *)(intptr_t)uap->arg, sizeof(fl)); + error = copyout(&ofl, (void *)(intptr_t)arg, sizeof(ofl)); + } else if (cmd == F_GETLK) { + error = copyout(&fl, (void *)(intptr_t)arg, sizeof(fl)); } return (error); } diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index bc447ab3bda5..05e9be832f24 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -97,6 +97,7 @@ int kern_fchmodat(struct thread *td, int fd, char *path, int kern_fchownat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int uid, int gid, int flag); int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg); +int kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg); int kern_fhstat(struct thread *td, fhandle_t fh, struct stat *buf); int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf); int kern_fstat(struct thread *td, int fd, struct stat *sbp);