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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to