Index: sys/compat/linux/linux_stats.c =================================================================== --- sys/compat/linux/linux_stats.c +++ sys/compat/linux/linux_stats.c @@ -59,6 +59,13 @@ #include #include +static void +symlink_perm_hook(struct vnode *vp, struct stat *sb) +{ + if ((vp->v_vflag & VV_READLINK) == 0) + sb->st_mode |= ACCESSPERMS; +} + static void translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) { @@ -84,13 +91,23 @@ sb->st_rdev = (major << 8 | minor); } +static void +lstat_vnhook(struct vnode *vp, struct stat *sb) +{ + if (vp->v_type == VLNK) + symlink_perm_hook(vp, sb); + else + translate_vnhook_major_minor(vp, sb); +} + static int linux_kern_statat(struct thread *td, int flag, int fd, const char *path, enum uio_seg pathseg, struct stat *sbp) { return (kern_statat(td, flag, fd, path, pathseg, sbp, - translate_vnhook_major_minor)); + (flag & AT_SYMLINK_NOFOLLOW) ? lstat_vnhook : + translate_vnhook_major_minor)); } #ifdef LINUX_LEGACY_SYSCALLS Index: sys/fs/fdescfs/fdesc_vnops.c =================================================================== --- sys/fs/fdescfs/fdesc_vnops.c +++ sys/fs/fdescfs/fdesc_vnops.c @@ -432,6 +432,8 @@ struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct timeval boottime; + struct file *fp; + int fd; getboottime(&boottime); vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; @@ -457,7 +459,20 @@ break; case Fdesc: - vap->va_type = (vp->v_vflag & VV_READLINK) == 0 ? VCHR : VLNK; + if ((vp->v_vflag & VV_READLINK) != 0) { + vap->va_type = VLNK; + fd = VTOFDESC(vp)->fd_fd; + if (fget(curthread, fd, &cap_no_rights, &fp) == 0) { + vap->va_mode = 0; + if (fp->f_flag & FREAD) + vap->va_mode |= (S_IRUSR | S_IXUSR); + if (fp->f_flag & FWRITE) + vap->va_mode |= (S_IWUSR | S_IXUSR); + fdrop(fp, curthread); + } + } else { + vap->va_type = VCHR; + } vap->va_nlink = 1; vap->va_size = 0; vap->va_rdev = makedev(0, vap->va_fileid);