Skip to content

Commit

Permalink
When asked to use kqueue, AIO stores its internal state in the
Browse files Browse the repository at this point in the history
`kn_sdata' member of the newly registered knote. The problem is that
this member is overwritten by a call to kevent(2) with the EV_ADD flag,
targetted at the same kevent/knote. For instance, a userland application
may set the pointer to NULL, leading to a panic.

A testcase was provided by the submitter.

PR:	kern/118911
Submitted by:	MOROHOSHI Akihiko <[email protected]>
MFC after:	1 day
  • Loading branch information
dumbbell committed Jan 24, 2008
1 parent eee74fe commit a8afa22
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 4 deletions.
10 changes: 6 additions & 4 deletions sys/kern/vfs_aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2251,6 +2251,7 @@ filt_aioattach(struct knote *kn)
*/
if ((kn->kn_flags & EV_FLAG1) == 0)
return (EPERM);
kn->kn_ptr.p_aio = aiocbe;
kn->kn_flags &= ~EV_FLAG1;

knlist_add(&aiocbe->klist, kn, 0);
Expand All @@ -2262,7 +2263,7 @@ filt_aioattach(struct knote *kn)
static void
filt_aiodetach(struct knote *kn)
{
struct aiocblist *aiocbe = (struct aiocblist *)kn->kn_sdata;
struct aiocblist *aiocbe = kn->kn_ptr.p_aio;

if (!knlist_empty(&aiocbe->klist))
knlist_remove(&aiocbe->klist, kn, 0);
Expand All @@ -2273,7 +2274,7 @@ filt_aiodetach(struct knote *kn)
static int
filt_aio(struct knote *kn, long hint)
{
struct aiocblist *aiocbe = (struct aiocblist *)kn->kn_sdata;
struct aiocblist *aiocbe = kn->kn_ptr.p_aio;

kn->kn_data = aiocbe->uaiocb._aiocb_private.error;
if (aiocbe->jobstate != JOBST_JOBFINISHED)
Expand All @@ -2295,6 +2296,7 @@ filt_lioattach(struct knote *kn)
*/
if ((kn->kn_flags & EV_FLAG1) == 0)
return (EPERM);
kn->kn_ptr.p_lio = lj;
kn->kn_flags &= ~EV_FLAG1;

knlist_add(&lj->klist, kn, 0);
Expand All @@ -2306,7 +2308,7 @@ filt_lioattach(struct knote *kn)
static void
filt_liodetach(struct knote *kn)
{
struct aioliojob * lj = (struct aioliojob *)kn->kn_sdata;
struct aioliojob * lj = kn->kn_ptr.p_lio;

if (!knlist_empty(&lj->klist))
knlist_remove(&lj->klist, kn, 0);
Expand All @@ -2317,7 +2319,7 @@ filt_liodetach(struct knote *kn)
static int
filt_lio(struct knote *kn, long hint)
{
struct aioliojob * lj = (struct aioliojob *)kn->kn_sdata;
struct aioliojob * lj = kn->kn_ptr.p_lio;

return (lj->lioj_flags & LIOJ_KEVENT_POSTED);
}
2 changes: 2 additions & 0 deletions sys/sys/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ struct knote {
union {
struct file *p_fp; /* file data pointer */
struct proc *p_proc; /* proc pointer */
struct aiocblist *p_aio; /* AIO job pointer */
struct aioliojob *p_lio; /* LIO job pointer */
} kn_ptr;
struct filterops *kn_fop;
void *kn_hook;
Expand Down

0 comments on commit a8afa22

Please sign in to comment.