From 6eefabd4ca40348f0bc0ab829bceb3a308e577b7 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Mon, 22 Nov 2021 22:36:56 +0000 Subject: [PATCH] syscalls: improve nstat, nfstat, nlstat Optionally return errors when truncating dev_t, ino_t, and nlink_t. In the interest of code reuse, use freebsd11_cvtstat() to perform the truncation and error handling and then convert the resulting struct freebsd11_stat to struct nstat. Add missing freebsd32 compat syscalls. These syscalls require translation because struct nstat contains four instances of struct timespec which in turn contains a time_t and a long. Reviewed by: kib --- sys/compat/freebsd32/freebsd32.h | 25 ++++++++ sys/compat/freebsd32/freebsd32_misc.c | 87 +++++++++++++++++++++++++++ sys/compat/freebsd32/syscalls.master | 10 +-- sys/kern/kern_descrip.c | 7 ++- sys/kern/vfs_syscalls.c | 56 ++++++++++------- sys/sys/vnode.h | 2 +- 6 files changed, 157 insertions(+), 30 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h index e5bb253aef78..4d5cea688a21 100644 --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -167,6 +167,31 @@ struct ostatfs32 { int32_t f_spare[2]; }; +struct nstat32 { + __uint32_t st_dev; /* inode's device */ + __uint32_t st_ino; /* inode's number */ + __uint32_t st_mode; /* inode protection mode */ + __uint32_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of the file's owner */ + gid_t st_gid; /* group ID of the file's group */ + __uint32_t st_rdev; /* device type */ + struct timespec32 st_atim; /* time of last access */ + struct timespec32 st_mtim; /* time of last data modification */ + struct timespec32 st_ctim; /* time of last file status change */ + off_t st_size; /* file size, in bytes */ + blkcnt_t st_blocks; /* blocks allocated for file */ + blksize_t st_blksize; /* optimal blocksize for I/O */ + fflags_t st_flags; /* user defined flags for file */ + __uint32_t st_gen; /* file generation number */ + struct timespec32 st_birthtim; /* time of file creation */ + /* + * See comment in the definition of struct freebsd11_stat + * in sys/stat.h about the following padding. + */ + unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32)); + unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32)); +}; + struct iovec32 { u_int32_t iov_base; int iov_len; diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 69ae3a1cd85d..e81148d3577c 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -2473,6 +2473,93 @@ freebsd11_freebsd32_fhstat(struct thread *td, error = copyout(&sb32, uap->sb, sizeof (sb32)); return (error); } + +static int +freebsd11_cvtnstat32(struct stat *sb, struct nstat32 *nsb32) +{ + struct nstat nsb; + int error; + + error = freebsd11_cvtnstat(sb, &nsb); + if (error != 0) + return (error); + + bzero(nsb32, sizeof(*nsb32)); + CP(nsb, *nsb32, st_dev); + CP(nsb, *nsb32, st_ino); + CP(nsb, *nsb32, st_mode); + CP(nsb, *nsb32, st_nlink); + CP(nsb, *nsb32, st_uid); + CP(nsb, *nsb32, st_gid); + CP(nsb, *nsb32, st_rdev); + CP(nsb, *nsb32, st_atim.tv_sec); + CP(nsb, *nsb32, st_atim.tv_nsec); + CP(nsb, *nsb32, st_mtim.tv_sec); + CP(nsb, *nsb32, st_mtim.tv_nsec); + CP(nsb, *nsb32, st_ctim.tv_sec); + CP(nsb, *nsb32, st_ctim.tv_nsec); + CP(nsb, *nsb32, st_size); + CP(nsb, *nsb32, st_blocks); + CP(nsb, *nsb32, st_blksize); + CP(nsb, *nsb32, st_flags); + CP(nsb, *nsb32, st_gen); + CP(nsb, *nsb32, st_birthtim.tv_sec); + CP(nsb, *nsb32, st_birthtim.tv_nsec); + return (0); +} + +int +freebsd11_freebsd32_nstat(struct thread *td, + struct freebsd11_freebsd32_nstat_args *uap) +{ + struct stat sb; + struct nstat32 nsb; + int error; + + error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, + &sb, NULL); + if (error != 0) + return (error); + error = freebsd11_cvtnstat32(&sb, &nsb); + if (error != 0) + error = copyout(&nsb, uap->ub, sizeof (nsb)); + return (error); +} + +int +freebsd11_freebsd32_nlstat(struct thread *td, + struct freebsd11_freebsd32_nlstat_args *uap) +{ + struct stat sb; + struct nstat32 nsb; + int error; + + error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, + UIO_USERSPACE, &sb, NULL); + if (error != 0) + return (error); + error = freebsd11_cvtnstat32(&sb, &nsb); + if (error == 0) + error = copyout(&nsb, uap->ub, sizeof (nsb)); + return (error); +} + +int +freebsd11_freebsd32_nfstat(struct thread *td, + struct freebsd11_freebsd32_nfstat_args *uap) +{ + struct nstat32 nub; + struct stat ub; + int error; + + error = kern_fstat(td, uap->fd, &ub); + if (error != 0) + return (error); + error = freebsd11_cvtnstat32(&ub, &nub); + if (error == 0) + error = copyout(&nub, uap->sb, sizeof(nub)); + return (error); +} #endif int diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 2e11fdb03a17..4fd7b2235d99 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -525,11 +525,11 @@ 276 AUE_LUTIMES STD { int freebsd32_lutimes(const char *path, \ const struct timeval32 *tptr); } 277 AUE_NULL OBSOL netbsd_msync -278 AUE_STAT COMPAT11|NOPROTO { int nstat(const char *path, \ - struct nstat *ub); } -279 AUE_FSTAT COMPAT11|NOPROTO { int nfstat(int fd, struct nstat *sb); } -280 AUE_LSTAT COMPAT11|NOPROTO { int nlstat(const char *path, \ - struct nstat *ub); } +278 AUE_STAT COMPAT11 { int freebsd32_nstat(const char *path, \ + struct nstat32 *ub); } +279 AUE_FSTAT COMPAT11 { int freebsd32_nfstat(int fd, struct nstat32 *sb); } +280 AUE_LSTAT COMPAT11 { int freebsd32_nlstat(const char *path, \ + struct nstat32 *ub); } 281 AUE_NULL RESERVED 282 AUE_NULL RESERVED 283 AUE_NULL RESERVED diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 37d978e96de5..37fec097dcfc 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1561,10 +1561,11 @@ freebsd11_nfstat(struct thread *td, struct freebsd11_nfstat_args *uap) int error; error = kern_fstat(td, uap->fd, &ub); - if (error == 0) { - freebsd11_cvtnstat(&ub, &nub); + if (error != 0) + return (error); + error = freebsd11_cvtnstat(&ub, &nub); + if (error != 0) error = copyout(&nub, uap->sb, sizeof(nub)); - } return (error); } #endif /* COMPAT_FREEBSD11 */ diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 1cffe903aef3..4391853337bd 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -44,6 +44,9 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef COMPAT_FREEBSD11 +#include +#endif #include #include #include @@ -2475,27 +2478,34 @@ kern_statat(struct thread *td, int flag, int fd, const char *path, /* * Implementation of the NetBSD [l]stat() functions. */ -void +int freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb) { + struct freebsd11_stat sb11; + int error; + + error = freebsd11_cvtstat(sb, &sb11); + if (error != 0) + return (error); bzero(nsb, sizeof(*nsb)); - nsb->st_dev = sb->st_dev; - nsb->st_ino = sb->st_ino; - nsb->st_mode = sb->st_mode; - nsb->st_nlink = sb->st_nlink; - nsb->st_uid = sb->st_uid; - nsb->st_gid = sb->st_gid; - nsb->st_rdev = sb->st_rdev; - nsb->st_atim = sb->st_atim; - nsb->st_mtim = sb->st_mtim; - nsb->st_ctim = sb->st_ctim; - nsb->st_size = sb->st_size; - nsb->st_blocks = sb->st_blocks; - nsb->st_blksize = sb->st_blksize; - nsb->st_flags = sb->st_flags; - nsb->st_gen = sb->st_gen; - nsb->st_birthtim = sb->st_birthtim; + CP(sb11, *nsb, st_dev); + CP(sb11, *nsb, st_ino); + CP(sb11, *nsb, st_mode); + CP(sb11, *nsb, st_nlink); + CP(sb11, *nsb, st_uid); + CP(sb11, *nsb, st_gid); + CP(sb11, *nsb, st_rdev); + CP(sb11, *nsb, st_atim); + CP(sb11, *nsb, st_mtim); + CP(sb11, *nsb, st_ctim); + CP(sb11, *nsb, st_size); + CP(sb11, *nsb, st_blocks); + CP(sb11, *nsb, st_blksize); + CP(sb11, *nsb, st_flags); + CP(sb11, *nsb, st_gen); + CP(sb11, *nsb, st_birthtim); + return (0); } #ifndef _SYS_SYSPROTO_H_ @@ -2515,8 +2525,10 @@ freebsd11_nstat(struct thread *td, struct freebsd11_nstat_args *uap) &sb, NULL); if (error != 0) return (error); - freebsd11_cvtnstat(&sb, &nsb); - return (copyout(&nsb, uap->ub, sizeof (nsb))); + error = freebsd11_cvtnstat(&sb, &nsb); + if (error == 0) + error = copyout(&nsb, uap->ub, sizeof (nsb)); + return (error); } /* @@ -2539,8 +2551,10 @@ freebsd11_nlstat(struct thread *td, struct freebsd11_nlstat_args *uap) UIO_USERSPACE, &sb, NULL); if (error != 0) return (error); - freebsd11_cvtnstat(&sb, &nsb); - return (copyout(&nsb, uap->ub, sizeof (nsb))); + error = freebsd11_cvtnstat(&sb, &nsb); + if (error == 0) + error = copyout(&nsb, uap->ub, sizeof (nsb)); + return (error); } #endif /* COMPAT_FREEBSD11 */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 1a202abfd4dd..3d04b6f68784 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -682,7 +682,7 @@ cache_validate(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) void cache_fast_lookup_enabled_recalc(void); 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); +int freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb); 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);