diff options
author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2017-10-13 14:14:46 +0000 |
---|---|---|
committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2017-10-13 14:14:46 +0000 |
commit | 627ac5b4e3befe4830fe8abda5d649bf278f4f84 (patch) | |
tree | 89150c58fd3c6e482266870419c8d314962cd234 | |
parent | 6e309d75d22d31b987dd5a28b6a758b043cfadff (diff) | |
download | src-627ac5b4e3befe4830fe8abda5d649bf278f4f84.tar.gz src-627ac5b4e3befe4830fe8abda5d649bf278f4f84.zip |
Don't call selrecord() outside the select system call in the LinuxKPI, because
then td->td_sel is NULL and this will result in a segfault inside selrecord().
This happens when only using kqueue() to poll for read and write events.
If select() and kqueue() is mixed there won't be a segfault.
Reported by: Johannes Lundberg
MFC after: 1 week
Sponsored by: Mellanox Technologies
Notes
Notes:
svn path=/head/; revision=324597
-rw-r--r-- | sys/compat/linuxkpi/common/src/linux_compat.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c index ca57bfae1c09..7aede5e8c97d 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -1021,6 +1021,8 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag) return (error); } +#define LINUX_POLL_TABLE_NORMAL ((poll_table *)1) + static int linux_dev_poll(struct cdev *dev, int events, struct thread *td) { @@ -1037,7 +1039,7 @@ linux_dev_poll(struct cdev *dev, int events, struct thread *td) filp->f_flags = file->f_flag; linux_set_current(td); if (filp->f_op->poll != NULL) - revents = filp->f_op->poll(filp, NULL) & events; + revents = filp->f_op->poll(filp, LINUX_POLL_TABLE_NORMAL) & events; else revents = 0; @@ -1094,7 +1096,9 @@ linux_poll_wait(struct linux_file *filp, wait_queue_head_t *wqh, poll_table *p) [LINUX_FWQ_STATE_READY] = LINUX_FWQ_STATE_QUEUED, }; - selrecord(curthread, &filp->f_selinfo); + /* check if we are called inside the select system call */ + if (p == LINUX_POLL_TABLE_NORMAL) + selrecord(curthread, &filp->f_selinfo); switch (linux_poll_wakeup_state(&filp->f_wait_queue.state, state)) { case LINUX_FWQ_STATE_INIT: @@ -1438,10 +1442,9 @@ linux_file_poll(struct file *file, int events, struct ucred *active_cred, filp = (struct linux_file *)file->f_data; filp->f_flags = file->f_flag; linux_set_current(td); - if (filp->f_op->poll != NULL) { - selrecord(td, &filp->f_selinfo); - revents = filp->f_op->poll(filp, NULL) & events; - } else + if (filp->f_op->poll != NULL) + revents = filp->f_op->poll(filp, LINUX_POLL_TABLE_NORMAL) & events; + else revents = 0; return (revents); |