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);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to