diff options
author | Marcin Slusarz <marcin.slusarz@gmail.com> | 2012-10-21 19:59:20 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-21 22:26:46 -0400 |
commit | 00e4845bad84689fbaacc86bc54a0b99d5d3c1fc (patch) | |
tree | a7fa743dbd353225e82d7bb029b8fcbe6743b3f0 /drivers | |
parent | 0bab097a9b18d7ad1a65c9263b3f896fc1f4b6ff (diff) |
drm/nouveau: validate vbios size
Without checking, we could detect vbios size as 0, allocate 0-byte array
(kmalloc returns invalid pointer for such allocation) and crash in
nouveau_bios_score while checking for vbios signature.
Reported-by: Heinz Diehl <htd@fritha.org>
Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/bios/base.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index f65bfedcce66..3a84ad4f171a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c | |||
@@ -72,7 +72,7 @@ nouveau_bios_shadow_of(struct nouveau_bios *bios) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | data = of_get_property(dn, "NVDA,BMP", &size); | 74 | data = of_get_property(dn, "NVDA,BMP", &size); |
75 | if (data) { | 75 | if (data && size) { |
76 | bios->size = size; | 76 | bios->size = size; |
77 | bios->data = kmalloc(bios->size, GFP_KERNEL); | 77 | bios->data = kmalloc(bios->size, GFP_KERNEL); |
78 | if (bios->data) | 78 | if (bios->data) |
@@ -104,6 +104,9 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios) | |||
104 | goto out; | 104 | goto out; |
105 | 105 | ||
106 | bios->size = nv_rd08(bios, 0x700002) * 512; | 106 | bios->size = nv_rd08(bios, 0x700002) * 512; |
107 | if (!bios->size) | ||
108 | goto out; | ||
109 | |||
107 | bios->data = kmalloc(bios->size, GFP_KERNEL); | 110 | bios->data = kmalloc(bios->size, GFP_KERNEL); |
108 | if (bios->data) { | 111 | if (bios->data) { |
109 | for (i = 0; i < bios->size; i++) | 112 | for (i = 0; i < bios->size; i++) |
@@ -155,6 +158,9 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) | |||
155 | 158 | ||
156 | /* read entire bios image to system memory */ | 159 | /* read entire bios image to system memory */ |
157 | bios->size = nv_rd08(bios, 0x300002) * 512; | 160 | bios->size = nv_rd08(bios, 0x300002) * 512; |
161 | if (!bios->size) | ||
162 | goto out; | ||
163 | |||
158 | bios->data = kmalloc(bios->size, GFP_KERNEL); | 164 | bios->data = kmalloc(bios->size, GFP_KERNEL); |
159 | if (bios->data) { | 165 | if (bios->data) { |
160 | for (i = 0; i < bios->size; i++) | 166 | for (i = 0; i < bios->size; i++) |
@@ -196,6 +202,8 @@ nouveau_bios_shadow_acpi(struct nouveau_bios *bios) | |||
196 | bios->size = 0; | 202 | bios->size = 0; |
197 | if (nouveau_acpi_get_bios_chunk(data, 0, 3) == 3) | 203 | if (nouveau_acpi_get_bios_chunk(data, 0, 3) == 3) |
198 | bios->size = data[2] * 512; | 204 | bios->size = data[2] * 512; |
205 | if (!bios->size) | ||
206 | return; | ||
199 | 207 | ||
200 | bios->data = kmalloc(bios->size, GFP_KERNEL); | 208 | bios->data = kmalloc(bios->size, GFP_KERNEL); |
201 | for (i = 0; bios->data && i < bios->size; i += cnt) { | 209 | for (i = 0; bios->data && i < bios->size; i += cnt) { |
@@ -231,12 +239,14 @@ nouveau_bios_shadow_pci(struct nouveau_bios *bios) | |||
231 | static int | 239 | static int |
232 | nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) | 240 | nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) |
233 | { | 241 | { |
234 | if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) { | 242 | if (bios->size < 3 || !bios->data || bios->data[0] != 0x55 || |
243 | bios->data[1] != 0xAA) { | ||
235 | nv_info(bios, "... signature not found\n"); | 244 | nv_info(bios, "... signature not found\n"); |
236 | return 0; | 245 | return 0; |
237 | } | 246 | } |
238 | 247 | ||
239 | if (nvbios_checksum(bios->data, bios->data[2] * 512)) { | 248 | if (nvbios_checksum(bios->data, |
249 | min_t(u32, bios->data[2] * 512, bios->size))) { | ||
240 | nv_info(bios, "... checksum invalid\n"); | 250 | nv_info(bios, "... checksum invalid\n"); |
241 | /* if a ro image is somewhat bad, it's probably all rubbish */ | 251 | /* if a ro image is somewhat bad, it's probably all rubbish */ |
242 | return writeable ? 2 : 1; | 252 | return writeable ? 2 : 1; |