diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-02 18:26:57 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-02 18:26:57 -0500 |
| commit | ad4bfcb1cad7534ae98db3edc5415df97d3e109b (patch) | |
| tree | 6a1c2aadab56ef35d97f5cd2d21488a0016c8b98 | |
| parent | dd9c1549edef02290edced639f67b54a25abbe0e (diff) | |
| parent | 981858bd7a401aa9607d9f430d5de920025fc3ea (diff) | |
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
| -rw-r--r-- | drivers/acpi/acpica/aclocal.h | 7 | ||||
| -rw-r--r-- | drivers/acpi/acpica/evgpe.c | 17 | ||||
| -rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 42 | ||||
| -rw-r--r-- | drivers/acpi/debugfs.c | 20 |
4 files changed, 66 insertions, 20 deletions
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 54784bb42ce..edc25867ad9 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
| @@ -416,10 +416,15 @@ struct acpi_gpe_handler_info { | |||
| 416 | u8 originally_enabled; /* True if GPE was originally enabled */ | 416 | u8 originally_enabled; /* True if GPE was originally enabled */ |
| 417 | }; | 417 | }; |
| 418 | 418 | ||
| 419 | struct acpi_gpe_notify_object { | ||
| 420 | struct acpi_namespace_node *node; | ||
| 421 | struct acpi_gpe_notify_object *next; | ||
| 422 | }; | ||
| 423 | |||
| 419 | union acpi_gpe_dispatch_info { | 424 | union acpi_gpe_dispatch_info { |
| 420 | struct acpi_namespace_node *method_node; /* Method node for this GPE level */ | 425 | struct acpi_namespace_node *method_node; /* Method node for this GPE level */ |
| 421 | struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ | 426 | struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ |
| 422 | struct acpi_namespace_node *device_node; /* Parent _PRW device for implicit notify */ | 427 | struct acpi_gpe_notify_object device; /* List of _PRW devices for implicit notify */ |
| 423 | }; | 428 | }; |
| 424 | 429 | ||
| 425 | /* | 430 | /* |
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 14988a86066..f4725212eb4 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c | |||
| @@ -457,6 +457,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
| 457 | acpi_status status; | 457 | acpi_status status; |
| 458 | struct acpi_gpe_event_info *local_gpe_event_info; | 458 | struct acpi_gpe_event_info *local_gpe_event_info; |
| 459 | struct acpi_evaluate_info *info; | 459 | struct acpi_evaluate_info *info; |
| 460 | struct acpi_gpe_notify_object *notify_object; | ||
| 460 | 461 | ||
| 461 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); | 462 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); |
| 462 | 463 | ||
| @@ -508,10 +509,18 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
| 508 | * from this thread -- because handlers may in turn run other | 509 | * from this thread -- because handlers may in turn run other |
| 509 | * control methods. | 510 | * control methods. |
| 510 | */ | 511 | */ |
| 511 | status = | 512 | status = acpi_ev_queue_notify_request( |
| 512 | acpi_ev_queue_notify_request(local_gpe_event_info->dispatch. | 513 | local_gpe_event_info->dispatch.device.node, |
| 513 | device_node, | 514 | ACPI_NOTIFY_DEVICE_WAKE); |
| 514 | ACPI_NOTIFY_DEVICE_WAKE); | 515 | |
| 516 | notify_object = local_gpe_event_info->dispatch.device.next; | ||
| 517 | while (ACPI_SUCCESS(status) && notify_object) { | ||
| 518 | status = acpi_ev_queue_notify_request( | ||
| 519 | notify_object->node, | ||
| 520 | ACPI_NOTIFY_DEVICE_WAKE); | ||
| 521 | notify_object = notify_object->next; | ||
| 522 | } | ||
| 523 | |||
| 515 | break; | 524 | break; |
| 516 | 525 | ||
| 517 | case ACPI_GPE_DISPATCH_METHOD: | 526 | case ACPI_GPE_DISPATCH_METHOD: |
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 3b20a3401b6..52aaff3df56 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c | |||
| @@ -198,7 +198,9 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, | |||
| 198 | acpi_status status = AE_BAD_PARAMETER; | 198 | acpi_status status = AE_BAD_PARAMETER; |
| 199 | struct acpi_gpe_event_info *gpe_event_info; | 199 | struct acpi_gpe_event_info *gpe_event_info; |
| 200 | struct acpi_namespace_node *device_node; | 200 | struct acpi_namespace_node *device_node; |
| 201 | struct acpi_gpe_notify_object *notify_object; | ||
| 201 | acpi_cpu_flags flags; | 202 | acpi_cpu_flags flags; |
| 203 | u8 gpe_dispatch_mask; | ||
| 202 | 204 | ||
| 203 | ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); | 205 | ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); |
| 204 | 206 | ||
| @@ -221,27 +223,49 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, | |||
| 221 | goto unlock_and_exit; | 223 | goto unlock_and_exit; |
| 222 | } | 224 | } |
| 223 | 225 | ||
| 226 | if (wake_device == ACPI_ROOT_OBJECT) { | ||
| 227 | goto out; | ||
| 228 | } | ||
| 229 | |||
| 224 | /* | 230 | /* |
| 225 | * If there is no method or handler for this GPE, then the | 231 | * If there is no method or handler for this GPE, then the |
| 226 | * wake_device will be notified whenever this GPE fires (aka | 232 | * wake_device will be notified whenever this GPE fires (aka |
| 227 | * "implicit notify") Note: The GPE is assumed to be | 233 | * "implicit notify") Note: The GPE is assumed to be |
| 228 | * level-triggered (for windows compatibility). | 234 | * level-triggered (for windows compatibility). |
| 229 | */ | 235 | */ |
| 230 | if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == | 236 | gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK; |
| 231 | ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) { | 237 | if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE |
| 238 | && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) { | ||
| 239 | goto out; | ||
| 240 | } | ||
| 232 | 241 | ||
| 233 | /* Validate wake_device is of type Device */ | 242 | /* Validate wake_device is of type Device */ |
| 234 | 243 | ||
| 235 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, | 244 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); |
| 236 | wake_device); | 245 | if (device_node->type != ACPI_TYPE_DEVICE) { |
| 237 | if (device_node->type != ACPI_TYPE_DEVICE) { | 246 | goto unlock_and_exit; |
| 238 | goto unlock_and_exit; | 247 | } |
| 239 | } | 248 | |
| 249 | if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) { | ||
| 240 | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | | 250 | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | |
| 241 | ACPI_GPE_LEVEL_TRIGGERED); | 251 | ACPI_GPE_LEVEL_TRIGGERED); |
| 242 | gpe_event_info->dispatch.device_node = device_node; | 252 | gpe_event_info->dispatch.device.node = device_node; |
| 253 | gpe_event_info->dispatch.device.next = NULL; | ||
| 254 | } else { | ||
| 255 | /* There are multiple devices to notify implicitly. */ | ||
| 256 | |||
| 257 | notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object)); | ||
| 258 | if (!notify_object) { | ||
| 259 | status = AE_NO_MEMORY; | ||
| 260 | goto unlock_and_exit; | ||
| 261 | } | ||
| 262 | |||
| 263 | notify_object->node = device_node; | ||
| 264 | notify_object->next = gpe_event_info->dispatch.device.next; | ||
| 265 | gpe_event_info->dispatch.device.next = notify_object; | ||
| 243 | } | 266 | } |
| 244 | 267 | ||
| 268 | out: | ||
| 245 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; | 269 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; |
| 246 | status = AE_OK; | 270 | status = AE_OK; |
| 247 | 271 | ||
diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index 5df67f1d6c6..384f7abcff7 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c | |||
| @@ -26,7 +26,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
| 26 | size_t count, loff_t *ppos) | 26 | size_t count, loff_t *ppos) |
| 27 | { | 27 | { |
| 28 | static char *buf; | 28 | static char *buf; |
| 29 | static int uncopied_bytes; | 29 | static u32 max_size; |
| 30 | static u32 uncopied_bytes; | ||
| 31 | |||
| 30 | struct acpi_table_header table; | 32 | struct acpi_table_header table; |
| 31 | acpi_status status; | 33 | acpi_status status; |
| 32 | 34 | ||
| @@ -37,19 +39,24 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
| 37 | if (copy_from_user(&table, user_buf, | 39 | if (copy_from_user(&table, user_buf, |
| 38 | sizeof(struct acpi_table_header))) | 40 | sizeof(struct acpi_table_header))) |
| 39 | return -EFAULT; | 41 | return -EFAULT; |
| 40 | uncopied_bytes = table.length; | 42 | uncopied_bytes = max_size = table.length; |
| 41 | buf = kzalloc(uncopied_bytes, GFP_KERNEL); | 43 | buf = kzalloc(max_size, GFP_KERNEL); |
| 42 | if (!buf) | 44 | if (!buf) |
| 43 | return -ENOMEM; | 45 | return -ENOMEM; |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | if (uncopied_bytes < count) { | 48 | if (buf == NULL) |
| 47 | kfree(buf); | 49 | return -EINVAL; |
| 50 | |||
| 51 | if ((*ppos > max_size) || | ||
| 52 | (*ppos + count > max_size) || | ||
| 53 | (*ppos + count < count) || | ||
| 54 | (count > uncopied_bytes)) | ||
| 48 | return -EINVAL; | 55 | return -EINVAL; |
| 49 | } | ||
| 50 | 56 | ||
| 51 | if (copy_from_user(buf + (*ppos), user_buf, count)) { | 57 | if (copy_from_user(buf + (*ppos), user_buf, count)) { |
| 52 | kfree(buf); | 58 | kfree(buf); |
| 59 | buf = NULL; | ||
| 53 | return -EFAULT; | 60 | return -EFAULT; |
| 54 | } | 61 | } |
| 55 | 62 | ||
| @@ -59,6 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
| 59 | if (!uncopied_bytes) { | 66 | if (!uncopied_bytes) { |
| 60 | status = acpi_install_method(buf); | 67 | status = acpi_install_method(buf); |
| 61 | kfree(buf); | 68 | kfree(buf); |
| 69 | buf = NULL; | ||
| 62 | if (ACPI_FAILURE(status)) | 70 | if (ACPI_FAILURE(status)) |
| 63 | return -EINVAL; | 71 | return -EINVAL; |
| 64 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); | 72 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); |
