diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index d73f95f3d071..99eb94357a1f 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1904,12 +1904,18 @@ freebsd32_fhstat(struct thread *td, struct freebsd32_fhstat_args *uap) } #if defined(COMPAT_FREEBSD11) -static void +extern int ino64_trunc_error; + +static int freebsd11_cvtstat32(struct stat *in, struct freebsd11_stat32 *out) { CP(*in, *out, st_ino); + if (in->st_ino != out->st_ino && ino64_trunc_error) + return (EOVERFLOW); CP(*in, *out, st_nlink); + if (in->st_nlink != out->st_nlink && ino64_trunc_error) + return (EOVERFLOW); CP(*in, *out, st_dev); CP(*in, *out, st_mode); CP(*in, *out, st_uid); @@ -1928,6 +1934,7 @@ freebsd11_cvtstat32(struct stat *in, struct freebsd11_stat32 *out) bzero((char *)&out->st_birthtim + sizeof(out->st_birthtim), sizeof(*out) - offsetof(struct freebsd11_stat32, st_birthtim) - sizeof(out->st_birthtim)); + return (0); } int @@ -1942,8 +1949,9 @@ freebsd11_freebsd32_stat(struct thread *td, &sb, NULL); if (error != 0) return (error); - freebsd11_cvtstat32(&sb, &sb32); - error = copyout(&sb32, uap->ub, sizeof (sb32)); + error = freebsd11_cvtstat32(&sb, &sb32); + if (error == 0) + error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } @@ -1958,8 +1966,9 @@ freebsd11_freebsd32_fstat(struct thread *td, error = kern_fstat(td, uap->fd, &sb); if (error != 0) return (error); - freebsd11_cvtstat32(&sb, &sb32); - error = copyout(&sb32, uap->ub, sizeof (sb32)); + error = freebsd11_cvtstat32(&sb, &sb32); + if (error == 0) + error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } @@ -1975,8 +1984,9 @@ freebsd11_freebsd32_fstatat(struct thread *td, &sb, NULL); if (error != 0) return (error); - freebsd11_cvtstat32(&sb, &sb32); - error = copyout(&sb32, uap->buf, sizeof (sb32)); + error = freebsd11_cvtstat32(&sb, &sb32); + if (error == 0) + error = copyout(&sb32, uap->buf, sizeof (sb32)); return (error); } @@ -1990,10 +2000,11 @@ freebsd11_freebsd32_lstat(struct thread *td, error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, UIO_USERSPACE, &sb, NULL); - if (error) + if (error != 0) return (error); - freebsd11_cvtstat32(&sb, &sb32); - error = copyout(&sb32, uap->ub, sizeof (sb32)); + error = freebsd11_cvtstat32(&sb, &sb32); + if (error == 0) + error = copyout(&sb32, uap->ub, sizeof (sb32)); return (error); } @@ -2012,8 +2023,9 @@ freebsd11_freebsd32_fhstat(struct thread *td, error = kern_fhstat(td, fh, &sb); if (error != 0) return (error); - freebsd11_cvtstat32(&sb, &sb32); - error = copyout(&sb32, uap->sb, sizeof (sb32)); + error = freebsd11_cvtstat32(&sb, &sb32); + if (error == 0) + error = copyout(&sb32, uap->sb, sizeof (sb32)); return (error); } #endif diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 2baaff77666b..6ad01c07ad9a 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1315,8 +1315,9 @@ freebsd11_fstat(struct thread *td, struct freebsd11_fstat_args *uap) error = kern_fstat(td, uap->fd, &sb); if (error != 0) return (error); - freebsd11_cvtstat(&sb, &osb); - error = copyout(&osb, uap->sb, sizeof(osb)); + error = freebsd11_cvtstat(&sb, &osb); + if (error == 0) + error = copyout(&osb, uap->sb, sizeof(osb)); return (error); } #endif /* COMPAT_FREEBSD11 */ diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 27b2635030d3..3aa67ad9142a 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -2107,14 +2107,22 @@ cvtstat(struct stat *st, struct ostat *ost) #endif /* COMPAT_43 */ #if defined(COMPAT_FREEBSD11) -void +int ino64_trunc_error; +SYSCTL_INT(_vfs, OID_AUTO, ino64_trunc_error, CTLFLAG_RW, + &ino64_trunc_error, 0, + "Error on truncation of inode number, device id or link count"); +int freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost) { ost->st_dev = st->st_dev; - ost->st_ino = st->st_ino; /* truncate */ + ost->st_ino = st->st_ino; + if (ost->st_ino != st->st_ino && ino64_trunc_error) + return (EOVERFLOW); ost->st_mode = st->st_mode; - ost->st_nlink = st->st_nlink; /* truncate */ + ost->st_nlink = st->st_nlink; + if (ost->st_nlink != st->st_nlink && ino64_trunc_error) + return (EOVERFLOW); ost->st_uid = st->st_uid; ost->st_gid = st->st_gid; ost->st_rdev = st->st_rdev; @@ -2131,6 +2139,7 @@ freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost) bzero((char *)&ost->st_birthtim + sizeof(ost->st_birthtim), sizeof(*ost) - offsetof(struct freebsd11_stat, st_birthtim) - sizeof(ost->st_birthtim)); + return (0); } int @@ -2144,8 +2153,9 @@ freebsd11_stat(struct thread *td, struct freebsd11_stat_args* uap) &sb, NULL); if (error != 0) return (error); - freebsd11_cvtstat(&sb, &osb); - error = copyout(&osb, uap->ub, sizeof(osb)); + error = freebsd11_cvtstat(&sb, &osb); + if (error == 0) + error = copyout(&osb, uap->ub, sizeof(osb)); return (error); } @@ -2160,8 +2170,9 @@ freebsd11_lstat(struct thread *td, struct freebsd11_lstat_args* uap) UIO_USERSPACE, &sb, NULL); if (error != 0) return (error); - freebsd11_cvtstat(&sb, &osb); - error = copyout(&osb, uap->ub, sizeof(osb)); + error = freebsd11_cvtstat(&sb, &osb); + if (error == 0) + error = copyout(&osb, uap->ub, sizeof(osb)); return (error); } @@ -2179,8 +2190,9 @@ freebsd11_fhstat(struct thread *td, struct freebsd11_fhstat_args* uap) error = kern_fhstat(td, fh, &sb); if (error != 0) return (error); - freebsd11_cvtstat(&sb, &osb); - error = copyout(&osb, uap->sb, sizeof(osb)); + error = freebsd11_cvtstat(&sb, &osb); + if (error == 0) + error = copyout(&osb, uap->sb, sizeof(osb)); return (error); } @@ -2195,8 +2207,9 @@ freebsd11_fstatat(struct thread *td, struct freebsd11_fstatat_args* uap) UIO_USERSPACE, &sb, NULL); if (error != 0) return (error); - freebsd11_cvtstat(&sb, &osb); - error = copyout(&osb, uap->buf, sizeof(osb)); + error = freebsd11_cvtstat(&sb, &osb); + if (error == 0) + error = copyout(&osb, uap->buf, sizeof(osb)); return (error); } #endif /* COMPAT_FREEBSD11 */ @@ -3738,6 +3751,8 @@ freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count, dstdp.d_type = dp->d_type; dstdp.d_namlen = dp->d_namlen; dstdp.d_fileno = dp->d_fileno; /* truncate */ + if (dstdp.d_fileno != dp->d_fileno && ino64_trunc_error) + continue; dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) + ((dp->d_namlen + 1 + 3) &~ 3); bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen); diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 7738341ae438..9cd350ed70cb 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -610,7 +610,7 @@ void cache_purgevfs(struct mount *mp, bool force); int change_dir(struct vnode *vp, struct thread *td); void cvtstat(struct stat *st, struct ostat *ost); void freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb); -void freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost); +int freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost); int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp); void getnewvnode_reserve(u_int count);