Commit ad4bfcb1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6:
  ACPI / ACPICA: Implicit notify for multiple devices
  ACPI / debugfs: Fix buffer overflows, double free
parents dd9c1549 981858bd
...@@ -416,10 +416,15 @@ struct acpi_gpe_handler_info { ...@@ -416,10 +416,15 @@ struct acpi_gpe_handler_info {
u8 originally_enabled; /* True if GPE was originally enabled */ u8 originally_enabled; /* True if GPE was originally enabled */
}; };
struct acpi_gpe_notify_object {
struct acpi_namespace_node *node;
struct acpi_gpe_notify_object *next;
};
union acpi_gpe_dispatch_info { union acpi_gpe_dispatch_info {
struct acpi_namespace_node *method_node; /* Method node for this GPE level */ struct acpi_namespace_node *method_node; /* Method node for this GPE level */
struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ struct acpi_gpe_handler_info *handler; /* Installed GPE handler */
struct acpi_namespace_node *device_node; /* Parent _PRW device for implicit notify */ struct acpi_gpe_notify_object device; /* List of _PRW devices for implicit notify */
}; };
/* /*
......
...@@ -457,6 +457,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) ...@@ -457,6 +457,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
acpi_status status; acpi_status status;
struct acpi_gpe_event_info *local_gpe_event_info; struct acpi_gpe_event_info *local_gpe_event_info;
struct acpi_evaluate_info *info; struct acpi_evaluate_info *info;
struct acpi_gpe_notify_object *notify_object;
ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
...@@ -508,10 +509,18 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) ...@@ -508,10 +509,18 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* from this thread -- because handlers may in turn run other * from this thread -- because handlers may in turn run other
* control methods. * control methods.
*/ */
status = status = acpi_ev_queue_notify_request(
acpi_ev_queue_notify_request(local_gpe_event_info->dispatch. local_gpe_event_info->dispatch.device.node,
device_node, ACPI_NOTIFY_DEVICE_WAKE);
notify_object = local_gpe_event_info->dispatch.device.next;
while (ACPI_SUCCESS(status) && notify_object) {
status = acpi_ev_queue_notify_request(
notify_object->node,
ACPI_NOTIFY_DEVICE_WAKE); ACPI_NOTIFY_DEVICE_WAKE);
notify_object = notify_object->next;
}
break; break;
case ACPI_GPE_DISPATCH_METHOD: case ACPI_GPE_DISPATCH_METHOD:
......
...@@ -198,7 +198,9 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, ...@@ -198,7 +198,9 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
acpi_status status = AE_BAD_PARAMETER; acpi_status status = AE_BAD_PARAMETER;
struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_event_info *gpe_event_info;
struct acpi_namespace_node *device_node; struct acpi_namespace_node *device_node;
struct acpi_gpe_notify_object *notify_object;
acpi_cpu_flags flags; acpi_cpu_flags flags;
u8 gpe_dispatch_mask;
ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);
...@@ -221,27 +223,49 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, ...@@ -221,27 +223,49 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
goto unlock_and_exit; goto unlock_and_exit;
} }
if (wake_device == ACPI_ROOT_OBJECT) {
goto out;
}
/* /*
* If there is no method or handler for this GPE, then the * If there is no method or handler for this GPE, then the
* wake_device will be notified whenever this GPE fires (aka * wake_device will be notified whenever this GPE fires (aka
* "implicit notify") Note: The GPE is assumed to be * "implicit notify") Note: The GPE is assumed to be
* level-triggered (for windows compatibility). * level-triggered (for windows compatibility).
*/ */
if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK;
ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) { if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE
&& gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) {
goto out;
}
/* Validate wake_device is of type Device */ /* Validate wake_device is of type Device */
device_node = ACPI_CAST_PTR(struct acpi_namespace_node, device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
wake_device);
if (device_node->type != ACPI_TYPE_DEVICE) { if (device_node->type != ACPI_TYPE_DEVICE) {
goto unlock_and_exit; goto unlock_and_exit;
} }
if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) {
gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY |
ACPI_GPE_LEVEL_TRIGGERED); ACPI_GPE_LEVEL_TRIGGERED);
gpe_event_info->dispatch.device_node = device_node; gpe_event_info->dispatch.device.node = device_node;
gpe_event_info->dispatch.device.next = NULL;
} else {
/* There are multiple devices to notify implicitly. */
notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object));
if (!notify_object) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
}
notify_object->node = device_node;
notify_object->next = gpe_event_info->dispatch.device.next;
gpe_event_info->dispatch.device.next = notify_object;
} }
out:
gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
status = AE_OK; status = AE_OK;
......
...@@ -26,7 +26,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, ...@@ -26,7 +26,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
static char *buf; static char *buf;
static int uncopied_bytes; static u32 max_size;
static u32 uncopied_bytes;
struct acpi_table_header table; struct acpi_table_header table;
acpi_status status; acpi_status status;
...@@ -37,19 +39,24 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, ...@@ -37,19 +39,24 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
if (copy_from_user(&table, user_buf, if (copy_from_user(&table, user_buf,
sizeof(struct acpi_table_header))) sizeof(struct acpi_table_header)))
return -EFAULT; return -EFAULT;
uncopied_bytes = table.length; uncopied_bytes = max_size = table.length;
buf = kzalloc(uncopied_bytes, GFP_KERNEL); buf = kzalloc(max_size, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
} }
if (uncopied_bytes < count) { if (buf == NULL)
kfree(buf); return -EINVAL;
if ((*ppos > max_size) ||
(*ppos + count > max_size) ||
(*ppos + count < count) ||
(count > uncopied_bytes))
return -EINVAL; return -EINVAL;
}
if (copy_from_user(buf + (*ppos), user_buf, count)) { if (copy_from_user(buf + (*ppos), user_buf, count)) {
kfree(buf); kfree(buf);
buf = NULL;
return -EFAULT; return -EFAULT;
} }
...@@ -59,6 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, ...@@ -59,6 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
if (!uncopied_bytes) { if (!uncopied_bytes) {
status = acpi_install_method(buf); status = acpi_install_method(buf);
kfree(buf); kfree(buf);
buf = NULL;
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -EINVAL; return -EINVAL;
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment