Date: Mon, 5 Jun 2017 11:40:30 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r319600 - in head/sys: compat/freebsd32 kern sys Message-ID: <201706051140.v55BeUft067555@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Mon Jun 5 11:40:30 2017 New Revision: 319600 URL: https://svnweb.freebsd.org/changeset/base/319600 Log: Add sysctl vfs.ino64_trunc_error controlling action on truncating inode number or link count for the ABI compat binaries. Right now, and by default after the change, too large 64bit values are silently truncated to 32 bits. Enabling the knob causes the system to return EOVERFLOW for stat(2) family of compat syscalls when some values cannot be completely represented by the old structures. For getdirentries(2), knob skips the dirents which would cause non-trivial truncation of d_ino. EOVERFLOW error is specified by the X/Open 1996 LFS document ('Adding Support for Arbitrary File Sizes to the Single UNIX Specification'). Based on the discussion with: bde Sponsored by: The FreeBSD Foundation Modified: head/sys/compat/freebsd32/freebsd32_misc.c head/sys/kern/kern_descrip.c head/sys/kern/vfs_syscalls.c head/sys/sys/vnode.h Modified: head/sys/compat/freebsd32/freebsd32_misc.c ============================================================================== --- head/sys/compat/freebsd32/freebsd32_misc.c Mon Jun 5 11:11:07 2017 (r319599) +++ head/sys/compat/freebsd32/freebsd32_misc.c Mon Jun 5 11:40:30 2017 (r319600) @@ -1904,12 +1904,18 @@ freebsd32_fhstat(struct thread *td, struct freebsd32_f } #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_ 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 Modified: head/sys/kern/kern_descrip.c ============================================================================== --- head/sys/kern/kern_descrip.c Mon Jun 5 11:11:07 2017 (r319599) +++ head/sys/kern/kern_descrip.c Mon Jun 5 11:40:30 2017 (r319600) @@ -1315,8 +1315,9 @@ freebsd11_fstat(struct thread *td, struct freebsd11_fs 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 */ Modified: head/sys/kern/vfs_syscalls.c ============================================================================== --- head/sys/kern/vfs_syscalls.c Mon Jun 5 11:11:07 2017 (r319599) +++ head/sys/kern/vfs_syscalls.c Mon Jun 5 11:40:30 2017 (r319600) @@ -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_st 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_sta &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_ls 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_f 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_ 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 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); Modified: head/sys/sys/vnode.h ============================================================================== --- head/sys/sys/vnode.h Mon Jun 5 11:11:07 2017 (r319599) +++ head/sys/sys/vnode.h Mon Jun 5 11:40:30 2017 (r319600) @@ -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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201706051140.v55BeUft067555>