aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrooks Davis <brooks@FreeBSD.org>2021-11-17 20:12:26 +0000
committerBrooks Davis <brooks@FreeBSD.org>2021-11-17 20:12:26 +0000
commit2b9d052d3eeb9ffd1094dc5165eff555b9fd6bc3 (patch)
tree7c61c5dc05d623057eec248f8e5817e3998da544
parentf19e3fd20601f0ff7fa3261fee339b46276b3d90 (diff)
downloadsrc-2b9d052d3eeb9ffd1094dc5165eff555b9fd6bc3.tar.gz
src-2b9d052d3eeb9ffd1094dc5165eff555b9fd6bc3.zip
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
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c25
-rw-r--r--sys/compat/freebsd32/freebsd32_proto.h14
-rw-r--r--sys/compat/freebsd32/freebsd32_syscall.h4
-rw-r--r--sys/compat/freebsd32/freebsd32_syscalls.c4
-rw-r--r--sys/compat/freebsd32/freebsd32_sysent.c4
-rw-r--r--sys/compat/freebsd32/freebsd32_systrace_args.c8
-rw-r--r--sys/compat/freebsd32/syscalls.master4
-rw-r--r--sys/kern/vfs_syscalls.c19
-rw-r--r--sys/sys/syscallsubr.h2
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
@@ -790,24 +790,33 @@ 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);