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.
This commit is contained in:
xtraeme 2007-11-10 09:32:24 +00:00
parent 110566cad5
commit 91551751e7
1 changed files with 16 additions and 11 deletions

View File

@ -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);
@ -341,12 +342,6 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped,
goto out;
}
/*
* 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.
*/
@ -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);