Fix renameat(2) for CAPABILITIES kernels.

When renameat(2) is used with:
- absolute path for to;
- tofd not set to AT_FDCWD;
- the target exists
kern_renameat() requires CAP_UNLINK capability on tofd, but
corresponding namei ni_filecap is not initialized at all because the
lookup is absolute.  As result, the check was done against empty filecap
and syscall fails erronously.

Fix it by creating a return flags namei member and reporting if the
lookup was absolute, then do not touch to.ni_filecaps at all.

PR:	222258
Reviewed by:	jilles, ngie
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
X-MFC-note:	KBI breakage
Differential revision:	https://reviews.freebsd.org/D19096
This commit is contained in:
Konstantin Belousov 2019-02-08 04:18:17 +00:00
parent 6f26dd50c3
commit 7cdb0b9d82
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=343891
3 changed files with 13 additions and 2 deletions

View File

@ -410,6 +410,7 @@ namei(struct nameidata *ndp)
dp = NULL;
cnp->cn_nameptr = cnp->cn_pnbuf;
if (cnp->cn_pnbuf[0] == '/') {
ndp->ni_resflags |= NIRES_ABS;
error = namei_handle_root(ndp, &dp);
} else {
if (ndp->ni_startdir != NULL) {
@ -1302,6 +1303,7 @@ NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg,
ndp->ni_dirp = namep;
ndp->ni_dirfd = dirfd;
ndp->ni_startdir = startdir;
ndp->ni_resflags = 0;
filecaps_init(&ndp->ni_filecaps);
ndp->ni_cnd.cn_thread = td;
if (rightsp != NULL)

View File

@ -3544,10 +3544,10 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
goto out;
}
#ifdef CAPABILITIES
if (newfd != AT_FDCWD) {
if (newfd != AT_FDCWD && (tond.ni_resflags & NIRES_ABS) == 0) {
/*
* If the target already exists we require CAP_UNLINKAT
* from 'newfd'.
* from 'newfd', when newfd was used for the lookup.
*/
error = cap_check(&tond.ni_filecaps.fc_rights,
&cap_unlinkat_rights);

View File

@ -87,6 +87,10 @@ struct nameidata {
*/
struct vnode *ni_vp; /* vnode of result */
struct vnode *ni_dvp; /* vnode of intermediate directory */
/*
* Results: flags returned from namei
*/
u_int ni_resflags;
/*
* Shared between namei and lookup/commit routines.
*/
@ -159,6 +163,11 @@ struct nameidata {
#define NOCAPCHECK 0x20000000 /* do not perform capability checks */
#define PARAMASK 0x3ffffe00 /* mask of parameter descriptors */
/*
* Namei results flags
*/
#define NIRES_ABS 0x00000001 /* Path was absolute */
/*
* Flags in ni_lcf, valid for the duration of the namei call.
*/