Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 25 Oct 2018 22:16:34 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r339748 - in head: lib/libc/sys sys/cddl/compat/opensolaris/sys sys/compat/cloudabi sys/compat/linux sys/kern sys/sys sys/ufs/ffs
Message-ID:  <201810252216.w9PMGYNw086754@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Thu Oct 25 22:16:34 2018
New Revision: 339748
URL: https://svnweb.freebsd.org/changeset/base/339748

Log:
  Implement O_BENEATH and AT_BENEATH.
  
  Flags prevent open(2) and *at(2) vfs syscalls name lookup from
  escaping the starting directory.  Supposedly the interface is similar
  to the same proposed Linux flags.
  
  Reviewed by:	jilles (code, previous version of manpages), 0mp (manpages)
  Discussed with:	allanjude, emaste, jonathan
  Sponsored by:	The FreeBSD Foundation
  Differential revision:	https://reviews.freebsd.org/D17547

Modified:
  head/lib/libc/sys/access.2
  head/lib/libc/sys/chflags.2
  head/lib/libc/sys/chmod.2
  head/lib/libc/sys/chown.2
  head/lib/libc/sys/link.2
  head/lib/libc/sys/open.2
  head/lib/libc/sys/stat.2
  head/lib/libc/sys/unlink.2
  head/lib/libc/sys/utimensat.2
  head/sys/cddl/compat/opensolaris/sys/vnode.h
  head/sys/compat/cloudabi/cloudabi_file.c
  head/sys/compat/linux/linux_file.c
  head/sys/kern/vfs_lookup.c
  head/sys/kern/vfs_mountroot.c
  head/sys/kern/vfs_syscalls.c
  head/sys/kern/vfs_vnops.c
  head/sys/sys/fcntl.h
  head/sys/sys/namei.h
  head/sys/sys/syscallsubr.h
  head/sys/ufs/ffs/ffs_alloc.c

Modified: head/lib/libc/sys/access.2
==============================================================================
--- head/lib/libc/sys/access.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/access.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)access.2	8.2 (Berkeley) 4/1/94
 .\" $FreeBSD$
 .\"
-.Dd September 15, 2014
+.Dd October 20, 2018
 .Dt ACCESS 2
 .Os
 .Sh NAME
@@ -120,6 +120,8 @@ list, defined in
 The checks for accessibility are performed using the effective user and group
 IDs instead of the real user and group ID as required in a call to
 .Fn access .
+.It Dv AT_BENEATH
+Only operate on files and directories below the starting directory.
 .El
 .Pp
 Even if a process's real or effective user has appropriate privileges
@@ -195,6 +197,15 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr chmod 2 ,

Modified: head/lib/libc/sys/chflags.2
==============================================================================
--- head/lib/libc/sys/chflags.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/chflags.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"	@(#)chflags.2	8.3 (Berkeley) 5/2/95
 .\" $FreeBSD$
 .\"
-.Dd March 22, 2013
+.Dd October 20, 2018
 .Dt CHFLAGS 2
 .Os
 .Sh NAME
@@ -94,6 +94,9 @@ defined in
 If
 .Fa path
 names a symbolic link, then the flags of the symbolic link are changed.
+.It Dv AT_BENEATH
+Only allow to change flags for a file which is beneath of
+the starting directory.
 .El
 .Pp
 If
@@ -302,6 +305,15 @@ error occurred while reading from or writing to the fi
 The underlying file system does not support file flags, or
 does not support all of the flags set in
 .Fa flags .
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr chflags 1 ,

Modified: head/lib/libc/sys/chmod.2
==============================================================================
--- head/lib/libc/sys/chmod.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/chmod.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)chmod.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd December 1, 2017
+.Dd October 20, 2018
 .Dt CHMOD 2
 .Os
 .Sh NAME
@@ -101,6 +101,9 @@ in
 If
 .Fa path
 names a symbolic link, then the mode of the symbolic link is changed.
+.It Dv AT_BENEATH
+Only allow to change permissions of a file which is beneath of
+the starting directory.
 .El
 .Pp
 If
@@ -285,6 +288,15 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr chmod 1 ,

Modified: head/lib/libc/sys/chown.2
==============================================================================
--- head/lib/libc/sys/chown.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/chown.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)chown.2	8.4 (Berkeley) 4/19/94
 .\" $FreeBSD$
 .\"
-.Dd December 1, 2017
+.Dd Octover 20, 2018
 .Dt CHOWN 2
 .Os
 .Sh NAME
@@ -118,6 +118,9 @@ list, defined in
 If
 .Fa path
 names a symbolic link, ownership of the symbolic link is changed.
+.It Dv AT_BENEATH
+Only allow to change ownership of a file which is beneath of
+the starting directory.
 .El
 .Pp
 If
@@ -227,6 +230,15 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr chgrp 1 ,

Modified: head/lib/libc/sys/link.2
==============================================================================
--- head/lib/libc/sys/link.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/link.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)link.2	8.3 (Berkeley) 1/12/94
 .\" $FreeBSD$
 .\"
-.Dd December 1, 2017
+.Dd October 20, 2018
 .Dt LINK 2
 .Os
 .Sh NAME
@@ -115,6 +115,8 @@ If
 .Fa name1
 names a symbolic link, a new link for the target of the symbolic link is
 created.
+.It Dv AT_BENEATH
+Only allow to link to a file which is beneath of the starting directory.
 .El
 .Pp
 If
@@ -257,6 +259,17 @@ or
 respectively, is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa name1
+is not strictly relative to the starting directory.
+For example,
+.Fa name1
+is absolute or includes a ".." component that escapes the starting directory.
+.Dv AT_BENEATH
+flag was specified.
 .El
 .Sh SEE ALSO
 .Xr chflags 2 ,

Modified: head/lib/libc/sys/open.2
==============================================================================
--- head/lib/libc/sys/open.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/open.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)open.2	8.2 (Berkeley) 11/16/93
 .\" $FreeBSD$
 .\"
-.Dd December 1, 2017
+.Dd October 20, 2018
 .Dt OPEN 2
 .Os
 .Sh NAME
@@ -142,6 +142,7 @@ O_TTY_INIT	ignored
 O_DIRECTORY	error if file is not a directory
 O_CLOEXEC	set FD_CLOEXEC upon open
 O_VERIFY	verify the contents of the file
+O_BENEATH	require path to be strictly relative to starting directory
 .Ed
 .Pp
 Opening a file with
@@ -269,6 +270,23 @@ means is implementation specific.
 The run-time linker (rtld) uses this flag to ensure shared objects have
 been verified before operating on them.
 .Pp
+.Dv O_BENEATH
+returns
+.Er ENOTCAPABLE
+if the specified path, after resolving all symlinks and ".." references
+in it, does not reside in the directory hierarchy of children beneath
+the starting directory, or is an absolute path.
+Starting directory is the process current directory if relative
+.Fa path
+is used for
+.Fn open ,
+and the directory referenced by the
+.Fa fd
+argument when specifying relative
+.Fa path
+for
+.Fn openat .
+.Pp
 If successful,
 .Fn open
 returns a non-negative integer, termed a file descriptor.
@@ -487,9 +505,13 @@ is specified and the process is in capability mode.
 was called and the process is in capability mode.
 .It Bq Er ENOTCAPABLE
 .Fa path
-is an absolute path or contained a ".." component leading to a
+is an absolute path,
+or contained a ".." component leading to a
 directory outside of the directory hierarchy specified by
-.Fa fd .
+.Fa fd ,
+and the process is in capability mode or the
+.Dv O_BENEATH
+flag was provided.
 .El
 .Sh SEE ALSO
 .Xr chmod 2 ,

Modified: head/lib/libc/sys/stat.2
==============================================================================
--- head/lib/libc/sys/stat.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/stat.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)stat.2	8.4 (Berkeley) 5/1/95
 .\" $FreeBSD$
 .\"
-.Dd December 1, 2017
+.Dd October 20, 2018
 .Dt STAT 2
 .Os
 .Sh NAME
@@ -100,6 +100,13 @@ defined in
 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 starting directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -397,6 +404,15 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr access 2 ,

Modified: head/lib/libc/sys/unlink.2
==============================================================================
--- head/lib/libc/sys/unlink.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/unlink.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -28,7 +28,7 @@
 .\"     @(#)unlink.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd December 1, 2017
+.Dd October 20, 2018
 .Dt UNLINK 2
 .Os
 .Sh NAME
@@ -89,6 +89,9 @@ Remove the directory entry specified by
 and
 .Fa path
 as a directory, not a normal file.
+.It Dv AT_BENEATH
+Only unlink files and directories which are beneath of the starting
+directory.
 .El
 .Pp
 If
@@ -200,6 +203,15 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr chflags 2 ,

Modified: head/lib/libc/sys/utimensat.2
==============================================================================
--- head/lib/libc/sys/utimensat.2	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/lib/libc/sys/utimensat.2	Thu Oct 25 22:16:34 2018	(r339748)
@@ -31,7 +31,7 @@
 .\"     @(#)utimes.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd June 7, 2017
+.Dd October 20, 2018
 .Dt UTIMENSAT 2
 .Os
 .Sh NAME
@@ -146,6 +146,9 @@ names a symbolic link, the symbolic link's times are c
 By default,
 .Fn utimensat
 changes the times of the file referenced by the symbolic link.
+.It Dv AT_BENEATH
+Only allow to change the times of a file which is beneath of
+the starting directory.
 .El
 .Sh RETURN VALUES
 .Rv -std
@@ -267,6 +270,15 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was specified but
+.Fa path
+is not strictly relative to the starting directory.
+For example,
+.Fa path
+is absolute or includes a ".." component that escapes the starting directory.
 .El
 .Sh SEE ALSO
 .Xr chflags 2 ,

Modified: head/sys/cddl/compat/opensolaris/sys/vnode.h
==============================================================================
--- head/sys/cddl/compat/opensolaris/sys/vnode.h	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/cddl/compat/opensolaris/sys/vnode.h	Thu Oct 25 22:16:34 2018	(r339748)
@@ -278,7 +278,7 @@ vn_remove(char *fnamep, enum uio_seg seg, enum rm dirf
 	ASSERT(seg == UIO_SYSSPACE);
 	ASSERT(dirflag == RMFILE);
 
-	return (kern_unlinkat(curthread, AT_FDCWD, fnamep, seg, 0));
+	return (kern_unlinkat(curthread, AT_FDCWD, fnamep, seg, 0, 0));
 }
 
 #endif	/* _KERNEL */

Modified: head/sys/compat/cloudabi/cloudabi_file.c
==============================================================================
--- head/sys/compat/cloudabi/cloudabi_file.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/compat/cloudabi/cloudabi_file.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -752,9 +752,9 @@ cloudabi_sys_file_unlink(struct thread *td,
 		return (error);
 
 	if (uap->flags & CLOUDABI_UNLINK_REMOVEDIR)
-		error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
+		error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE, 0);
 	else
-		error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
+		error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0, 0);
 	cloudabi_freestr(path);
 	return (error);
 }

Modified: head/sys/compat/linux/linux_file.c
==============================================================================
--- head/sys/compat/linux/linux_file.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/compat/linux/linux_file.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -590,7 +590,7 @@ linux_unlink(struct thread *td, struct linux_unlink_ar
 		printf(ARGS(unlink, "%s"), path);
 #endif
 
-	error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
+	error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 0);
 	if (error == EPERM) {
 		/* Introduce POSIX noncompliant behaviour of Linux */
 		if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
@@ -623,9 +623,9 @@ linux_unlinkat(struct thread *td, struct linux_unlinka
 #endif
 
 	if (args->flag & LINUX_AT_REMOVEDIR)
-		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
+		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE, 0);
 	else
-		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
+		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0, 0);
 	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
 		/* Introduce POSIX noncompliant behaviour of Linux */
 		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
@@ -741,7 +741,7 @@ linux_rmdir(struct thread *td, struct linux_rmdir_args
 	if (ldebug(rmdir))
 		printf(ARGS(rmdir, "%s"), path);
 #endif
-	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
+	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
 	LFREEPATH(path);
 	return (error);
 }

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/kern/vfs_lookup.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -242,7 +242,8 @@ namei_handle_root(struct nameidata *ndp, struct vnode 
 	struct componentname *cnp;
 
 	cnp = &ndp->ni_cnd;
-	if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0) {
+	if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 ||
+	    (cnp->cn_flags & BENEATH) != 0) {
 #ifdef KTRACE
 		if (KTRPOINT(curthread, KTR_CAPFAIL))
 			ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
@@ -434,8 +435,10 @@ namei(struct nameidata *ndp)
 			vrele(dp);
 		goto out;
 	}
-	if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 &&
-	    lookup_cap_dotdot != 0)
+	if (((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 &&
+	    lookup_cap_dotdot != 0) ||
+	    ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0 &&
+	    (cnp->cn_flags & BENEATH) != 0))
 		ndp->ni_lcf |= NI_LCF_CAP_DOTDOT;
 	SDT_PROBE3(vfs, namei, lookup, entry, dp, cnp->cn_pnbuf,
 	    cnp->cn_flags);

Modified: head/sys/kern/vfs_mountroot.c
==============================================================================
--- head/sys/kern/vfs_mountroot.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/kern/vfs_mountroot.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -389,7 +389,7 @@ vfs_mountroot_shuffle(struct thread *td, struct mount 
 		vfs_unbusy(mpdevfs);
 		/* Unlink the no longer needed /dev/dev -> / symlink */
 		error = kern_unlinkat(td, AT_FDCWD, "/dev/dev",
-		    UIO_SYSSPACE, 0);
+		    UIO_SYSSPACE, 0, 0);
 		if (error)
 			printf("mountroot: unable to unlink /dev/dev "
 			    "(error %d)\n", error);

Modified: head/sys/kern/vfs_syscalls.c
==============================================================================
--- head/sys/kern/vfs_syscalls.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/kern/vfs_syscalls.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -1443,11 +1443,12 @@ sys_linkat(struct thread *td, struct linkat_args *uap)
 	int flag;
 
 	flag = uap->flag;
-	if (flag & ~AT_SYMLINK_FOLLOW)
+	if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH)) != 0)
 		return (EINVAL);
 
 	return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2,
-	    UIO_USERSPACE, (flag & AT_SYMLINK_FOLLOW) ? FOLLOW : NOFOLLOW));
+	    UIO_USERSPACE, ((flag & AT_SYMLINK_FOLLOW) != 0 ? FOLLOW :
+	    NOFOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0)));
 }
 
 int hardlink_check_uid = 0;
@@ -1731,7 +1732,7 @@ int
 sys_unlink(struct thread *td, struct unlink_args *uap)
 {
 
-	return (kern_unlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0));
+	return (kern_unlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0, 0));
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -1744,22 +1745,25 @@ struct unlinkat_args {
 int
 sys_unlinkat(struct thread *td, struct unlinkat_args *uap)
 {
-	int flag = uap->flag;
-	int fd = uap->fd;
-	char *path = uap->path;
+	int fd, flag;
+	char *path;
 
-	if (flag & ~AT_REMOVEDIR)
+	flag = uap->flag;
+	fd = uap->fd;
+	path = uap->path;
+
+	if ((flag & ~(AT_REMOVEDIR | AT_BENEATH)) != 0)
 		return (EINVAL);
 
-	if (flag & AT_REMOVEDIR)
-		return (kern_rmdirat(td, fd, path, UIO_USERSPACE));
+	if ((uap->flag & AT_REMOVEDIR) != 0)
+		return (kern_rmdirat(td, fd, path, UIO_USERSPACE, flag));
 	else
-		return (kern_unlinkat(td, fd, path, UIO_USERSPACE, 0));
+		return (kern_unlinkat(td, fd, path, UIO_USERSPACE, flag, 0));
 }
 
 int
 kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
-    ino_t oldinum)
+    int flag, ino_t oldinum)
 {
 	struct mount *mp;
 	struct vnode *vp;
@@ -1769,7 +1773,8 @@ kern_unlinkat(struct thread *td, int fd, char *path, e
 
 restart:
 	bwillwrite();
-	NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1,
+	NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
+	    ((flag & AT_BENEATH) != 0 ? BENEATH : 0),
 	    pathseg, path, fd, &cap_unlinkat_rights, td);
 	if ((error = namei(&nd)) != 0)
 		return (error == EINVAL ? EPERM : error);
@@ -1960,7 +1965,7 @@ kern_accessat(struct thread *td, int fd, char *path, e
 	struct nameidata nd;
 	int error;
 
-	if (flag & ~AT_EACCESS)
+	if ((flag & ~(AT_EACCESS | AT_BENEATH)) != 0)
 		return (EINVAL);
 	if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0)
 		return (EINVAL);
@@ -1981,8 +1986,8 @@ kern_accessat(struct thread *td, int fd, char *path, e
 		usecred = cred;
 	AUDIT_ARG_VALUE(amode);
 	NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF |
-	    AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights,
-	    td);
+	    AUDITVNODE1 | ((flag & AT_BENEATH) != 0 ? BENEATH : 0),
+	    pathseg, path, fd, &cap_fstat_rights, td);
 	if ((error = namei(&nd)) != 0)
 		goto out;
 	vp = nd.ni_vp;
@@ -2273,11 +2278,12 @@ kern_statat(struct thread *td, int flag, int fd, char 
 	struct stat sb;
 	int error;
 
-	if (flag & ~AT_SYMLINK_NOFOLLOW)
+	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
 		return (EINVAL);
 
-	NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
-	    FOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd,
+	NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) != 0 ?
+	    NOFOLLOW : FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) |
+	    LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd,
 	    &cap_fstat_rights, td);
 
 	if ((error = namei(&nd)) != 0)
@@ -2588,15 +2594,12 @@ struct chflagsat_args {
 int
 sys_chflagsat(struct thread *td, struct chflagsat_args *uap)
 {
-	int fd = uap->fd;
-	const char *path = uap->path;
-	u_long flags = uap->flags;
-	int atflag = uap->atflag;
 
-	if (atflag & ~AT_SYMLINK_NOFOLLOW)
+	if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
 		return (EINVAL);
 
-	return (kern_chflagsat(td, fd, path, UIO_USERSPACE, flags, atflag));
+	return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE,
+	    uap->flags, uap->atflag));
 }
 
 /*
@@ -2625,6 +2628,7 @@ kern_chflagsat(struct thread *td, int fd, const char *
 
 	AUDIT_ARG_FFLAGS(flags);
 	follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+	follow |= (atflag & AT_BENEATH) != 0 ? BENEATH : 0;
 	NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
 	    &cap_fchflags_rights, td);
 	if ((error = namei(&nd)) != 0)
@@ -2719,15 +2723,12 @@ struct fchmodat_args {
 int
 sys_fchmodat(struct thread *td, struct fchmodat_args *uap)
 {
-	int flag = uap->flag;
-	int fd = uap->fd;
-	char *path = uap->path;
-	mode_t mode = uap->mode;
 
-	if (flag & ~AT_SYMLINK_NOFOLLOW)
+	if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
 		return (EINVAL);
 
-	return (kern_fchmodat(td, fd, path, UIO_USERSPACE, mode, flag));
+	return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE,
+	    uap->mode, uap->flag));
 }
 
 /*
@@ -2755,7 +2756,8 @@ kern_fchmodat(struct thread *td, int fd, char *path, e
 	int error, follow;
 
 	AUDIT_ARG_MODE(mode);
-	follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+	follow = (flag & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : FOLLOW;
+	follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0;
 	NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
 	    &cap_fchmod_rights, td);
 	if ((error = namei(&nd)) != 0)
@@ -2850,10 +2852,8 @@ struct fchownat_args {
 int
 sys_fchownat(struct thread *td, struct fchownat_args *uap)
 {
-	int flag;
 
-	flag = uap->flag;
-	if (flag & ~AT_SYMLINK_NOFOLLOW)
+	if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
 		return (EINVAL);
 
 	return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid,
@@ -2869,6 +2869,7 @@ kern_fchownat(struct thread *td, int fd, char *path, e
 
 	AUDIT_ARG_OWNER(uid, gid);
 	follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+	follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0;
 	NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
 	    &cap_fchown_rights, td);
 
@@ -3220,14 +3221,14 @@ kern_utimensat(struct thread *td, int fd, char *path, 
 	struct timespec ts[2];
 	int error, flags;
 
-	if (flag & ~AT_SYMLINK_NOFOLLOW)
+	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
 		return (EINVAL);
 
 	if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0)
 		return (error);
 	NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
-	    FOLLOW) | AUDITVNODE1, pathseg, path, fd,
-	    &cap_futimes_rights, td);
+	    FOLLOW) |  ((flag & AT_BENEATH) != 0 ? BENEATH : 0) | AUDITVNODE1,
+	    pathseg, path, fd, &cap_futimes_rights, td);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	/*
@@ -3671,11 +3672,12 @@ int
 sys_rmdir(struct thread *td, struct rmdir_args *uap)
 {
 
-	return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE));
+	return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0));
 }
 
 int
-kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg)
+kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
+    int flag)
 {
 	struct mount *mp;
 	struct vnode *vp;
@@ -3684,7 +3686,8 @@ kern_rmdirat(struct thread *td, int fd, char *path, en
 
 restart:
 	bwillwrite();
-	NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1,
+	NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
+	    ((flag & AT_BENEATH) != 0 ? BENEATH : 0),
 	    pathseg, path, fd, &cap_unlinkat_rights, td);
 	if ((error = namei(&nd)) != 0)
 		return (error);

Modified: head/sys/kern/vfs_vnops.c
==============================================================================
--- head/sys/kern/vfs_vnops.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/kern/vfs_vnops.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -212,6 +212,8 @@ restart:
 		ndp->ni_cnd.cn_flags = ISOPEN | LOCKPARENT | LOCKLEAF | NOCACHE;
 		if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
 			ndp->ni_cnd.cn_flags |= FOLLOW;
+		if ((fmode & O_BENEATH) != 0)
+			ndp->ni_cnd.cn_flags |= BENEATH;
 		if (!(vn_open_flags & VN_OPEN_NOAUDIT))
 			ndp->ni_cnd.cn_flags |= AUDITVNODE1;
 		if (vn_open_flags & VN_OPEN_NOCAPCHECK)
@@ -269,6 +271,8 @@ restart:
 		    ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF;
 		if (!(fmode & FWRITE))
 			ndp->ni_cnd.cn_flags |= LOCKSHARED;
+		if ((fmode & O_BENEATH) != 0)
+			ndp->ni_cnd.cn_flags |= BENEATH;
 		if (!(vn_open_flags & VN_OPEN_NOAUDIT))
 			ndp->ni_cnd.cn_flags |= AUDITVNODE1;
 		if (vn_open_flags & VN_OPEN_NOCAPCHECK)

Modified: head/sys/sys/fcntl.h
==============================================================================
--- head/sys/sys/fcntl.h	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/sys/fcntl.h	Thu Oct 25 22:16:34 2018	(r339748)
@@ -133,6 +133,7 @@ typedef	__pid_t		pid_t;
 
 #if __BSD_VISIBLE
 #define	O_VERIFY	0x00200000	/* open only after verification */
+#define	O_BENEATH	0x00400000	/* Fail if not under cwd */
 #endif
 
 /*
@@ -206,10 +207,12 @@ typedef	__pid_t		pid_t;
 /*
  * Miscellaneous flags for the *at() syscalls.
  */
-#define	AT_EACCESS		0x100	/* Check access using effective user and group ID */
-#define	AT_SYMLINK_NOFOLLOW	0x200   /* Do not follow symbolic links */
-#define	AT_SYMLINK_FOLLOW	0x400	/* Follow symbolic link */
-#define	AT_REMOVEDIR		0x800	/* Remove directory instead of file */
+#define	AT_EACCESS		0x0100	/* Check access using effective user
+					   and group ID */
+#define	AT_SYMLINK_NOFOLLOW	0x0200	/* Do not follow symbolic links */
+#define	AT_SYMLINK_FOLLOW	0x0400	/* Follow symbolic link */
+#define	AT_REMOVEDIR		0x0800	/* Remove directory instead of file */
+#define	AT_BENEATH		0x1000	/* Fail if not under dirfd */
 #endif
 
 /*

Modified: head/sys/sys/namei.h
==============================================================================
--- head/sys/sys/namei.h	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/sys/namei.h	Thu Oct 25 22:16:34 2018	(r339748)
@@ -119,6 +119,7 @@ struct nameidata {
 #define	WANTPARENT	0x0010	/* want parent vnode returned unlocked */
 #define	NOCACHE		0x0020	/* name must not be left in cache */
 #define	FOLLOW		0x0040	/* follow symbolic links */
+#define	BENEATH		0x0080	/* No escape from the start dir */
 #define	LOCKSHARED	0x0100	/* Shared lock leaf */
 #define	NOFOLLOW	0x0000	/* do not follow symbolic links (pseudo) */
 #define	MODMASK		0x01fc	/* mask of operational modifiers */

Modified: head/sys/sys/syscallsubr.h
==============================================================================
--- head/sys/sys/syscallsubr.h	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/sys/syscallsubr.h	Thu Oct 25 22:16:34 2018	(r339748)
@@ -219,7 +219,7 @@ int	kern_recvit(struct thread *td, int s, struct msghd
 int	kern_renameat(struct thread *td, int oldfd, char *old, int newfd,
 	    char *new, enum uio_seg pathseg);
 int	kern_rmdirat(struct thread *td, int fd, char *path,
-	    enum uio_seg pathseg);
+	    enum uio_seg pathseg, int flag);
 int	kern_sched_getparam(struct thread *td, struct thread *targettd,
 	    struct sched_param *param);
 int	kern_sched_getscheduler(struct thread *td, struct thread *targettd,
@@ -286,7 +286,7 @@ int	kern_thr_suspend(struct thread *td, struct timespe
 int	kern_truncate(struct thread *td, char *path, enum uio_seg pathseg,
 	    off_t length);
 int	kern_unlinkat(struct thread *td, int fd, char *path,
-	    enum uio_seg pathseg, ino_t oldinum);
+	    enum uio_seg pathseg, int flag, ino_t oldinum);
 int	kern_utimesat(struct thread *td, int fd, char *path,
 	    enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
 int	kern_utimensat(struct thread *td, int fd, char *path,

Modified: head/sys/ufs/ffs/ffs_alloc.c
==============================================================================
--- head/sys/ufs/ffs/ffs_alloc.c	Thu Oct 25 21:45:24 2018	(r339747)
+++ head/sys/ufs/ffs/ffs_alloc.c	Thu Oct 25 22:16:34 2018	(r339748)
@@ -3399,7 +3399,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
 		vn_finished_write(mp);
 		mp = NULL;
 		error = kern_unlinkat(td, AT_FDCWD, (char *)(intptr_t)cmd.value,
-		    UIO_USERSPACE, (ino_t)cmd.size);
+		    UIO_USERSPACE, 0, (ino_t)cmd.size);
 		break;
 
 	case FFS_SET_INODE:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201810252216.w9PMGYNw086754>