Decompose linkat()/renameat() rights to source and target.
To make it easier to understand how Capsicum interacts with linkat() and renameat(), rename the rights to CAP_{LINK,RENAME}AT_{SOURCE,TARGET}. This also addresses a shortcoming in Capsicum, where it isn't possible to disable linking to files stored in a directory. Creating hardlinks essentially makes it possible to access files with additional rights. Reviewed by: rwatson, wblock Differential Revision: https://reviews.freebsd.org/D3411
This commit is contained in:
parent
34d2e76a64
commit
bc1ace0b96
@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 23, 2015
|
||||
.Dd August 27, 2015
|
||||
.Dt RIGHTS 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -71,7 +71,7 @@ The
|
||||
family of functions should be used to manage the structure.
|
||||
.Sh RIGHTS
|
||||
The following rights may be specified in a rights mask:
|
||||
.Bl -tag -width CAP_EXTATTR_DELETE
|
||||
.Bl -tag -width CAP_RENAMEAT_SOURCE
|
||||
.It Dv CAP_ACCEPT
|
||||
Permit
|
||||
.Xr accept 2
|
||||
@ -328,12 +328,28 @@ argument is non-NULL).
|
||||
.Dv CAP_EVENT
|
||||
is also required on file descriptors that will be monitored using
|
||||
.Xr kevent 2 .
|
||||
.It Dv CAP_LINKAT
|
||||
.It Dv CAP_LINKAT_SOURCE
|
||||
Permit
|
||||
.Xr linkat 2
|
||||
and
|
||||
.Xr renameat 2
|
||||
on the destination directory descriptor.
|
||||
on the source directory descriptor.
|
||||
This right includes the
|
||||
.Dv CAP_LOOKUP
|
||||
right.
|
||||
.Pp
|
||||
Warning:
|
||||
.Dv CAP_LINKAT_SOURCE
|
||||
makes it possible to link files in a directory for which file
|
||||
descriptors exist that have additional rights.
|
||||
For example,
|
||||
a file stored in a directory that does not allow
|
||||
.Dv CAP_READ
|
||||
may be linked in another directory that does allow
|
||||
.Dv CAP_READ ,
|
||||
thereby granting read access to a file that is otherwise unreadable.
|
||||
.It Dv CAP_LINKAT_TARGET
|
||||
Permit
|
||||
.Xr linkat 2
|
||||
on the target directory descriptor.
|
||||
This right includes the
|
||||
.Dv CAP_LOOKUP
|
||||
right.
|
||||
@ -474,10 +490,28 @@ is also required) and related system calls.
|
||||
.It Dv CAP_RECV
|
||||
An alias to
|
||||
.Dv CAP_READ .
|
||||
.It Dv CAP_RENAMEAT
|
||||
.It Dv CAP_RENAMEAT_SOURCE
|
||||
Permit
|
||||
.Xr renameat 2 .
|
||||
This right is required on the source directory descriptor.
|
||||
.Xr renameat 2
|
||||
on the source directory descriptor.
|
||||
This right includes the
|
||||
.Dv CAP_LOOKUP
|
||||
right.
|
||||
.Pp
|
||||
Warning:
|
||||
.Dv CAP_RENAMEAT_SOURCE
|
||||
makes it possible to move files to a directory for which file
|
||||
descriptors exist that have additional rights.
|
||||
For example,
|
||||
a file stored in a directory that does not allow
|
||||
.Dv CAP_READ
|
||||
may be moved to another directory that does allow
|
||||
.Dv CAP_READ ,
|
||||
thereby granting read access to a file that is otherwise unreadable.
|
||||
.It Dv CAP_RENAMEAT_TARGET
|
||||
Permit
|
||||
.Xr renameat 2
|
||||
on the target directory descriptor.
|
||||
This right includes the
|
||||
.Dv CAP_LOOKUP
|
||||
right.
|
||||
|
@ -56,13 +56,13 @@ __FBSDID("$FreeBSD$");
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY, CAP_MKDIRAT) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FILE, CAP_CREATE) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FIFO, CAP_MKFIFOAT) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LOOKUP) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LINKAT_SOURCE) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT_TARGET) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_OPEN, CAP_LOOKUP) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_READDIR, CAP_READ) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_READLINK, CAP_LOOKUP) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_LINKAT) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT_SOURCE) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_RENAMEAT_TARGET) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_STAT_FGET, CAP_FSTAT) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE, CAP_FTRUNCATE) \
|
||||
MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES, CAP_FUTIMES) \
|
||||
|
@ -1441,7 +1441,8 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2,
|
||||
|
||||
again:
|
||||
bwillwrite();
|
||||
NDINIT_AT(&nd, LOOKUP, follow | AUDITVNODE1, segflg, path1, fd1, td);
|
||||
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, segflg, path1, fd1,
|
||||
cap_rights_init(&rights, CAP_LINKAT_SOURCE), td);
|
||||
|
||||
if ((error = namei(&nd)) != 0)
|
||||
return (error);
|
||||
@ -1451,9 +1452,9 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2,
|
||||
vrele(vp);
|
||||
return (EPERM); /* POSIX */
|
||||
}
|
||||
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE2 |
|
||||
NOCACHE, segflg, path2, fd2, cap_rights_init(&rights, CAP_LINKAT),
|
||||
td);
|
||||
NDINIT_ATRIGHTS(&nd, CREATE,
|
||||
LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE, segflg, path2, fd2,
|
||||
cap_rights_init(&rights, CAP_LINKAT_TARGET), td);
|
||||
if ((error = namei(&nd)) == 0) {
|
||||
if (nd.ni_vp != NULL) {
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
@ -3461,10 +3462,11 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new,
|
||||
#ifdef MAC
|
||||
NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART |
|
||||
AUDITVNODE1, pathseg, old, oldfd,
|
||||
cap_rights_init(&rights, CAP_RENAMEAT), td);
|
||||
cap_rights_init(&rights, CAP_RENAMEAT_SOURCE), td);
|
||||
#else
|
||||
NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1,
|
||||
pathseg, old, oldfd, cap_rights_init(&rights, CAP_RENAMEAT), td);
|
||||
pathseg, old, oldfd,
|
||||
cap_rights_init(&rights, CAP_RENAMEAT_SOURCE), td);
|
||||
#endif
|
||||
|
||||
if ((error = namei(&fromnd)) != 0)
|
||||
@ -3479,7 +3481,7 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new,
|
||||
fvp = fromnd.ni_vp;
|
||||
NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE |
|
||||
SAVESTART | AUDITVNODE2, pathseg, new, newfd,
|
||||
cap_rights_init(&rights, CAP_LINKAT), td);
|
||||
cap_rights_init(&rights, CAP_RENAMEAT_TARGET), td);
|
||||
if (fromnd.ni_vp->v_type == VDIR)
|
||||
tond.ni_cnd.cn_flags |= WILLBEDIR;
|
||||
if ((error = namei(&tond)) != 0) {
|
||||
|
@ -150,16 +150,16 @@
|
||||
#define CAP_FUTIMES CAPRIGHT(0, 0x0000000000200000ULL)
|
||||
/* Allows for futimens(2), futimes(2), futimesat(2) and utimensat(2). */
|
||||
#define CAP_FUTIMESAT (CAP_FUTIMES | CAP_LOOKUP)
|
||||
/* Allows for linkat(2) and renameat(2) (destination directory descriptor). */
|
||||
#define CAP_LINKAT (CAP_LOOKUP | 0x0000000000400000ULL)
|
||||
/* Allows for linkat(2) (target directory descriptor). */
|
||||
#define CAP_LINKAT_TARGET (CAP_LOOKUP | 0x0000000000400000ULL)
|
||||
/* Allows for mkdirat(2). */
|
||||
#define CAP_MKDIRAT (CAP_LOOKUP | 0x0000000000800000ULL)
|
||||
/* Allows for mkfifoat(2). */
|
||||
#define CAP_MKFIFOAT (CAP_LOOKUP | 0x0000000001000000ULL)
|
||||
/* Allows for mknodat(2). */
|
||||
#define CAP_MKNODAT (CAP_LOOKUP | 0x0000000002000000ULL)
|
||||
/* Allows for renameat(2). */
|
||||
#define CAP_RENAMEAT (CAP_LOOKUP | 0x0000000004000000ULL)
|
||||
/* Allows for renameat(2) (source directory descriptor). */
|
||||
#define CAP_RENAMEAT_SOURCE (CAP_LOOKUP | 0x0000000004000000ULL)
|
||||
/* Allows for symlinkat(2). */
|
||||
#define CAP_SYMLINKAT (CAP_LOOKUP | 0x0000000008000000ULL)
|
||||
/*
|
||||
@ -197,6 +197,11 @@
|
||||
/* Allows for connectat(2) on a directory descriptor. */
|
||||
#define CAP_CONNECTAT (CAP_LOOKUP | 0x0000010000000000ULL)
|
||||
|
||||
/* Allows for linkat(2) (source directory descriptor). */
|
||||
#define CAP_LINKAT_SOURCE (CAP_LOOKUP | 0x0000020000000000ULL)
|
||||
/* Allows for renameat(2) (target directory descriptor). */
|
||||
#define CAP_RENAMEAT_TARGET (CAP_LOOKUP | 0x0000040000000000ULL)
|
||||
|
||||
#define CAP_SOCK_CLIENT \
|
||||
(CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \
|
||||
CAP_PEELOFF | CAP_RECV | CAP_SEND | CAP_SETSOCKOPT | CAP_SHUTDOWN)
|
||||
@ -206,10 +211,10 @@
|
||||
CAP_SETSOCKOPT | CAP_SHUTDOWN)
|
||||
|
||||
/* All used bits for index 0. */
|
||||
#define CAP_ALL0 CAPRIGHT(0, 0x000001FFFFFFFFFFULL)
|
||||
#define CAP_ALL0 CAPRIGHT(0, 0x000007FFFFFFFFFFULL)
|
||||
|
||||
/* Available bits for index 0. */
|
||||
#define CAP_UNUSED0_42 CAPRIGHT(0, 0x0000020000000000ULL)
|
||||
#define CAP_UNUSED0_44 CAPRIGHT(0, 0x0000080000000000ULL)
|
||||
/* ... */
|
||||
#define CAP_UNUSED0_57 CAPRIGHT(0, 0x0100000000000000ULL)
|
||||
|
||||
|
@ -158,11 +158,13 @@ static struct cap_desc {
|
||||
{ CAP_FSTAT, "fs" },
|
||||
{ CAP_FSTATFS, "sf" },
|
||||
{ CAP_FUTIMES, "fu" },
|
||||
{ CAP_LINKAT, "li" },
|
||||
{ CAP_LINKAT_SOURCE, "ls" },
|
||||
{ CAP_LINKAT_TARGET, "lt" },
|
||||
{ CAP_MKDIRAT, "md" },
|
||||
{ CAP_MKFIFOAT, "mf" },
|
||||
{ CAP_MKNODAT, "mn" },
|
||||
{ CAP_RENAMEAT, "rn" },
|
||||
{ CAP_RENAMEAT_SOURCE, "rs" },
|
||||
{ CAP_RENAMEAT_TARGET, "rt" },
|
||||
{ CAP_SYMLINKAT, "sl" },
|
||||
{ CAP_UNLINKAT, "un" },
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user