fd: tighten seq protected areas to not contain malloc/free

This commit is contained in:
Mateusz Guzik 2018-03-28 03:07:02 +00:00
parent 2f68cdb944
commit 179da98f71
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=331657

View File

@ -111,6 +111,11 @@ static void fdgrowtable_exp(struct filedesc *fdp, int nfd);
static void fdunused(struct filedesc *fdp, int fd);
static void fdused(struct filedesc *fdp, int fd);
static int getmaxfd(struct thread *td);
static u_long *filecaps_copy_prep(const struct filecaps *src);
static void filecaps_copy_finish(const struct filecaps *src,
struct filecaps *dst, u_long *ioctls);
static u_long *filecaps_free_prep(struct filecaps *fcaps);
static void filecaps_free_finish(u_long *ioctls);
/*
* Each process has:
@ -302,12 +307,12 @@ fdfree(struct filedesc *fdp, int fd)
#ifdef CAPABILITIES
seq_write_begin(&fde->fde_seq);
#endif
fdefree_last(fde);
fde->fde_file = NULL;
fdunused(fdp, fd);
#ifdef CAPABILITIES
seq_write_end(&fde->fde_seq);
#endif
fdefree_last(fde);
fdunused(fdp, fd);
}
void
@ -813,6 +818,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new)
struct filedescent *oldfde, *newfde;
struct proc *p;
struct file *delfp;
u_long *oioctls, *nioctls;
int error, maxfd;
p = td->td_proc;
@ -902,15 +908,18 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new)
newfde = &fdp->fd_ofiles[new];
delfp = newfde->fde_file;
oioctls = filecaps_free_prep(&newfde->fde_caps);
nioctls = filecaps_copy_prep(&oldfde->fde_caps);
/*
* Duplicate the source descriptor.
*/
#ifdef CAPABILITIES
seq_write_begin(&newfde->fde_seq);
#endif
filecaps_free(&newfde->fde_caps);
memcpy(newfde, oldfde, fde_change_size);
filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true);
filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps,
nioctls);
if ((flags & FDDUP_FLAG_CLOEXEC) != 0)
newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE;
else
@ -918,6 +927,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new)
#ifdef CAPABILITIES
seq_write_end(&newfde->fde_seq);
#endif
filecaps_free_finish(oioctls);
td->td_retval[0] = new;
error = 0;
@ -1503,6 +1513,40 @@ filecaps_copy(const struct filecaps *src, struct filecaps *dst, bool locked)
return (0);
}
static u_long *
filecaps_copy_prep(const struct filecaps *src)
{
u_long *ioctls;
size_t size;
if (src->fc_ioctls == NULL)
return (NULL);
KASSERT(src->fc_nioctls > 0,
("fc_ioctls != NULL, but fc_nioctls=%hd", src->fc_nioctls));
size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls;
ioctls = malloc(size, M_FILECAPS, M_WAITOK);
return (ioctls);
}
static void
filecaps_copy_finish(const struct filecaps *src, struct filecaps *dst,
u_long *ioctls)
{
size_t size;
*dst = *src;
if (src->fc_ioctls == NULL) {
MPASS(ioctls == NULL);
return;
}
size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls;
dst->fc_ioctls = ioctls;
bcopy(src->fc_ioctls, dst->fc_ioctls, size);
}
/*
* Move filecaps structure to the new place and clear the old place.
*/
@ -1538,6 +1582,23 @@ filecaps_free(struct filecaps *fcaps)
bzero(fcaps, sizeof(*fcaps));
}
static u_long *
filecaps_free_prep(struct filecaps *fcaps)
{
u_long *ioctls;
ioctls = fcaps->fc_ioctls;
bzero(fcaps, sizeof(*fcaps));
return (ioctls);
}
static void
filecaps_free_finish(u_long *ioctls)
{
free(ioctls, M_FILECAPS);
}
/*
* Validate the given filecaps structure.
*/
@ -2963,6 +3024,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode,
{
struct filedescent *newfde, *oldfde;
struct file *fp;
u_long *ioctls;
int error, indx;
KASSERT(openerror == ENODEV || openerror == ENXIO,
@ -3007,11 +3069,13 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode,
fhold(fp);
newfde = &fdp->fd_ofiles[indx];
oldfde = &fdp->fd_ofiles[dfd];
ioctls = filecaps_copy_prep(&oldfde->fde_caps);
#ifdef CAPABILITIES
seq_write_begin(&newfde->fde_seq);
#endif
memcpy(newfde, oldfde, fde_change_size);
filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true);
filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps,
ioctls);
#ifdef CAPABILITIES
seq_write_end(&newfde->fde_seq);
#endif