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:
parent
6f26dd50c3
commit
7cdb0b9d82
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=343891
@ -410,6 +410,7 @@ namei(struct nameidata *ndp)
|
|||||||
dp = NULL;
|
dp = NULL;
|
||||||
cnp->cn_nameptr = cnp->cn_pnbuf;
|
cnp->cn_nameptr = cnp->cn_pnbuf;
|
||||||
if (cnp->cn_pnbuf[0] == '/') {
|
if (cnp->cn_pnbuf[0] == '/') {
|
||||||
|
ndp->ni_resflags |= NIRES_ABS;
|
||||||
error = namei_handle_root(ndp, &dp);
|
error = namei_handle_root(ndp, &dp);
|
||||||
} else {
|
} else {
|
||||||
if (ndp->ni_startdir != NULL) {
|
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_dirp = namep;
|
||||||
ndp->ni_dirfd = dirfd;
|
ndp->ni_dirfd = dirfd;
|
||||||
ndp->ni_startdir = startdir;
|
ndp->ni_startdir = startdir;
|
||||||
|
ndp->ni_resflags = 0;
|
||||||
filecaps_init(&ndp->ni_filecaps);
|
filecaps_init(&ndp->ni_filecaps);
|
||||||
ndp->ni_cnd.cn_thread = td;
|
ndp->ni_cnd.cn_thread = td;
|
||||||
if (rightsp != NULL)
|
if (rightsp != NULL)
|
||||||
|
@ -3544,10 +3544,10 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#ifdef CAPABILITIES
|
#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
|
* 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,
|
error = cap_check(&tond.ni_filecaps.fc_rights,
|
||||||
&cap_unlinkat_rights);
|
&cap_unlinkat_rights);
|
||||||
|
@ -87,6 +87,10 @@ struct nameidata {
|
|||||||
*/
|
*/
|
||||||
struct vnode *ni_vp; /* vnode of result */
|
struct vnode *ni_vp; /* vnode of result */
|
||||||
struct vnode *ni_dvp; /* vnode of intermediate directory */
|
struct vnode *ni_dvp; /* vnode of intermediate directory */
|
||||||
|
/*
|
||||||
|
* Results: flags returned from namei
|
||||||
|
*/
|
||||||
|
u_int ni_resflags;
|
||||||
/*
|
/*
|
||||||
* Shared between namei and lookup/commit routines.
|
* Shared between namei and lookup/commit routines.
|
||||||
*/
|
*/
|
||||||
@ -159,6 +163,11 @@ struct nameidata {
|
|||||||
#define NOCAPCHECK 0x20000000 /* do not perform capability checks */
|
#define NOCAPCHECK 0x20000000 /* do not perform capability checks */
|
||||||
#define PARAMASK 0x3ffffe00 /* mask of parameter descriptors */
|
#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.
|
* Flags in ni_lcf, valid for the duration of the namei call.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user