aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2017-10-13 14:14:46 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2017-10-13 14:14:46 +0000
commit627ac5b4e3befe4830fe8abda5d649bf278f4f84 (patch)
tree89150c58fd3c6e482266870419c8d314962cd234
parent6e309d75d22d31b987dd5a28b6a758b043cfadff (diff)
downloadsrc-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.c15
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);