Author: ed Date: Thu Aug 27 15:16:41 2015 New Revision: 287209 URL: https://svnweb.freebsd.org/changeset/base/287209
Log: 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 Modified: head/share/man/man4/rights.4 head/sys/compat/cloudabi/cloudabi_fd.c head/sys/kern/vfs_syscalls.c head/sys/sys/capsicum.h head/usr.bin/procstat/procstat_files.c Modified: head/share/man/man4/rights.4 ============================================================================== --- head/share/man/man4/rights.4 Thu Aug 27 15:03:34 2015 (r287208) +++ head/share/man/man4/rights.4 Thu Aug 27 15:16:41 2015 (r287209) @@ -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 cal .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. Modified: head/sys/compat/cloudabi/cloudabi_fd.c ============================================================================== --- head/sys/compat/cloudabi/cloudabi_fd.c Thu Aug 27 15:03:34 2015 (r287208) +++ head/sys/compat/cloudabi/cloudabi_fd.c Thu Aug 27 15:16:41 2015 (r287209) @@ -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) \ Modified: head/sys/kern/vfs_syscalls.c ============================================================================== --- head/sys/kern/vfs_syscalls.c Thu Aug 27 15:03:34 2015 (r287208) +++ head/sys/kern/vfs_syscalls.c Thu Aug 27 15:16:41 2015 (r287209) @@ -1441,7 +1441,8 @@ kern_linkat(struct thread *td, int fd1, 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 @@ again: 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 @@ again: #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 @@ again: 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) { Modified: head/sys/sys/capsicum.h ============================================================================== --- head/sys/sys/capsicum.h Thu Aug 27 15:03:34 2015 (r287208) +++ head/sys/sys/capsicum.h Thu Aug 27 15:16:41 2015 (r287209) @@ -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) Modified: head/usr.bin/procstat/procstat_files.c ============================================================================== --- head/usr.bin/procstat/procstat_files.c Thu Aug 27 15:03:34 2015 (r287208) +++ head/usr.bin/procstat/procstat_files.c Thu Aug 27 15:16:41 2015 (r287209) @@ -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" }, _______________________________________________ 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"