mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-17 13:53:39 +00:00
Don't make Linux stat() open character devices to resolve its name.
The existing code calls kern_open() to resolve the vnode of a pathname right after a stat(). This is not correct, because it causes random character devices to be opened in /dev. This means ls'ing a tape streamer will cause it to rewind, for example. Changes I have made: - Add kern_statat_vnhook() to allow binary emulators to `post-process' struct stat, using the proper vnode. - Remove unneeded printf's from stat() and statfs(). - Make the Linuxolator use kern_statat_vnhook(), replacing translate_path_major_minor_at(). - Let translate_fd_major_minor() use vp->v_rdev instead of vp->v_un.vu_cdev. Result: crw-rw-rw- 1 root root 0, 14 Feb 20 13:54 /dev/ptmx crw--w---- 1 root adm 136, 0 Feb 20 14:03 /dev/pts/0 crw--w---- 1 root adm 136, 1 Feb 20 14:02 /dev/pts/1 crw--w---- 1 ed tty 136, 2 Feb 20 14:03 /dev/pts/2 Before this commit, ptmx also had a major number of 136, because it silently allocated and deallocated a pseudo-terminal. Device nodes that cannot be opened now have proper major/minor-numbers. Reviewed by: kib, netchild, rdivacky (thanks!)
This commit is contained in:
parent
3d919b7521
commit
0eee862a54
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=188849
|
@ -62,6 +62,44 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
static void
|
||||
translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
|
||||
{
|
||||
int major, minor;
|
||||
|
||||
if (vp->v_type == VCHR && vp->v_rdev != NULL &&
|
||||
linux_driver_get_major_minor(vp->v_rdev->si_name,
|
||||
&major, &minor) == 0) {
|
||||
sb->st_rdev = (major << 8 | minor);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
linux_kern_statat(struct thread *td, int flag, int fd, char *path,
|
||||
enum uio_seg pathseg, struct stat *sbp)
|
||||
{
|
||||
|
||||
return (kern_statat_vnhook(td, flag, fd, path, pathseg, sbp,
|
||||
translate_vnhook_major_minor));
|
||||
}
|
||||
|
||||
static int
|
||||
linux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
struct stat *sbp)
|
||||
{
|
||||
|
||||
return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
|
||||
}
|
||||
|
||||
static int
|
||||
linux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
struct stat *sbp)
|
||||
{
|
||||
|
||||
return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
|
||||
pathseg, sbp));
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: This was removed from newstat_copyout(), and almost identical
|
||||
* XXX: code was in stat64_copyout(). findcdev() needs to be replaced
|
||||
|
@ -102,14 +140,15 @@ static void
|
|||
translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
|
||||
{
|
||||
struct file *fp;
|
||||
struct vnode *vp;
|
||||
int major, minor;
|
||||
|
||||
if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
|
||||
fget(td, fd, &fp) != 0)
|
||||
return;
|
||||
if (fp->f_vnode != NULL &&
|
||||
fp->f_vnode->v_un.vu_cdev != NULL &&
|
||||
linux_driver_get_major_minor(fp->f_vnode->v_un.vu_cdev->si_name,
|
||||
vp = fp->f_vnode;
|
||||
if (vp != NULL && vp->v_rdev != NULL &&
|
||||
linux_driver_get_major_minor(vp->v_rdev->si_name,
|
||||
&major, &minor) == 0) {
|
||||
buf->st_rdev = (major << 8 | minor);
|
||||
} else if (fp->f_type == DTYPE_PTS) {
|
||||
|
@ -124,32 +163,6 @@ translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
|
|||
fdrop(fp, td);
|
||||
}
|
||||
|
||||
static void
|
||||
translate_path_major_minor_at(struct thread *td, char *path,
|
||||
struct stat *buf, int dfd)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct filedesc *fdp = p->p_fd;
|
||||
int fd;
|
||||
int temp;
|
||||
|
||||
if (!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode))
|
||||
return;
|
||||
temp = td->td_retval[0];
|
||||
if (kern_openat(td, dfd, path, UIO_SYSSPACE, O_RDONLY, 0) != 0)
|
||||
return;
|
||||
fd = td->td_retval[0];
|
||||
td->td_retval[0] = temp;
|
||||
translate_fd_major_minor(td, fd, buf);
|
||||
fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
|
||||
}
|
||||
|
||||
static inline void
|
||||
translate_path_major_minor(struct thread *td, char *path, struct stat *buf)
|
||||
{
|
||||
translate_path_major_minor_at(td, path, buf, AT_FDCWD);
|
||||
}
|
||||
|
||||
static int
|
||||
newstat_copyout(struct stat *buf, void *ubuf)
|
||||
{
|
||||
|
@ -187,9 +200,7 @@ linux_newstat(struct thread *td, struct linux_newstat_args *args)
|
|||
printf(ARGS(newstat, "%s, *"), path);
|
||||
#endif
|
||||
|
||||
error = kern_stat(td, path, UIO_SYSSPACE, &buf);
|
||||
if (!error)
|
||||
translate_path_major_minor(td, path, &buf);
|
||||
error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
|
||||
LFREEPATH(path);
|
||||
if (error)
|
||||
return (error);
|
||||
|
@ -210,9 +221,7 @@ linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
|
|||
printf(ARGS(newlstat, "%s, *"), path);
|
||||
#endif
|
||||
|
||||
error = kern_lstat(td, path, UIO_SYSSPACE, &sb);
|
||||
if (!error)
|
||||
translate_path_major_minor(td, path, &sb);
|
||||
error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
|
||||
LFREEPATH(path);
|
||||
if (error)
|
||||
return (error);
|
||||
|
@ -279,12 +288,11 @@ linux_stat(struct thread *td, struct linux_stat_args *args)
|
|||
if (ldebug(stat))
|
||||
printf(ARGS(stat, "%s, *"), path);
|
||||
#endif
|
||||
error = kern_stat(td, path, UIO_SYSSPACE, &buf);
|
||||
error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
|
||||
if (error) {
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
translate_path_major_minor(td, path, &buf);
|
||||
LFREEPATH(path);
|
||||
return(stat_copyout(&buf, args->up));
|
||||
}
|
||||
|
@ -302,12 +310,11 @@ linux_lstat(struct thread *td, struct linux_lstat_args *args)
|
|||
if (ldebug(lstat))
|
||||
printf(ARGS(lstat, "%s, *"), path);
|
||||
#endif
|
||||
error = kern_lstat(td, path, UIO_SYSSPACE, &buf);
|
||||
error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
|
||||
if (error) {
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
translate_path_major_minor(td, path, &buf);
|
||||
LFREEPATH(path);
|
||||
return(stat_copyout(&buf, args->up));
|
||||
}
|
||||
|
@ -526,9 +533,7 @@ linux_stat64(struct thread *td, struct linux_stat64_args *args)
|
|||
printf(ARGS(stat64, "%s, *"), filename);
|
||||
#endif
|
||||
|
||||
error = kern_stat(td, filename, UIO_SYSSPACE, &buf);
|
||||
if (!error)
|
||||
translate_path_major_minor(td, filename, &buf);
|
||||
error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
|
||||
LFREEPATH(filename);
|
||||
if (error)
|
||||
return (error);
|
||||
|
@ -549,9 +554,7 @@ linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
|
|||
printf(ARGS(lstat64, "%s, *"), args->filename);
|
||||
#endif
|
||||
|
||||
error = kern_lstat(td, filename, UIO_SYSSPACE, &sb);
|
||||
if (!error)
|
||||
translate_path_major_minor(td, filename, &sb);
|
||||
error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
|
||||
LFREEPATH(filename);
|
||||
if (error)
|
||||
return (error);
|
||||
|
@ -597,8 +600,7 @@ linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
|
|||
printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
|
||||
#endif
|
||||
|
||||
error = kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
|
||||
translate_path_major_minor_at(td, args->pathname, &buf, dfd);
|
||||
error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
|
||||
if (!error)
|
||||
error = stat64_copyout(&buf, args->statbuf);
|
||||
LFREEPATH(path);
|
||||
|
|
|
@ -339,8 +339,6 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
|||
out:
|
||||
vfs_unbusy(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
if (mtx_owned(&Giant))
|
||||
printf("statfs(%d): %s: %d\n", vfslocked, path, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -2343,6 +2341,15 @@ int
|
|||
kern_statat(struct thread *td, int flag, int fd, char *path,
|
||||
enum uio_seg pathseg, struct stat *sbp)
|
||||
{
|
||||
|
||||
return (kern_statat_vnhook(td, flag, fd, path, pathseg, sbp, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
kern_statat_vnhook(struct thread *td, int flag, int fd, char *path,
|
||||
enum uio_seg pathseg, struct stat *sbp,
|
||||
void (*hook)(struct vnode *vp, struct stat *sbp))
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct stat sb;
|
||||
int error, vfslocked;
|
||||
|
@ -2362,12 +2369,12 @@ kern_statat(struct thread *td, int flag, int fd, char *path,
|
|||
SDT_PROBE(vfs, , stat, mode, path, sb.st_mode, 0, 0, 0);
|
||||
if (S_ISREG(sb.st_mode))
|
||||
SDT_PROBE(vfs, , stat, reg, path, pathseg, 0, 0, 0);
|
||||
if (__predict_false(hook != NULL))
|
||||
hook(nd.ni_vp, &sb);
|
||||
}
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vput(nd.ni_vp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
if (mtx_owned(&Giant))
|
||||
printf("stat(%d): %s\n", vfslocked, path);
|
||||
if (error)
|
||||
return (error);
|
||||
*sbp = sb;
|
||||
|
|
|
@ -193,6 +193,9 @@ int kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
|
|||
struct stat *sbp);
|
||||
int kern_statat(struct thread *td, int flag, int fd, char *path,
|
||||
enum uio_seg pathseg, struct stat *sbp);
|
||||
int kern_statat_vnhook(struct thread *td, int flag, int fd, char *path,
|
||||
enum uio_seg pathseg, struct stat *sbp,
|
||||
void (*hook)(struct vnode *vp, struct stat *sbp));
|
||||
int kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
struct statfs *buf);
|
||||
int kern_symlink(struct thread *td, char *path, char *link,
|
||||
|
|
Loading…
Reference in a new issue