Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F147974624
D18359.id51220.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D18359.id51220.diff
View Options
Index: lib/libc/sys/Makefile.inc
===================================================================
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -184,7 +184,9 @@
extattr_get_file.2 \
fcntl.2 \
ffclock.2 \
+ fhlink.2 \
fhopen.2 \
+ fhreadlink.2 \
flock.2 \
fork.2 \
fsync.2 \
@@ -395,7 +397,8 @@
MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.2
MLINKS+=fsync.2 fdatasync.2
MLINKS+=getdirentries.2 getdents.2
-MLINKS+=getfh.2 lgetfh.2
+MLINKS+=getfh.2 lgetfh.2 \
+ getfh.2 getfhat.2
MLINKS+=getgid.2 getegid.2
MLINKS+=getitimer.2 setitimer.2
MLINKS+=getlogin.2 getlogin_r.3
Index: lib/libc/sys/Symbol.map
===================================================================
--- lib/libc/sys/Symbol.map
+++ lib/libc/sys/Symbol.map
@@ -85,6 +85,9 @@
fchown;
fcntl;
fhopen;
+ fhlink;
+ fhlinkat;
+ fhreadlink;
flock;
fork;
fpathconf;
@@ -98,6 +101,7 @@
getegid;
geteuid;
getfh;
+ getfhat;
getgid;
getgroups;
getitimer;
@@ -568,6 +572,12 @@
__fcntl_compat;
_fhopen;
__sys_fhopen;
+ _fhlink;
+ __sys_fhlink;
+ _fhlinkat;
+ __sys_fhlinkat;
+ _fhreadlink;
+ __sys_fhreadlink;
_fhstat;
__sys_fhstat;
_fhstatfs;
@@ -606,6 +616,8 @@
__sys_geteuid;
_getfh;
__sys_getfh;
+ _getfhat;
+ __sys_getfhat;
_getfsstat;
__sys_getfsstat;
_getgid;
Index: lib/libc/sys/getfh.2
===================================================================
--- lib/libc/sys/getfh.2
+++ lib/libc/sys/getfh.2
@@ -28,12 +28,13 @@
.\" @(#)getfh.2 8.1 (Berkeley) 6/9/93
.\" $FreeBSD$
.\"
-.Dd April 14, 2011
+.Dd November 26, 2018
.Dt GETFH 2
.Os
.Sh NAME
.Nm getfh ,
-.Nm lgetfh
+.Nm lgetfh ,
+.Nm getfhat
.Nd get file handle
.Sh LIBRARY
.Lb libc
@@ -44,6 +45,8 @@
.Fn getfh "const char *path" "fhandle_t *fhp"
.Ft int
.Fn lgetfh "const char *path" "fhandle_t *fhp"
+.Ft int
+.Fn getfhat "int fd" "const char *path" "fhandle_t *fhp" "int flag"
.Sh DESCRIPTION
The
.Fn getfh
@@ -51,6 +54,7 @@
returns a file handle for the specified file or directory
in the file handle pointed to by
.Fa fhp .
+.Pp
The
.Fn lgetfh
system call is like
@@ -62,6 +66,85 @@
while
.Fn getfh
returns information about the file the link references.
+.Pp
+The
+.Fn getfhat
+system call is equivalent to
+.Fn getfh
+and
+.Fn lgetfh
+except when the
+.Fa path
+specifies a relative path, or the
+.Dv AT_BENEATH
+flag is provided.
+For
+.Fn getfhat
+and relative
+.Fa path ,
+the status is retrieved from a file relative to
+the directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+For
+.Dv AT_BENEATH
+and absolute
+.Fa path ,
+the status is retrieved from a file specified by the
+.Fa path ,
+but additional permission checks are performed, see below.
+.Pp
+The values for the
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from this list,
+defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, the status of the symbolic link is returned.
+.It Dv AT_BENEATH
+Only stat files and directories below the topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.El
+.Pp
+If
+.Fn getfhat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn getfth
+or
+.Fn lgetfh
+respectively, depending on whether or not the
+.Dv AT_SYMLINK_NOFOLLOW
+bit is set in
+.Fa flag .
+.Pp
+When
+.Fn getfhat
+is called with an absolute
+.Fa path
+without the
+.Dv AT_BENEATH
+flag, it ignores the
+.Fa fd
+argument.
+When
+.Dv AT_BENEATH
+is specified with an absolute
+.Fa path ,
+a directory passed by the
+.Fa fd
+argument is used as the topping point for the resolution.
These system calls are restricted to the superuser.
.Sh RETURN VALUES
.Rv -std
@@ -104,6 +187,35 @@
.Tn I/O
error occurred while reading from or writing to the file system.
.El
+.Pp
+In addition to the errors returned by
+.Fn getfh ,
+and
+.Fn lgetfh ,
+the
+.Fn getfhat
+system call may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument, is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
.Sh SEE ALSO
.Xr fhopen 2 ,
.Xr open 2 ,
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ sys/compat/freebsd32/syscalls.master
@@ -1138,5 +1138,12 @@
int policy); }
563 AUE_NULL NOPROTO { int getrandom(void *buf, size_t buflen, \
unsigned int flags); }
+564 AUE_NULL NOPROTO { int getfhat( int fd, _In_ char *path, \
+ _Out_ struct fhandle *fhp, int flags); }
+565 AUE_NULL NOPROTO { int fhlink( struct fhandle *fhp, const char *to ); }
+566 AUE_NULL NOPROTO { int fhlinkat( struct fhandle *fhp, int tofd, \
+ const char *to, int flags,); }
+567 AUE_NULL NOPROTO { int fhreadlink( struct fhandle *fhp, char *buf, \
+ size_t bufsize); }
; vim: syntax=off
Index: sys/kern/capabilities.conf
===================================================================
--- sys/kern/capabilities.conf
+++ sys/kern/capabilities.conf
@@ -469,6 +469,7 @@
symlinkat
unlinkat
utimensat
+getfhat
##
## Process descriptor-related system calls are allowed.
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -3139,6 +3139,35 @@
unsigned int flags
);
}
+564 AUE_NULL STD {
+ int getfhat(
+ int fd,
+ _In_ char *path,
+ _Out_ struct fhandle *fhp,
+ int flags
+ );
+ }
+565 AUE_NULL STD {
+ int fhlink(
+ struct fhandle *fhp,
+ const char *to
+ );
+ }
+566 AUE_NULL STD {
+ int fhlinkat(
+ struct fhandle *fhp,
+ int tofd,
+ const char *to,
+ int flags,
+ );
+ }
+567 AUE_NULL STD {
+ int fhreadlink(
+ struct fhandle *fhp,
+ char *buf,
+ size_t bufsize
+ );
+ }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c
+++ sys/kern/vfs_syscalls.c
@@ -4128,41 +4128,226 @@
int
sys_lgetfh(struct thread *td, struct lgetfh_args *uap)
{
+ int error = kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname,
+ UIO_USERSPACE, uap->fhp);
+ return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct getfh_args {
+ char *fname;
+ fhandle_t *fhp;
+};
+#endif
+int
+sys_getfh(struct thread *td, struct getfh_args *uap)
+{
+ int error = kern_getfhat(td, 0, AT_FDCWD, uap->fname,
+ UIO_USERSPACE, uap->fhp);
+ return (error);
+}
+
+/*
+ * syscall for the rpc.lockd to use to translate an open descriptor into
+ * a NFS file handle.
+ *
+ * warning: do not remove the priv_check() call or this becomes one giant
+ * security hole.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct getfhat_args {
+ int fd;
+ char *path;
+ fhandle_t *fhp;
+ int flags;
+};
+#endif
+int
+sys_getfhat(struct thread *td, struct getfhat_args *uap)
+{
+ if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ return (EINVAL);
+ return (kern_getfhat(td, uap->flags, uap->fd, uap->path,
+ UIO_USERSPACE, uap->fhp));
+}
+
+int
+kern_getfhat(struct thread *td, int flags, int fd, const char *path,
+ enum uio_seg pathseg, fhandle_t *fhp)
+{
struct nameidata nd;
fhandle_t fh;
struct vnode *vp;
+ cap_rights_t rights;
int error;
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
- NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
- uap->fname, td);
- error = namei(&nd);
- if (error != 0)
- return (error);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vp = nd.ni_vp;
+
+ if (path) {
+ NDINIT_AT(&nd, LOOKUP, (flags & AT_SYMLINK_NOFOLLOW ? NOFOLLOW : FOLLOW)
+ | (flags & AT_BENEATH ? BENEATH : 0)
+ | LOCKLEAF | AUDITVNODE1,
+ pathseg, path, fd, td);
+
+ error = namei(&nd);
+ if (error != 0)
+ return (error);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vp = nd.ni_vp;
+ }
+ else {
+ error = fgetvp(td, fd, cap_rights_init(&rights, CAP_PREAD), &vp);
+ if (error != 0)
+ return (error);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ }
+
bzero(&fh, sizeof(fh));
fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
error = VOP_VPTOFH(vp, &fh.fh_fid);
vput(vp);
if (error == 0)
- error = copyout(&fh, uap->fhp, sizeof (fh));
+ error = copyout(&fh, fhp, sizeof (fh));
return (error);
}
#ifndef _SYS_SYSPROTO_H_
-struct getfh_args {
- char *fname;
- fhandle_t *fhp;
+struct fhlink_args {
+ fhandle_t *fhp;
+ int tofd;
+ const char *to;
};
#endif
+int sys_fhlink(struct thread *td, struct fhlink_args *uap)
+{
+ return (kern_fhlinkat(td, AT_FDCWD, uap->to, UIO_USERSPACE, uap->fhp, 0));
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct fhlinkat_args {
+ fhandle_t *fhp;
+ int tofd;
+ const char *to;
+ int flags;
+};
+#endif
+int sys_fhlinkat(struct thread *td, struct fhlinkat_args *uap)
+{
+ if ((uap->flags & ~(AT_SYMLINK_FOLLOW | AT_BENEATH)) != 0)
+ return (EINVAL);
+ return (kern_fhlinkat(td, uap->flags, uap->to, UIO_USERSPACE, uap->fhp,
+ uap->flags));
+}
+
+int kern_fhlinkat(struct thread *td, int fd, const char *path,
+ enum uio_seg pathseg, fhandle_t *fhp, int flags)
+{
+ fhandle_t fh;
+ struct mount *mp;
+ struct vnode *vp;
+ struct nameidata nd;
+ int error;
+
+ error = priv_check(td, PRIV_VFS_GETFH);
+ if (error != 0)
+ return (error);
+
+ error = copyin(fhp, &fh, sizeof(fh));
+ if (error != 0)
+ return (error);
+
+again:
+ bwillwrite();
+ if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
+ return (ESTALE);
+
+ error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp);
+ vfs_unbusy(mp);
+ if (error != 0)
+ return (error);
+
+ /* code taken from kern_linkat */
+ if (vp->v_type == VDIR) {
+ vput(vp);
+ return (EPERM); /* POSIX */
+ }
+
+ /* reuse the same target rights capability as linkat() */
+ NDINIT_ATRIGHTS(&nd, CREATE, (flags & AT_SYMLINK_NOFOLLOW ? NOFOLLOW : FOLLOW)
+ | (flags & AT_BENEATH ? BENEATH : 0)
+ | LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE,
+ pathseg, path, fd, &cap_linkat_target_rights, td);
+
+ if ((error = namei(&nd)) == 0) {
+ if (nd.ni_vp != NULL) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ vput(vp);
+ return (EEXIST);
+ } else if (nd.ni_dvp->v_mount != vp->v_mount) {
+ /*
+ * Cross-device link. No need to recheck
+ * vp->v_type, since it cannot change, except
+ * to VBAD.
+ */
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vput(nd.ni_dvp);
+ vput(vp);
+ return (EXDEV);
+ } else {
+ error = can_hardlink(vp, td->td_ucred);
+#ifdef MAC
+ if (error == 0)
+ error = mac_vnode_check_link(td->td_ucred,
+ nd.ni_dvp, vp, &nd.ni_cnd);
+#endif
+ if (error != 0) {
+ vput(vp);
+ vput(nd.ni_dvp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ return (error);
+ }
+ error = vn_start_write(vp, &mp, V_NOWAIT);
+ if (error != 0) {
+ vput(vp);
+ vput(nd.ni_dvp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ error = vn_start_write(NULL, &mp,
+ V_XSLEEP | PCATCH);
+ if (error != 0)
+ return (error);
+ goto again;
+ }
+ error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+ vput(nd.ni_dvp);
+ vn_finished_write(mp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ }
+ }
+ vput(vp);
+ return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct fhreadlink_args {
+ fhandle_t *fhp;
+ char *buf;
+ size_t bufsize;
+};
+#endif
int
-sys_getfh(struct thread *td, struct getfh_args *uap)
+sys_fhreadlink(struct thread *td, struct fhreadlink_args *uap)
{
- struct nameidata nd;
fhandle_t fh;
+ struct iovec aiov;
+ struct uio auio;
+ struct mount *mp;
struct vnode *vp;
int error;
@@ -4169,19 +4354,46 @@
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
- uap->fname, td);
- error = namei(&nd);
+
+ if (uap->bufsize > IOSIZE_MAX)
+ return (EINVAL);
+
+ error = copyin(uap->fhp, &fh, sizeof(fh))
if (error != 0)
return (error);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vp = nd.ni_vp;
- bzero(&fh, sizeof(fh));
- fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
- error = VOP_VPTOFH(vp, &fh.fh_fid);
+
+ if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
+ return (ESTALE);
+
+ error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp);
+ vfs_unbusy(mp);
+ if (error != 0)
+ return (error);
+
+#ifdef MAC
+ error = mac_vnode_check_readlink(td->td_ucred, vp);
+ if (error != 0) {
+ vput(vp);
+ return (error);
+ }
+#endif
+
+ if (vp->v_type != VLNK && (vp->v_vflag & VV_READLINK) == 0)
+ error = EINVAL;
+ else {
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->bufsize;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = 0;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_td = td;
+ auio.uio_resid = uap->bufsize;
+ error = VOP_READLINK(vp, &auio, td->td_ucred);
+ td->td_retval[0] = uap->bufsize - auio.uio_resid;
+ }
vput(vp);
- if (error == 0)
- error = copyout(&fh, uap->fhp, sizeof (fh));
return (error);
}
Index: sys/sys/mount.h
===================================================================
--- sys/sys/mount.h
+++ sys/sys/mount.h
@@ -932,11 +932,15 @@
struct stat;
__BEGIN_DECLS
+int fhlink(struct fhandle *, const char *);
+int fhlinkat(struct fhandle *, int, const char *, int);
int fhopen(const struct fhandle *, int);
+int fhreadlink(struct fhandle *, char *, size_t);
int fhstat(const struct fhandle *, struct stat *);
int fhstatfs(const struct fhandle *, struct statfs *);
int fstatfs(int, struct statfs *);
int getfh(const char *, fhandle_t *);
+int getfhat(int, char *, struct fhandle *, int);
int getfsstat(struct statfs *, long, int);
int getmntinfo(struct statfs **, int);
int lgetfh(const char *, fhandle_t *);
Index: sys/sys/syscallsubr.h
===================================================================
--- sys/sys/syscallsubr.h
+++ sys/sys/syscallsubr.h
@@ -118,6 +118,8 @@
enum uio_seg pathseg, int uid, int gid, int flag);
int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg);
int kern_fcntl_freebsd(struct thread *td, int fd, int cmd, long arg);
+int kern_fhlinkat(struct thread *td, int fd, const char *path,
+ enum uio_seg pathseg, fhandle_t *fhp, int flags);
int kern_fhstat(struct thread *td, fhandle_t fh, struct stat *buf);
int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf);
int kern_fpathconf(struct thread *td, int fd, int name, long *valuep);
@@ -131,6 +133,8 @@
enum uio_seg tptrseg);
int kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
off_t *basep, ssize_t *residp, enum uio_seg bufseg);
+int kern_getfhat(struct thread *td, int flag, int fd, const char *path,
+ enum uio_seg pathseg, fhandle_t *fhp);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
size_t *countp, enum uio_seg bufseg, int mode);
int kern_getitimer(struct thread *, u_int, struct itimerval *);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 15, 11:25 PM (12 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29725568
Default Alt Text
D18359.id51220.diff (15 KB)
Attached To
Mode
D18359: getfhat, fhlink, fhlinkat, fhreadlink: new file handle system calls
Attached
Detach File
Event Timeline
Log In to Comment