svn commit: r366937 - in stable/12: lib/libc/sys sys/cddl/compat/opensolaris/sys sys/compat/cloudabi sys/compat/linux sys/kern sys/sys sys/ufs/ffs

Konstantin Belousov kib at FreeBSD.org
Thu Oct 22 15:23:45 UTC 2020


Author: kib
Date: Thu Oct 22 15:23:41 2020
New Revision: 366937
URL: https://svnweb.freebsd.org/changeset/base/366937

Log:
  MFC r339748, r340343, r340347, r341256, r366015-r366023, r366549:
  O_BENEATH and related features.
  
  Sponsored by:	The FreeBSD Foundation
  Tested by:	pho

Modified:
  stable/12/lib/libc/sys/access.2
  stable/12/lib/libc/sys/chflags.2
  stable/12/lib/libc/sys/chmod.2
  stable/12/lib/libc/sys/chown.2
  stable/12/lib/libc/sys/fhlink.2
  stable/12/lib/libc/sys/getfh.2
  stable/12/lib/libc/sys/link.2
  stable/12/lib/libc/sys/open.2
  stable/12/lib/libc/sys/stat.2
  stable/12/lib/libc/sys/unlink.2
  stable/12/lib/libc/sys/utimensat.2
  stable/12/sys/cddl/compat/opensolaris/sys/vnode.h
  stable/12/sys/compat/cloudabi/cloudabi_file.c
  stable/12/sys/compat/linux/linux_file.c
  stable/12/sys/kern/vfs_lookup.c
  stable/12/sys/kern/vfs_mountroot.c
  stable/12/sys/kern/vfs_syscalls.c
  stable/12/sys/kern/vfs_vnops.c
  stable/12/sys/sys/fcntl.h
  stable/12/sys/sys/namei.h
  stable/12/sys/sys/syscallsubr.h
  stable/12/sys/ufs/ffs/ffs_alloc.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/lib/libc/sys/access.2
==============================================================================
--- stable/12/lib/libc/sys/access.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/access.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)access.2	8.2 (Berkeley) 4/1/94
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt ACCESS 2
 .Os
 .Sh NAME
@@ -120,6 +120,20 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 Even if a process's real or effective user has appropriate privileges
@@ -197,6 +211,24 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn faccessat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chmod 2 ,

Modified: stable/12/lib/libc/sys/chflags.2
==============================================================================
--- stable/12/lib/libc/sys/chflags.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/chflags.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"	@(#)chflags.2	8.3 (Berkeley) 5/2/95
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt CHFLAGS 2
 .Os
 .Sh NAME
@@ -94,6 +94,21 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -306,6 +321,24 @@ Corrupted data was detected while reading from the fil
 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
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn chflagsat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chflags 1 ,

Modified: stable/12/lib/libc/sys/chmod.2
==============================================================================
--- stable/12/lib/libc/sys/chmod.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/chmod.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)chmod.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt CHMOD 2
 .Os
 .Sh NAME
@@ -101,6 +101,21 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -289,6 +304,24 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn fchmodat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chmod 1 ,

Modified: stable/12/lib/libc/sys/chown.2
==============================================================================
--- stable/12/lib/libc/sys/chown.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/chown.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)chown.2	8.4 (Berkeley) 4/19/94
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt CHOWN 2
 .Os
 .Sh NAME
@@ -118,6 +118,21 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -231,6 +246,24 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn fchownat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chgrp 1 ,

Modified: stable/12/lib/libc/sys/fhlink.2
==============================================================================
--- stable/12/lib/libc/sys/fhlink.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/fhlink.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt FHLINK 2
 .Os
 .Sh NAME
@@ -110,6 +110,13 @@ created.
 Only allow to link to a file which is beneath of the topping directory.
 See the description of the
 .Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
 flag in the
 .Xr open 2
 manual page.

Modified: stable/12/lib/libc/sys/getfh.2
==============================================================================
--- stable/12/lib/libc/sys/getfh.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/getfh.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -29,7 +29,7 @@
 .\"	@(#)getfh.2	8.1 (Berkeley) 6/9/93
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt GETFH 2
 .Os
 .Sh NAME
@@ -109,6 +109,13 @@ names a symbolic link, the status of the symbolic link
 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.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
 flag in the
 .Xr open 2
 manual page.

Modified: stable/12/lib/libc/sys/link.2
==============================================================================
--- stable/12/lib/libc/sys/link.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/link.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)link.2	8.3 (Berkeley) 1/12/94
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt LINK 2
 .Os
 .Sh NAME
@@ -115,6 +115,20 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -259,6 +273,26 @@ or
 respectively, is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa name1
+is not strictly relative to the starting directory.
+For example,
+.Fa name1
+is absolute or includes a ".." component that escapes
+the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fa linkat
+and the absolute path
+.Fa name1
+does not have its tail fully contained under the topping directory,
+or the relative path
+.Fa name1
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chflags 2 ,

Modified: stable/12/lib/libc/sys/open.2
==============================================================================
--- stable/12/lib/libc/sys/open.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/open.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)open.2	8.2 (Berkeley) 11/16/93
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt OPEN 2
 .Os
 .Sh NAME
@@ -75,8 +75,14 @@ function is equivalent to the
 .Fn open
 function except in the case where the
 .Fa path
-specifies a relative path.
-In this case the file to be opened is determined relative to the directory
+specifies a relative path, or the
+.Dv O_BENEATH
+flag is provided.
+For
+.Fn openat
+and relative
+.Fa path ,
+the file to be opened is determined relative to the directory
 associated with the file descriptor
 .Fa fd
 instead of the current working directory.
@@ -95,6 +101,32 @@ parameter, the current working directory is used
 and the behavior is identical to a call to
 .Fn open .
 .Pp
+When
+.Fn openat
+is called with an absolute
+.Fa path
+without the
+.Dv O_BENEATH
+flag, it ignores the
+.Fa fd
+argument.
+When
+.Dv O_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.
+When
+.Dv O_BENEATH
+is specified with a relative path, the
+.Fa fd
+argument is used both as the starting point, and as the topping point
+for the resolution.
+See the definition of the
+.Dv O_BENEATH
+flag below.
+.Pp
 In
 .Xr capsicum 4
 capability mode,
@@ -109,14 +141,28 @@ must be strictly relative to a file descriptor
 as defined in
 .Pa sys/kern/vfs_lookup.c .
 .Fa path
-must not be an absolute path and must not contain ".." components.
+must not be an absolute path and must not contain ".." components
+which cause the path resolution to escape the directory hierarchy
+starting at
+.Fa fd .
 Additionally, no symbolic link in
 .Fa path
-may contain ".." components either.
+may target absolute path or contain escaping ".." components.
 .Fa fd
 must not be
 .Dv AT_FDCWD .
 .Pp
+If the
+.Dv vfs.lookup_cap_dotdot
+.Xr sysctl 3
+MIB is set to zero, ".." components in the paths,
+used in capability mode, or with the
+.Dv O_BENEATH
+flag, are completely disabled.
+If the
+.Dv vfs.lookup_cap_dotdot_nonlocal
+MIB is set to zero, ".." is not allowed if found on non-local filesystem.
+.Pp
 The flags specified are formed by
 .Em or Ns 'ing
 the following values
@@ -143,6 +189,8 @@ 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 resolved path to be strictly relative to topping directory
+O_RESOLVE_BENEATH	require walked path to be strictly relative to topping directory
 .Ed
 .Pp
 Opening a file with
@@ -266,7 +314,34 @@ The details of what
 means is implementation specific.
 The run-time linker (rtld) uses this flag to ensure shared objects have
 been verified before operating on them.
+.Dv O_BENEATH
+returns
+.Er ENOTCAPABLE
+if the specified path, after resolving all symlinks and ".."
+references, does not end up with tail residing in the directory hierarchy of
+children beneath the topping directory.
+Topping 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 using
+.Fn openat .
+.Dv O_BENEATH
+allows arbitrary prefix that ends up at the topping directory,
+after which all further resolved components must be under it.
 .Pp
+.Dv O_RESOLVE_BENEATH
+returns
+.Er ENOTCAPABLE
+if any intermediate component of the specified relative path does not
+reside in the directory hierarchy beneath the topping directory.
+Comparing to
+.Dv O_BENEATH,
+absolute paths or even the temporal escape from beneath of the topping
+directory is not allowed.
+.Pp
 When
 .Fa fd
 is opened with
@@ -280,6 +355,7 @@ The primary use for this descriptor will be as the loo
 .Fn *at
 family of functions.
 .Pp
+.Pp
 If successful,
 .Fn open
 returns a non-negative integer, termed a file descriptor.
@@ -480,6 +556,12 @@ and
 .Dv O_EXEC
 or
 .Dv O_SEARCH .
+.It Bq Er EINVAL
+The
+.Dv O_RESOLVE_BENEATH
+flag is specified and
+.Dv path
+is absolute.
 .It Bq Er EBADF
 The
 .Fa path
@@ -508,9 +590,26 @@ 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.
+.It Bq Er ENOTCAPABLE
+The
+.Dv O_BENEATH
+flag was provided, and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
+.It Bq Er ENOTCAPABLE
+The
+.Dv O_RESOLVE_BENEATH
+flag was provided, and the relative
+.Fa path
+escapes topping directory.
 .El
 .Sh SEE ALSO
 .Xr chmod 2 ,

Modified: stable/12/lib/libc/sys/stat.2
==============================================================================
--- stable/12/lib/libc/sys/stat.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/stat.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)stat.2	8.4 (Berkeley) 5/1/95
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt STAT 2
 .Os
 .Sh NAME
@@ -84,11 +84,24 @@ and
 .Fn lstat
 except when the
 .Fa path
-specifies a relative path.
-In this case the status is retrieved from a file relative to
+specifies a relative path, or the
+.Dv AT_BENEATH
+flag is provided.
+For
+.Fn fstatat
+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
@@ -100,6 +113,20 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -118,6 +145,23 @@ respectively, depending on whether or not the
 bit is set in
 .Fa flag .
 .Pp
+When
+.Fn fstatat
+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.
+.Pp
 The
 .Fa sb
 argument is a pointer to a
@@ -409,6 +453,24 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn fstatat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr access 2 ,

Modified: stable/12/lib/libc/sys/unlink.2
==============================================================================
--- stable/12/lib/libc/sys/unlink.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/unlink.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -28,7 +28,7 @@
 .\"     @(#)unlink.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt UNLINK 2
 .Os
 .Sh NAME
@@ -89,6 +89,21 @@ 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 topping
+directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Pp
 If
@@ -202,6 +217,24 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn unlinkat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chflags 2 ,

Modified: stable/12/lib/libc/sys/utimensat.2
==============================================================================
--- stable/12/lib/libc/sys/utimensat.2	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/lib/libc/sys/utimensat.2	Thu Oct 22 15:23:41 2020	(r366937)
@@ -31,7 +31,7 @@
 .\"     @(#)utimes.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd March 30, 2020
+.Dd September 23, 2020
 .Dt UTIMENSAT 2
 .Os
 .Sh NAME
@@ -146,6 +146,21 @@ 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 topping directory.
+See the description of the
+.Dv O_BENEATH
+flag in the
+.Xr open 2
+manual page.
+.It Dv AT_RESOLVE_BENEATH
+Only walks paths below the topping directory.
+See the description of the
+.Dv O_RESOLVE_BENEATH
+flag in the
+.Xr open 2
+manual page.
 .El
 .Sh RETURN VALUES
 .Rv -std
@@ -269,6 +284,24 @@ argument is not an absolute path and
 is neither
 .Dv AT_FDCWD
 nor a file descriptor associated with a directory.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path,
+or contained a ".." component leading to a
+directory outside of the directory hierarchy specified by
+.Fa fd ,
+and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+The
+.Dv AT_BENEATH
+flag was provided to
+.Fn utimensat ,
+and the absolute
+.Fa path
+does not have its tail fully contained under the topping directory,
+or the relative
+.Fa path
+escapes it.
 .El
 .Sh SEE ALSO
 .Xr chflags 2 ,

Modified: stable/12/sys/cddl/compat/opensolaris/sys/vnode.h
==============================================================================
--- stable/12/sys/cddl/compat/opensolaris/sys/vnode.h	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/sys/cddl/compat/opensolaris/sys/vnode.h	Thu Oct 22 15:23:41 2020	(r366937)
@@ -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: stable/12/sys/compat/cloudabi/cloudabi_file.c
==============================================================================
--- stable/12/sys/compat/cloudabi/cloudabi_file.c	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/sys/compat/cloudabi/cloudabi_file.c	Thu Oct 22 15:23:41 2020	(r366937)
@@ -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: stable/12/sys/compat/linux/linux_file.c
==============================================================================
--- stable/12/sys/compat/linux/linux_file.c	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/sys/compat/linux/linux_file.c	Thu Oct 22 15:23:41 2020	(r366937)
@@ -540,7 +540,7 @@ linux_unlink(struct thread *td, struct linux_unlink_ar
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-	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,
@@ -568,9 +568,9 @@ linux_unlinkat(struct thread *td, struct linux_unlinka
 	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
 
 	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,
@@ -661,7 +661,7 @@ linux_rmdir(struct thread *td, struct linux_rmdir_args
 
 	LCONVPATHEXIST(td, args->path, &path);
 
-	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
+	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
 	LFREEPATH(path);
 	return (error);
 }

Modified: stable/12/sys/kern/vfs_lookup.c
==============================================================================
--- stable/12/sys/kern/vfs_lookup.c	Thu Oct 22 12:22:08 2020	(r366936)
+++ stable/12/sys/kern/vfs_lookup.c	Thu Oct 22 15:23:41 2020	(r366937)
@@ -174,9 +174,18 @@ static void
 nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp)
 {
 	struct nameicap_tracker *nt;
+	struct componentname *cnp;
 
 	if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR)
 		return;
+	cnp = &ndp->ni_cnd;
+	if ((cnp->cn_flags & BENEATH) != 0 &&
+	    (ndp->ni_lcf & NI_LCF_BENEATH_LATCHED) == 0) {
+		MPASS((ndp->ni_lcf & NI_LCF_LATCH) != 0);
+		if (dp != ndp->ni_beneath_latch)
+			return;
+		ndp->ni_lcf |= NI_LCF_BENEATH_LATCHED;
+	}
 	nt = uma_zalloc(nt_zone, M_WAITOK);
 	vhold(dp);
 	nt->dp = dp;
@@ -184,7 +193,7 @@ nameicap_tracker_add(struct nameidata *ndp, struct vno
 }
 
 static void
-nameicap_cleanup(struct nameidata *ndp)
+nameicap_cleanup(struct nameidata *ndp, bool clean_latch)
 {
 	struct nameicap_tracker *nt, *nt1;
 
@@ -195,12 +204,20 @@ nameicap_cleanup(struct nameidata *ndp)
 		vdrop(nt->dp);
 		uma_zfree(nt_zone, nt);
 	}
+	if (clean_latch && (ndp->ni_lcf & NI_LCF_LATCH) != 0) {
+		ndp->ni_lcf &= ~NI_LCF_LATCH;
+		vrele(ndp->ni_beneath_latch);
+	}
 }
 
 /*
  * For dotdot lookups in capability mode, only allow the component
  * lookup to succeed if the resulting directory was already traversed
- * during the operation.  Also fail dotdot lookups for non-local
+ * during the operation.  This catches situations where already
+ * traversed directory is moved to different parent, and then we walk
+ * over it with dotdots.
+ *
+ * Also allow to force failure of dotdot lookups for non-local
  * filesystems, where external agents might assist local lookups to
  * escape the compartment.
  */
@@ -219,6 +236,12 @@ nameicap_check_dotdot(struct nameidata *ndp, struct vn
 		return (ENOTCAPABLE);
 	TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head,
 	    nm_link) {
+		if ((ndp->ni_lcf & NI_LCF_LATCH) != 0 &&
+		    ndp->ni_beneath_latch == nt->dp) {
+			ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED;
+			nameicap_cleanup(ndp, false);
+			return (0);
+		}
 		if (dp == nt->dp)
 			return (0);
 	}
@@ -249,6 +272,11 @@ namei_handle_root(struct nameidata *ndp, struct vnode 
 #endif
 		return (ENOTCAPABLE);
 	}
+	if ((cnp->cn_flags & BENEATH) != 0) {
+		ndp->ni_lcf |= NI_LCF_BENEATH_ABS;
+		ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED;
+		nameicap_cleanup(ndp, false);
+	}
 	while (*(cnp->cn_nameptr) == '/') {
 		cnp->cn_nameptr++;
 		ndp->ni_pathlen--;
@@ -290,6 +318,7 @@ namei(struct nameidata *ndp)
 	struct thread *td;
 	struct proc *p;
 	cap_rights_t rights;
+	struct filecaps dirfd_caps;
 	struct uio auio;
 	int error, linklen, startdir_used;
 
@@ -347,6 +376,7 @@ namei(struct nameidata *ndp)
 	if (error == 0 && IN_CAPABILITY_MODE(td) &&
 	    (cnp->cn_flags & NOCAPCHECK) == 0) {
 		ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
+		ndp->ni_resflags |= NIRES_STRICTREL;
 		if (ndp->ni_dirfd == AT_FDCWD) {
 #ifdef KTRACE
 			if (KTRPOINT(td, KTR_CAPFAIL))
@@ -441,13 +471,42 @@ namei(struct nameidata *ndp)
 			    ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
 			    ndp->ni_filecaps.fc_nioctls != -1) {
 				ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
+				ndp->ni_resflags |= NIRES_STRICTREL;
 			}
 #endif
 		}
 		if (error == 0 && dp->v_type != VDIR)
 			error = ENOTDIR;
 	}
+	if (error == 0 && (cnp->cn_flags & BENEATH) != 0) {
+		if (ndp->ni_dirfd == AT_FDCWD) {
+			ndp->ni_beneath_latch = fdp->fd_cdir;
+			vrefact(ndp->ni_beneath_latch);
+		} else {
+			rights = ndp->ni_rightsneeded;
+			cap_rights_set(&rights, CAP_LOOKUP);
+			error = fgetvp_rights(td, ndp->ni_dirfd, &rights,
+			    &dirfd_caps, &ndp->ni_beneath_latch);
+			if (error == 0 && dp->v_type != VDIR) {
+				vrele(ndp->ni_beneath_latch);
+				error = ENOTDIR;
+			}
+		}
+		if (error == 0)
+			ndp->ni_lcf |= NI_LCF_LATCH;
+	}
 	FILEDESC_SUNLOCK(fdp);
+
+	if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) {
+		if (cnp->cn_pnbuf[0] == '/' ||
+		    (ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) {
+			error = EINVAL;
+		} else if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0) {
+			ndp->ni_lcf |= NI_LCF_STRICTRELATIVE |
+			    NI_LCF_CAP_DOTDOT;
+		}
+	}
+
 	if (ndp->ni_startdir != NULL && !startdir_used)
 		vrele(ndp->ni_startdir);
 	if (error != 0) {
@@ -455,16 +514,29 @@ namei(struct nameidata *ndp)
 			vrele(dp);
 		goto out;
 	}
-	if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 &&
-	    lookup_cap_dotdot != 0)
+	MPASS((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | NI_LCF_LATCH)) !=
+	    NI_LCF_BENEATH_ABS);
+	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);
 	for (;;) {
 		ndp->ni_startdir = dp;
 		error = lookup(ndp);
-		if (error != 0)
+		if (error != 0) {
+			/*
+			 * Override an error to not allow user to use
+			 * BENEATH as an oracle.
+			 */
+			if ((ndp->ni_lcf & (NI_LCF_LATCH |
+			    NI_LCF_BENEATH_LATCHED)) == NI_LCF_LATCH)
+				error = ENOTCAPABLE;
 			goto out;
+		}
+
 		/*
 		 * If not a symbolic link, we're done.
 		 */
@@ -474,9 +546,15 @@ namei(struct nameidata *ndp)
 				namei_cleanup_cnp(cnp);
 			} else
 				cnp->cn_flags |= HASBUF;
-			nameicap_cleanup(ndp);
-			SDT_PROBE2(vfs, namei, lookup, return, 0, ndp->ni_vp);
-			return (0);
+			if ((ndp->ni_lcf & (NI_LCF_LATCH |
+			    NI_LCF_BENEATH_LATCHED)) == NI_LCF_LATCH) {
+				NDFREE(ndp, 0);
+				error = ENOTCAPABLE;
+			}
+			nameicap_cleanup(ndp, true);
+			SDT_PROBE2(vfs, namei, lookup, return, error,
+			    (error == 0 ? ndp->ni_vp : NULL));
+			return (error);
 		}
 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
 			error = ELOOP;
@@ -547,8 +625,9 @@ namei(struct nameidata *ndp)
 	vrele(ndp->ni_dvp);
 out:
 	vrele(ndp->ni_rootdir);
+	MPASS(error != 0);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list