Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142457728
D18359.id51280.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D18359.id51280.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;
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, char *path, \
+ 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_z_ char *path,
+ _Out_ struct fhandle *fhp,
+ int flags
+ );
+ }
+565 AUE_NULL STD {
+ int fhlink(
+ _In_ struct fhandle *fhp,
+ _In_z_ const char *to
+ );
+ }
+566 AUE_NULL STD {
+ int fhlinkat(
+ _In_ struct fhandle *fhp,
+ int tofd,
+ _In_z_ const char *to,
+ int flags,
+ );
+ }
+567 AUE_NULL STD {
+ int fhreadlink(
+ _In_ struct fhandle *fhp,
+ _Out_writes_(bufsize) 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
@@ -105,6 +105,10 @@
const struct timespec *, int, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
struct thread *td);
+static int kern_fhlinkat(struct thread *td, int fd, const char *path,
+ enum uio_seg pathseg, fhandle_t *fhp, int flags);
+static int kern_getfhat(struct thread *td, int flags, int fd,
+ const char *path, enum uio_seg pathseg, fhandle_t *fhp);
/*
* Sync each mounted filesystem.
@@ -4121,67 +4125,278 @@
*/
#ifndef _SYS_SYSPROTO_H_
struct lgetfh_args {
- char *fname;
+ char *fname;
fhandle_t *fhp;
};
#endif
int
sys_lgetfh(struct thread *td, struct lgetfh_args *uap)
{
+ return (kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname,
+ UIO_USERSPACE, uap->fhp));
+}
+
+#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));
+}
+
+static 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;
+struct fhlink_args {
fhandle_t *fhp;
+ int tofd;
+ const char *to;
};
#endif
int
-sys_getfh(struct thread *td, struct getfh_args *uap)
+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));
+}
+
+static 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_fhreadlink(struct thread *td, struct fhreadlink_args *uap)
+{
fhandle_t fh;
+ struct iovec aiov;
+ struct uio auio;
+ struct mount *mp;
struct vnode *vp;
int error;
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 *);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jan 21, 4:22 AM (8 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27789434
Default Alt Text
D18359.id51280.diff (14 KB)
Attached To
Mode
D18359: getfhat, fhlink, fhlinkat, fhreadlink: new file handle system calls
Attached
Detach File
Event Timeline
Log In to Comment