summaryrefslogtreecommitdiff
path: root/sys/dev/sysmon
diff options
context:
space:
mode:
authorxtraeme <xtraeme@NetBSD.org>2007-11-10 09:32:24 +0000
committerxtraeme <xtraeme@NetBSD.org>2007-11-10 09:32:24 +0000
commit91551751e7fa1e882ce8224c90d49a83a971c97c (patch)
treecda917b152293f7e901da2bbc4417027cb1a46f1 /sys/dev/sysmon
parent110566cad5a8c3a18a553966d0f4564b776d786d (diff)
Add another flag that is set only when the event was enqueued
(and its dictionary created) successfully and use it in the POWER_EVENT_RECVDICT ioctl to check if the dictionary is ready before calling prop_dictionary_copyout_ioctl(). This fixes a rare condition when too many events are enqueued and there wasn't time to create the dictionary, so prop_dictionary_copyout_ioctl() fails with a NULL pointer dereference.
Diffstat (limited to 'sys/dev/sysmon')
-rw-r--r--sys/dev/sysmon/sysmon_power.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/sys/dev/sysmon/sysmon_power.c b/sys/dev/sysmon/sysmon_power.c
index a75d0b586d0..167c6398aaa 100644
--- a/sys/dev/sysmon/sysmon_power.c
+++ b/sys/dev/sysmon/sysmon_power.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sysmon_power.c,v 1.29 2007/10/10 23:25:40 xtraeme Exp $ */
+/* $NetBSD: sysmon_power.c,v 1.30 2007/11/10 09:32:24 xtraeme Exp $ */
/*-
* Copyright (c) 2007 Juan Romero Pardines.
@@ -69,7 +69,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.29 2007/10/10 23:25:40 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.30 2007/11/10 09:32:24 xtraeme Exp $");
#include "opt_compat_netbsd.h"
#include <sys/param.h>
@@ -156,6 +156,7 @@ static const struct power_event_description penvsys_type_desc[] = {
#define SYSMON_MAX_POWER_EVENTS 32
#define SYSMON_POWER_DICTIONARY_BUSY 0x01
+#define SYSMON_POWER_DICTIONARY_READY 0x02
static power_event_t sysmon_power_event_queue[SYSMON_MAX_POWER_EVENTS];
static int sysmon_power_event_queue_head;
@@ -265,7 +266,7 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped,
power_event_t pev;
int rv, error = 0;
- if (!pev_data)
+ if (!ped || !ped->dict || !pev_data)
return EINVAL;
mutex_enter(&sysmon_power_event_queue_mtx);
@@ -342,12 +343,6 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped,
}
/*
- * The dictionary for the event was created successfully
- * at this point, time to add it into the list.
- */
- SLIST_INSERT_HEAD(&pev_dict_list, ped, pev_dict_head);
-
- /*
* Enqueue the event.
*/
rv = sysmon_queue_power_event(&pev);
@@ -359,8 +354,11 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped,
goto out;
} else {
/*
- * Notify the daemon that an event is ready.
+ * Notify the daemon that an event is ready and its
+ * dictionary is ready to be fetched.
*/
+ ped->flags |= SYSMON_POWER_DICTIONARY_READY;
+ SLIST_INSERT_HEAD(&pev_dict_list, ped, pev_dict_head);
cv_broadcast(&sysmon_power_event_queue_cv);
mutex_exit(&sysmon_power_event_queue_mtx);
selnotify(&sysmon_power_event_queue_selinfo, 0);
@@ -563,12 +561,18 @@ sysmonioctl_power(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
*/
mutex_enter(&sysmon_power_event_queue_mtx);
ped = SLIST_FIRST(&pev_dict_list);
- if (!ped) {
+ if (!ped || !ped->dict) {
mutex_exit(&sysmon_power_event_queue_mtx);
error = ENOTSUP;
break;
}
+ if ((ped->flags & SYSMON_POWER_DICTIONARY_READY) == 0) {
+ mutex_exit(&sysmon_power_event_queue_mtx);
+ error = EINVAL;
+ break;
+ }
+
if (ped->flags & SYSMON_POWER_DICTIONARY_BUSY) {
mutex_exit(&sysmon_power_event_queue_mtx);
error = EBUSY;
@@ -590,6 +594,7 @@ sysmonioctl_power(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
*/
mutex_enter(&sysmon_power_event_queue_mtx);
ped->flags &= ~SYSMON_POWER_DICTIONARY_BUSY;
+ ped->flags &= ~SYSMON_POWER_DICTIONARY_READY;
SLIST_REMOVE_HEAD(&pev_dict_list, pev_dict_head);
mutex_exit(&sysmon_power_event_queue_mtx);
sysmon_power_destroy_dictionary(ped);