]>
Commit | Line | Data |
---|---|---|
04fd09d4 SL |
1 | From 4762198f67971267219148d22af61719cd9110fe Mon Sep 17 00:00:00 2001 |
2 | From: Ross Lagerwall <ross.lagerwall@citrix.com> | |
3 | Date: Mon, 28 Jan 2019 10:04:24 +0000 | |
4 | Subject: efi: cper: Fix possible out-of-bounds access | |
5 | ||
6 | [ Upstream commit 45b14a4ffcc1e0b5caa246638f942cbe7eaea7ad ] | |
7 | ||
8 | When checking a generic status block, we iterate over all the generic | |
9 | data blocks. The loop condition only checks that the start of the | |
10 | generic data block is valid (within estatus->data_length) but not the | |
11 | whole block. Because the size of data blocks (excluding error data) may | |
12 | vary depending on the revision and the revision is contained within the | |
13 | data block, ensure that enough of the current data block is valid before | |
14 | dereferencing any members otherwise an out-of-bounds access may occur if | |
15 | estatus->data_length is invalid. | |
16 | ||
17 | This relies on the fact that struct acpi_hest_generic_data_v300 is a | |
18 | superset of the earlier version. Also rework the other checks to avoid | |
19 | potential underflow. | |
20 | ||
21 | Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com> | |
22 | Acked-by: Borislav Petkov <bp@suse.de> | |
23 | Tested-by: Tyler Baicar <baicar.tyler@gmail.com> | |
24 | Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | |
25 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
26 | --- | |
27 | drivers/firmware/efi/cper.c | 13 +++++++++---- | |
28 | 1 file changed, 9 insertions(+), 4 deletions(-) | |
29 | ||
30 | diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c | |
31 | index d2fcafcea07e..ce23d5402bd6 100644 | |
32 | --- a/drivers/firmware/efi/cper.c | |
33 | +++ b/drivers/firmware/efi/cper.c | |
34 | @@ -641,19 +641,24 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header); | |
35 | int cper_estatus_check(const struct acpi_hest_generic_status *estatus) | |
36 | { | |
37 | struct acpi_hest_generic_data *gdata; | |
38 | - unsigned int data_len, gedata_len; | |
39 | + unsigned int data_len, record_size; | |
40 | int rc; | |
41 | ||
42 | rc = cper_estatus_check_header(estatus); | |
43 | if (rc) | |
44 | return rc; | |
45 | + | |
46 | data_len = estatus->data_length; | |
47 | ||
48 | apei_estatus_for_each_section(estatus, gdata) { | |
49 | - gedata_len = acpi_hest_get_error_length(gdata); | |
50 | - if (gedata_len > data_len - acpi_hest_get_size(gdata)) | |
51 | + if (sizeof(struct acpi_hest_generic_data) > data_len) | |
52 | + return -EINVAL; | |
53 | + | |
54 | + record_size = acpi_hest_get_record_size(gdata); | |
55 | + if (record_size > data_len) | |
56 | return -EINVAL; | |
57 | - data_len -= acpi_hest_get_record_size(gdata); | |
58 | + | |
59 | + data_len -= record_size; | |
60 | } | |
61 | if (data_len) | |
62 | return -EINVAL; | |
63 | -- | |
64 | 2.19.1 | |
65 |