Date: Wed, 17 Nov 2021 20:22:45 GMT From: Brooks Davis <brooks@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 2b9d052d3eeb - main - freebsd32: fix getfsstat sign extension bugs Message-ID: <202111172022.1AHKMj4a060140@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by brooks: URL: https://cgit.FreeBSD.org/src/commit/?id=2b9d052d3eeb9ffd1094dc5165eff555b9fd6bc3 commit 2b9d052d3eeb9ffd1094dc5165eff555b9fd6bc3 Author: Brooks Davis <brooks@FreeBSD.org> AuthorDate: 2021-11-17 20:12:26 +0000 Commit: Brooks Davis <brooks@FreeBSD.org> CommitDate: 2021-11-17 20:12:26 +0000 freebsd32: fix getfsstat sign extension bugs Add freebsd32 versions of getfsstat and freebsd11_getfsstat so that bufsize is properly sign-extended if a negative value is passed. Reject negative values before passing to kern_getfsstat as a size_t. Reviewed by: kevans --- sys/compat/freebsd32/freebsd32_misc.c | 25 +++++++++++++++++++++++++ sys/compat/freebsd32/freebsd32_proto.h | 14 ++++++++++++++ sys/compat/freebsd32/freebsd32_syscall.h | 4 ++-- sys/compat/freebsd32/freebsd32_syscalls.c | 4 ++-- sys/compat/freebsd32/freebsd32_sysent.c | 4 ++-- sys/compat/freebsd32/freebsd32_systrace_args.c | 8 ++++---- sys/compat/freebsd32/syscalls.master | 4 ++-- sys/kern/vfs_syscalls.c | 19 ++++++++++++++----- sys/sys/syscallsubr.h | 2 ++ 9 files changed, 67 insertions(+), 17 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index a165b47b2928..5bff0cea845e 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -292,6 +292,21 @@ copy_statfs(struct statfs *in, struct ostatfs32 *out) } #endif +int +freebsd32_getfsstat(struct thread *td, struct freebsd32_getfsstat_args *uap) +{ + size_t count; + int error; + + if (uap->bufsize < 0 || uap->bufsize > SIZE_MAX) + return (EINVAL); + error = kern_getfsstat(td, &uap->buf, uap->bufsize, &count, + UIO_USERSPACE, uap->mode); + if (error == 0) + td->td_retval[0] = count; + return (error); +} + #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_getfsstat(struct thread *td, @@ -323,6 +338,16 @@ freebsd4_freebsd32_getfsstat(struct thread *td, } #endif +#ifdef COMPAT_FREEBSD11 +int +freebsd11_freebsd32_getfsstat(struct thread *td, + struct freebsd11_freebsd32_getfsstat_args *uap) +{ + return(kern_freebsd11_getfsstat(td, uap->buf, uap->bufsize, + uap->mode)); +} +#endif + int freebsd32_sigaltstack(struct thread *td, struct freebsd32_sigaltstack_args *uap) diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h index ae3abe22dda4..50733c35d51b 100644 --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -709,6 +709,11 @@ struct freebsd32_fhstat_args { char u_fhp_l_[PADL_(const struct fhandle *)]; const struct fhandle * u_fhp; char u_fhp_r_[PADR_(const struct fhandle *)]; char sb_l_[PADL_(struct stat32 *)]; struct stat32 * sb; char sb_r_[PADR_(struct stat32 *)]; }; +struct freebsd32_getfsstat_args { + char buf_l_[PADL_(struct statfs *)]; struct statfs * buf; char buf_r_[PADR_(struct statfs *)]; + char bufsize_l_[PADL_(int32_t)]; int32_t bufsize; char bufsize_r_[PADR_(int32_t)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; +}; #ifdef PAD64_REQUIRED struct freebsd32_mknodat_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; @@ -912,6 +917,7 @@ int freebsd32_utimensat(struct thread *, struct freebsd32_utimensat_args *); int freebsd32_fstat(struct thread *, struct freebsd32_fstat_args *); int freebsd32_fstatat(struct thread *, struct freebsd32_fstatat_args *); int freebsd32_fhstat(struct thread *, struct freebsd32_fhstat_args *); +int freebsd32_getfsstat(struct thread *, struct freebsd32_getfsstat_args *); #ifdef PAD64_REQUIRED int freebsd32_mknodat(struct thread *, struct freebsd32_mknodat_args *); #else @@ -1317,6 +1323,11 @@ struct freebsd11_freebsd32_kevent_args { char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)]; char timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * timeout; char timeout_r_[PADR_(const struct timespec32 *)]; }; +struct freebsd11_freebsd32_getfsstat_args { + char buf_l_[PADL_(struct freebsd11_statfs *)]; struct freebsd11_statfs * buf; char buf_r_[PADR_(struct freebsd11_statfs *)]; + char bufsize_l_[PADL_(int32_t)]; int32_t bufsize; char bufsize_r_[PADR_(int32_t)]; + char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; +}; #ifdef PAD64_REQUIRED #else #endif @@ -1344,6 +1355,7 @@ int freebsd11_freebsd32_lstat(struct thread *, struct freebsd11_freebsd32_lstat_ int freebsd11_freebsd32_getdirentries(struct thread *, struct freebsd11_freebsd32_getdirentries_args *); int freebsd11_freebsd32_fhstat(struct thread *, struct freebsd11_freebsd32_fhstat_args *); int freebsd11_freebsd32_kevent(struct thread *, struct freebsd11_freebsd32_kevent_args *); +int freebsd11_freebsd32_getfsstat(struct thread *, struct freebsd11_freebsd32_getfsstat_args *); int freebsd11_freebsd32_fstatat(struct thread *, struct freebsd11_freebsd32_fstatat_args *); #endif /* COMPAT_FREEBSD11 */ @@ -1474,6 +1486,7 @@ int freebsd11_freebsd32_fstatat(struct thread *, struct freebsd11_freebsd32_fsta #define FREEBSD32_SYS_AUE_freebsd11_freebsd32_kevent AUE_KEVENT #define FREEBSD32_SYS_AUE_freebsd32_nmount AUE_NMOUNT #define FREEBSD32_SYS_AUE_freebsd32_sendfile AUE_SENDFILE +#define FREEBSD32_SYS_AUE_freebsd11_freebsd32_getfsstat AUE_GETFSSTAT #define FREEBSD32_SYS_AUE_freebsd32_ksem_init AUE_SEMINIT #define FREEBSD32_SYS_AUE_freebsd32_ksem_open AUE_SEMOPEN #define FREEBSD32_SYS_AUE_freebsd32_sigaction AUE_SIGACTION @@ -1538,6 +1551,7 @@ int freebsd11_freebsd32_fstatat(struct thread *, struct freebsd11_freebsd32_fsta #define FREEBSD32_SYS_AUE_freebsd32_fstat AUE_FSTAT #define FREEBSD32_SYS_AUE_freebsd32_fstatat AUE_FSTATAT #define FREEBSD32_SYS_AUE_freebsd32_fhstat AUE_FHSTAT +#define FREEBSD32_SYS_AUE_freebsd32_getfsstat AUE_GETFSSTAT #define FREEBSD32_SYS_AUE_freebsd32_mknodat AUE_MKNODAT #define FREEBSD32_SYS_AUE_freebsd32_mknodat AUE_MKNODAT #define FREEBSD32_SYS_AUE_freebsd32_kevent AUE_KEVENT diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index 05dfb299e332..4f4e8ac9caf6 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -329,7 +329,7 @@ #define FREEBSD32_SYS_lchflags 391 #define FREEBSD32_SYS_uuidgen 392 #define FREEBSD32_SYS_freebsd32_sendfile 393 -#define FREEBSD32_SYS_freebsd11_getfsstat 395 +#define FREEBSD32_SYS_freebsd11_freebsd32_getfsstat 395 #define FREEBSD32_SYS_freebsd11_statfs 396 #define FREEBSD32_SYS_freebsd11_fstatfs 397 #define FREEBSD32_SYS_freebsd11_fhstatfs 398 @@ -488,7 +488,7 @@ #define FREEBSD32_SYS_getdirentries 554 #define FREEBSD32_SYS_statfs 555 #define FREEBSD32_SYS_fstatfs 556 -#define FREEBSD32_SYS_getfsstat 557 +#define FREEBSD32_SYS_freebsd32_getfsstat 557 #define FREEBSD32_SYS_fhstatfs 558 #define FREEBSD32_SYS_freebsd32_mknodat 559 #define FREEBSD32_SYS_freebsd32_mknodat 559 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index 3206e069e85d..7af646c17e3e 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -409,7 +409,7 @@ const char *freebsd32_syscallnames[] = { "uuidgen", /* 392 = uuidgen */ "freebsd32_sendfile", /* 393 = freebsd32_sendfile */ "#394", /* 394 = mac_syscall */ - "compat11.getfsstat", /* 395 = freebsd11 getfsstat */ + "compat11.freebsd32_getfsstat", /* 395 = freebsd11 freebsd32_getfsstat */ "compat11.statfs", /* 396 = freebsd11 statfs */ "compat11.fstatfs", /* 397 = freebsd11 fstatfs */ "compat11.fhstatfs", /* 398 = freebsd11 fhstatfs */ @@ -594,7 +594,7 @@ const char *freebsd32_syscallnames[] = { "getdirentries", /* 554 = getdirentries */ "statfs", /* 555 = statfs */ "fstatfs", /* 556 = fstatfs */ - "getfsstat", /* 557 = getfsstat */ + "freebsd32_getfsstat", /* 557 = freebsd32_getfsstat */ "fhstatfs", /* 558 = fhstatfs */ #ifdef PAD64_REQUIRED "freebsd32_mknodat", /* 559 = freebsd32_mknodat */ diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 12fecbee75ab..1960cddc0542 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -462,7 +462,7 @@ struct sysent freebsd32_sysent[] = { { .sy_narg = AS(uuidgen_args), .sy_call = (sy_call_t *)sys_uuidgen, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 392 = uuidgen */ { .sy_narg = AS(freebsd32_sendfile_args), .sy_call = (sy_call_t *)freebsd32_sendfile, .sy_auevent = AUE_SENDFILE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 393 = freebsd32_sendfile */ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 394 = mac_syscall */ - { compat11(AS(freebsd11_getfsstat_args),getfsstat), .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 395 = freebsd11 getfsstat */ + { compat11(AS(freebsd11_freebsd32_getfsstat_args),freebsd32_getfsstat), .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 395 = freebsd11 freebsd32_getfsstat */ { compat11(AS(freebsd11_statfs_args),statfs), .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 396 = freebsd11 statfs */ { compat11(AS(freebsd11_fstatfs_args),fstatfs), .sy_auevent = AUE_FSTATFS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 397 = freebsd11 fstatfs */ { compat11(AS(freebsd11_fhstatfs_args),fhstatfs), .sy_auevent = AUE_FHSTATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 398 = freebsd11 fhstatfs */ @@ -647,7 +647,7 @@ struct sysent freebsd32_sysent[] = { { .sy_narg = AS(getdirentries_args), .sy_call = (sy_call_t *)sys_getdirentries, .sy_auevent = AUE_GETDIRENTRIES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 554 = getdirentries */ { .sy_narg = AS(statfs_args), .sy_call = (sy_call_t *)sys_statfs, .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 555 = statfs */ { .sy_narg = AS(fstatfs_args), .sy_call = (sy_call_t *)sys_fstatfs, .sy_auevent = AUE_FSTATFS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 556 = fstatfs */ - { .sy_narg = AS(getfsstat_args), .sy_call = (sy_call_t *)sys_getfsstat, .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 557 = getfsstat */ + { .sy_narg = AS(freebsd32_getfsstat_args), .sy_call = (sy_call_t *)freebsd32_getfsstat, .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 557 = freebsd32_getfsstat */ { .sy_narg = AS(fhstatfs_args), .sy_call = (sy_call_t *)sys_fhstatfs, .sy_auevent = AUE_FHSTATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 558 = fhstatfs */ #ifdef PAD64_REQUIRED { .sy_narg = AS(freebsd32_mknodat_args), .sy_call = (sy_call_t *)freebsd32_mknodat, .sy_auevent = AUE_MKNODAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 559 = freebsd32_mknodat */ diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index 6ba992bed5c9..6727bd8e5c76 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3207,9 +3207,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } - /* getfsstat */ + /* freebsd32_getfsstat */ case 557: { - struct getfsstat_args *p = params; + struct freebsd32_getfsstat_args *p = params; uarg[0] = (intptr_t)p->buf; /* struct statfs * */ iarg[1] = p->bufsize; /* int32_t */ iarg[2] = p->mode; /* int */ @@ -8858,7 +8858,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* getfsstat */ + /* freebsd32_getfsstat */ case 557: switch (ndx) { case 0: @@ -11149,7 +11149,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* getfsstat */ + /* freebsd32_getfsstat */ case 557: if (ndx == 0 || ndx == 1) p = "int"; diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 2bcf84d3baf7..3734219fba30 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -746,7 +746,7 @@ size_t nbytes, struct sf_hdtr32 *hdtr, \ off_t *sbytes, int flags); } 394 AUE_NULL UNIMPL mac_syscall -395 AUE_GETFSSTAT COMPAT11|NOPROTO { int getfsstat( \ +395 AUE_GETFSSTAT COMPAT11 { int freebsd32_getfsstat( \ struct freebsd11_statfs *buf, \ int32_t bufsize, int mode); } 396 AUE_STATFS COMPAT11|NOPROTO { int statfs(const char *path, \ @@ -1140,7 +1140,7 @@ 555 AUE_STATFS NOPROTO { int statfs(const char *path, \ struct statfs *buf); } 556 AUE_FSTATFS NOPROTO { int fstatfs(int fd, struct statfs *buf); } -557 AUE_GETFSSTAT NOPROTO { int getfsstat(struct statfs *buf, \ +557 AUE_GETFSSTAT STD { int freebsd32_getfsstat(struct statfs *buf, \ int32_t bufsize, int mode); } 558 AUE_FHSTATFS NOPROTO { int fhstatfs(const struct fhandle *u_fhp, \ struct statfs *buf); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 4357669786f8..1cffe903aef3 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -789,25 +789,34 @@ freebsd11_fstatfs(struct thread *td, struct freebsd11_fstatfs_args *uap) */ int freebsd11_getfsstat(struct thread *td, struct freebsd11_getfsstat_args *uap) +{ + return (kern_freebsd11_getfsstat(td, uap->buf, uap->bufsize, uap->mode)); +} + +int +kern_freebsd11_getfsstat(struct thread *td, struct freebsd11_statfs * ubuf, + long bufsize, int mode) { struct freebsd11_statfs osb; struct statfs *buf, *sp; size_t count, size; int error; - count = uap->bufsize / sizeof(struct ostatfs); + if (bufsize < 0) + return (EINVAL); + + count = bufsize / sizeof(struct ostatfs); size = count * sizeof(struct statfs); - error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, - uap->mode); + error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, mode); if (error == 0) td->td_retval[0] = count; if (size > 0) { sp = buf; while (count > 0 && error == 0) { freebsd11_cvtstatfs(sp, &osb); - error = copyout(&osb, uap->buf, sizeof(osb)); + error = copyout(&osb, ubuf, sizeof(osb)); sp++; - uap->buf++; + ubuf++; count--; } free(buf, M_STATFS); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 5032df4be874..24d2a199a272 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -145,6 +145,8 @@ int kern_fhopen(struct thread *td, const struct fhandle *u_fhp, int flags); 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_fpathconf(struct thread *td, int fd, int name, long *valuep); +int kern_freebsd11_getfsstat(struct thread *td, + struct freebsd11_statfs *ubuf, long bufsize, int mode); int kern_fstat(struct thread *td, int fd, struct stat *sbp); int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); int kern_fsync(struct thread *td, int fd, bool fullsync);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202111172022.1AHKMj4a060140>