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
This commit is contained in:
parent
2b2135b8b5
commit
4f77f48884
@ -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 ,
|
||||
|
@ -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 file system.
|
||||
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 ,
|
||||
|
@ -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 ,
|
||||
|
@ -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 ,
|
||||
|
@ -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 ,
|
||||
|
@ -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 ,
|
||||
|
@ -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 ,
|
||||
|
@ -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 ,
|
||||
|
@ -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 changed.
|
||||
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 ,
|
||||
|
@ -278,7 +278,7 @@ vn_remove(char *fnamep, enum uio_seg seg, enum rm dirflag)
|
||||
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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -590,7 +590,7 @@ linux_unlink(struct thread *td, struct linux_unlink_args *args)
|
||||
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_unlinkat_args *args)
|
||||
#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 *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);
|
||||
}
|
||||
|
@ -242,7 +242,8 @@ namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
|
||||
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);
|
||||
|
@ -389,7 +389,7 @@ vfs_mountroot_shuffle(struct thread *td, struct mount *mpdevfs)
|
||||
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);
|
||||
|
@ -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, enum uio_seg pathseg,
|
||||
|
||||
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, enum uio_seg pathseg,
|
||||
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, enum uio_seg pathseg,
|
||||
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 *path,
|
||||
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 *path,
|
||||
|
||||
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, enum uio_seg pathseg,
|
||||
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, enum uio_seg pathseg,
|
||||
|
||||
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, enum uio_seg pathseg,
|
||||
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, enum uio_seg pathseg)
|
||||
|
||||
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);
|
||||
|
@ -212,6 +212,8 @@ vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags,
|
||||
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 @@ vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags,
|
||||
((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)
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
@ -219,7 +219,7 @@ int kern_recvit(struct thread *td, int s, struct msghdr *mp,
|
||||
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 timespec *tsp);
|
||||
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,
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user