diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1809,7 +1809,7 @@ filecaps_free(struct filecaps *fcaps) { - free(fcaps->fc_ioctls, M_FILECAPS); + filecaps_free_raw(fcaps); bzero(fcaps, sizeof(*fcaps)); } diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -4189,7 +4189,7 @@ (NC_NOMAKEENTRY | NC_KEEPPOSENTRY | LOCKLEAF | LOCKPARENT | WANTPARENT | \ FAILIFEXISTS | FOLLOW | EMPTYPATH | LOCKSHARED | SAVENAME | SAVESTART | \ WILLBEDIR | ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2 | NOCAPCHECK | \ - OPENREAD | OPENWRITE) + OPENREAD | OPENWRITE | WANTFILECAPS) #define CACHE_FPL_INTERNAL_CN_FLAGS \ (ISDOTDOT | MAKEENTRY | ISLASTCN) diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -80,6 +80,8 @@ SDT_PROBE_DEFINE4(vfs, namei, lookup, return, "int", "struct vnode *", "bool", "struct nameidata"); +MALLOC_DECLARE(M_FILECAPS); + /* Allocation zone for namei. */ uma_zone_t namei_zone; @@ -427,6 +429,7 @@ if (error != 0) { if (*dpp != NULL) vrele(*dpp); + filecaps_free_raw(&ndp->ni_filecaps); pwd_drop(pwd); return (error); } @@ -503,10 +506,13 @@ goto errout; } } + if ((cnp->cn_flags & WANTFILECAPS) == 0) + filecaps_free_raw(&ndp->ni_filecaps); SDT_PROBE4(vfs, namei, lookup, return, 0, ndp->ni_vp, false, ndp); return (0); errout: + filecaps_free_raw(&ndp->ni_filecaps); SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp); return (error); } @@ -735,6 +741,8 @@ } else cnp->cn_flags |= HASBUF; nameicap_cleanup(ndp); + if ((cnp->cn_flags & WANTFILECAPS) == 0) + filecaps_free_raw(&ndp->ni_filecaps); pwd_drop(pwd); if (error == 0) NDVALIDATE(ndp); @@ -764,6 +772,7 @@ SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp); namei_cleanup_cnp(cnp); nameicap_cleanup(ndp); + filecaps_free_raw(&ndp->ni_filecaps); pwd_drop(pwd); return (error); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1164,8 +1164,8 @@ /* Set the flags early so the finit in devfs can pick them up. */ fp->f_flag = flags & FMASK; cmode = ((mode & ~pdp->pd_cmask) & ALLPERMS) & ~S_ISTXT; - NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, - &rights); + NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | WANTFILECAPS, + pathseg, path, fd, &rights); td->td_dupfd = -1; /* XXX check for fdopen */ error = vn_open(&nd, &flags, cmode, fp); if (error != 0) { diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -237,6 +237,10 @@ bool filecaps_copy(const struct filecaps *src, struct filecaps *dst, bool locked); void filecaps_move(struct filecaps *src, struct filecaps *dst); +#define filecaps_free_raw(fcaps) do { \ + struct filecaps *_fcaps = (fcaps); \ + free(_fcaps->fc_ioctls, M_FILECAPS); \ +} while (0) void filecaps_free(struct filecaps *fcaps); int closef(struct file *fp, struct thread *td); diff --git a/sys/sys/namei.h b/sys/sys/namei.h --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -184,7 +184,7 @@ #define NOCAPCHECK 0x00100000 /* do not perform capability checks */ #define OPENREAD 0x00200000 /* open for reading */ #define OPENWRITE 0x00400000 /* open for writing */ -/* UNUSED 0x00800000 */ +#define WANTFILECAPS 0x00800000 /* copy file caps for the caller */ #define HASBUF 0x01000000 /* has allocated pathname buffer */ #define NOEXECCHECK 0x02000000 /* do not perform exec check on dir */ #define MAKEENTRY 0x04000000 /* entry is to be added to name cache */