diff options
author | Daniel Axtens <dja@axtens.net> | 2017-07-12 17:36:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-12 19:26:03 -0400 |
commit | c69a48cdb301a18697bc8c9935baf4f32861cf9e (patch) | |
tree | 3d680cd46b81c0af90221efe13517e011e8b61d8 | |
parent | 054f367a32381b5640c5d150fe0b7ba285564998 (diff) |
powerpc: make feature-fixup tests fortify-safe
Testing the fortified string functions[1] would cause a kernel panic on
boot in test_feature_fixups() due to a buffer overflow in memcmp.
This boils down to things like this:
extern unsigned int ftr_fixup_test1;
extern unsigned int ftr_fixup_test1_orig;
check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
We know that these are asm labels so it is safe to read up to 'size'
bytes at those addresses.
However, because we have passed the address of a single unsigned int to
memcmp, the compiler believes the underlying object is in fact a single
unsigned int. So if size > sizeof(unsigned int), there will be a panic
at runtime.
We can fix this by changing the types: instead of calling the asm labels
unsigned ints, call them unsigned int[]s. Therefore the size isn't
incorrectly determined at compile time and we get a regular unsafe
memcmp and no panic.
[1] http://openwall.com/lists/kernel-hardening/2017/05/09/2
Link: http://lkml.kernel.org/r/1497903987-21002-7-git-send-email-keescook@chromium.org
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Kees Cook <keescook@chromium.org>
Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Tested-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Daniel Micay <danielmicay@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/powerpc/lib/feature-fixups.c | 180 |
1 files changed, 90 insertions, 90 deletions
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index f3917705c686..41cf5ae273cf 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c | |||
@@ -233,192 +233,192 @@ static long calc_offset(struct fixup_entry *entry, unsigned int *p) | |||
233 | 233 | ||
234 | static void test_basic_patching(void) | 234 | static void test_basic_patching(void) |
235 | { | 235 | { |
236 | extern unsigned int ftr_fixup_test1; | 236 | extern unsigned int ftr_fixup_test1[]; |
237 | extern unsigned int end_ftr_fixup_test1; | 237 | extern unsigned int end_ftr_fixup_test1[]; |
238 | extern unsigned int ftr_fixup_test1_orig; | 238 | extern unsigned int ftr_fixup_test1_orig[]; |
239 | extern unsigned int ftr_fixup_test1_expected; | 239 | extern unsigned int ftr_fixup_test1_expected[]; |
240 | int size = &end_ftr_fixup_test1 - &ftr_fixup_test1; | 240 | int size = end_ftr_fixup_test1 - ftr_fixup_test1; |
241 | 241 | ||
242 | fixup.value = fixup.mask = 8; | 242 | fixup.value = fixup.mask = 8; |
243 | fixup.start_off = calc_offset(&fixup, &ftr_fixup_test1 + 1); | 243 | fixup.start_off = calc_offset(&fixup, ftr_fixup_test1 + 1); |
244 | fixup.end_off = calc_offset(&fixup, &ftr_fixup_test1 + 2); | 244 | fixup.end_off = calc_offset(&fixup, ftr_fixup_test1 + 2); |
245 | fixup.alt_start_off = fixup.alt_end_off = 0; | 245 | fixup.alt_start_off = fixup.alt_end_off = 0; |
246 | 246 | ||
247 | /* Sanity check */ | 247 | /* Sanity check */ |
248 | check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0); | 248 | check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0); |
249 | 249 | ||
250 | /* Check we don't patch if the value matches */ | 250 | /* Check we don't patch if the value matches */ |
251 | patch_feature_section(8, &fixup); | 251 | patch_feature_section(8, &fixup); |
252 | check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0); | 252 | check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0); |
253 | 253 | ||
254 | /* Check we do patch if the value doesn't match */ | 254 | /* Check we do patch if the value doesn't match */ |
255 | patch_feature_section(0, &fixup); | 255 | patch_feature_section(0, &fixup); |
256 | check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0); | 256 | check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0); |
257 | 257 | ||
258 | /* Check we do patch if the mask doesn't match */ | 258 | /* Check we do patch if the mask doesn't match */ |
259 | memcpy(&ftr_fixup_test1, &ftr_fixup_test1_orig, size); | 259 | memcpy(ftr_fixup_test1, ftr_fixup_test1_orig, size); |
260 | check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0); | 260 | check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0); |
261 | patch_feature_section(~8, &fixup); | 261 | patch_feature_section(~8, &fixup); |
262 | check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0); | 262 | check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0); |
263 | } | 263 | } |
264 | 264 | ||
265 | static void test_alternative_patching(void) | 265 | static void test_alternative_patching(void) |
266 | { | 266 | { |
267 | extern unsigned int ftr_fixup_test2; | 267 | extern unsigned int ftr_fixup_test2[]; |
268 | extern unsigned int end_ftr_fixup_test2; | 268 | extern unsigned int end_ftr_fixup_test2[]; |
269 | extern unsigned int ftr_fixup_test2_orig; | 269 | extern unsigned int ftr_fixup_test2_orig[]; |
270 | extern unsigned int ftr_fixup_test2_alt; | 270 | extern unsigned int ftr_fixup_test2_alt[]; |
271 | extern unsigned int ftr_fixup_test2_expected; | 271 | extern unsigned int ftr_fixup_test2_expected[]; |
272 | int size = &end_ftr_fixup_test2 - &ftr_fixup_test2; | 272 | int size = end_ftr_fixup_test2 - ftr_fixup_test2; |
273 | 273 | ||
274 | fixup.value = fixup.mask = 0xF; | 274 | fixup.value = fixup.mask = 0xF; |
275 | fixup.start_off = calc_offset(&fixup, &ftr_fixup_test2 + 1); | 275 | fixup.start_off = calc_offset(&fixup, ftr_fixup_test2 + 1); |
276 | fixup.end_off = calc_offset(&fixup, &ftr_fixup_test2 + 2); | 276 | fixup.end_off = calc_offset(&fixup, ftr_fixup_test2 + 2); |
277 | fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test2_alt); | 277 | fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test2_alt); |
278 | fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test2_alt + 1); | 278 | fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test2_alt + 1); |
279 | 279 | ||
280 | /* Sanity check */ | 280 | /* Sanity check */ |
281 | check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0); | 281 | check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0); |
282 | 282 | ||
283 | /* Check we don't patch if the value matches */ | 283 | /* Check we don't patch if the value matches */ |
284 | patch_feature_section(0xF, &fixup); | 284 | patch_feature_section(0xF, &fixup); |
285 | check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0); | 285 | check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0); |
286 | 286 | ||
287 | /* Check we do patch if the value doesn't match */ | 287 | /* Check we do patch if the value doesn't match */ |
288 | patch_feature_section(0, &fixup); | 288 | patch_feature_section(0, &fixup); |
289 | check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0); | 289 | check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0); |
290 | 290 | ||
291 | /* Check we do patch if the mask doesn't match */ | 291 | /* Check we do patch if the mask doesn't match */ |
292 | memcpy(&ftr_fixup_test2, &ftr_fixup_test2_orig, size); | 292 | memcpy(ftr_fixup_test2, ftr_fixup_test2_orig, size); |
293 | check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0); | 293 | check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0); |
294 | patch_feature_section(~0xF, &fixup); | 294 | patch_feature_section(~0xF, &fixup); |
295 | check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0); | 295 | check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0); |
296 | } | 296 | } |
297 | 297 | ||
298 | static void test_alternative_case_too_big(void) | 298 | static void test_alternative_case_too_big(void) |
299 | { | 299 | { |
300 | extern unsigned int ftr_fixup_test3; | 300 | extern unsigned int ftr_fixup_test3[]; |
301 | extern unsigned int end_ftr_fixup_test3; | 301 | extern unsigned int end_ftr_fixup_test3[]; |
302 | extern unsigned int ftr_fixup_test3_orig; | 302 | extern unsigned int ftr_fixup_test3_orig[]; |
303 | extern unsigned int ftr_fixup_test3_alt; | 303 | extern unsigned int ftr_fixup_test3_alt[]; |
304 | int size = &end_ftr_fixup_test3 - &ftr_fixup_test3; | 304 | int size = end_ftr_fixup_test3 - ftr_fixup_test3; |
305 | 305 | ||
306 | fixup.value = fixup.mask = 0xC; | 306 | fixup.value = fixup.mask = 0xC; |
307 | fixup.start_off = calc_offset(&fixup, &ftr_fixup_test3 + 1); | 307 | fixup.start_off = calc_offset(&fixup, ftr_fixup_test3 + 1); |
308 | fixup.end_off = calc_offset(&fixup, &ftr_fixup_test3 + 2); | 308 | fixup.end_off = calc_offset(&fixup, ftr_fixup_test3 + 2); |
309 | fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test3_alt); | 309 | fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test3_alt); |
310 | fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test3_alt + 2); | 310 | fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test3_alt + 2); |
311 | 311 | ||
312 | /* Sanity check */ | 312 | /* Sanity check */ |
313 | check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0); | 313 | check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); |
314 | 314 | ||
315 | /* Expect nothing to be patched, and the error returned to us */ | 315 | /* Expect nothing to be patched, and the error returned to us */ |
316 | check(patch_feature_section(0xF, &fixup) == 1); | 316 | check(patch_feature_section(0xF, &fixup) == 1); |
317 | check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0); | 317 | check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); |
318 | check(patch_feature_section(0, &fixup) == 1); | 318 | check(patch_feature_section(0, &fixup) == 1); |
319 | check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0); | 319 | check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); |
320 | check(patch_feature_section(~0xF, &fixup) == 1); | 320 | check(patch_feature_section(~0xF, &fixup) == 1); |
321 | check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0); | 321 | check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); |
322 | } | 322 | } |
323 | 323 | ||
324 | static void test_alternative_case_too_small(void) | 324 | static void test_alternative_case_too_small(void) |
325 | { | 325 | { |
326 | extern unsigned int ftr_fixup_test4; | 326 | extern unsigned int ftr_fixup_test4[]; |
327 | extern unsigned int end_ftr_fixup_test4; | 327 | extern unsigned int end_ftr_fixup_test4[]; |
328 | extern unsigned int ftr_fixup_test4_orig; | 328 | extern unsigned int ftr_fixup_test4_orig[]; |
329 | extern unsigned int ftr_fixup_test4_alt; | 329 | extern unsigned int ftr_fixup_test4_alt[]; |
330 | extern unsigned int ftr_fixup_test4_expected; | 330 | extern unsigned int ftr_fixup_test4_expected[]; |
331 | int size = &end_ftr_fixup_test4 - &ftr_fixup_test4; | 331 | int size = end_ftr_fixup_test4 - ftr_fixup_test4; |
332 | unsigned long flag; | 332 | unsigned long flag; |
333 | 333 | ||
334 | /* Check a high-bit flag */ | 334 | /* Check a high-bit flag */ |
335 | flag = 1UL << ((sizeof(unsigned long) - 1) * 8); | 335 | flag = 1UL << ((sizeof(unsigned long) - 1) * 8); |
336 | fixup.value = fixup.mask = flag; | 336 | fixup.value = fixup.mask = flag; |
337 | fixup.start_off = calc_offset(&fixup, &ftr_fixup_test4 + 1); | 337 | fixup.start_off = calc_offset(&fixup, ftr_fixup_test4 + 1); |
338 | fixup.end_off = calc_offset(&fixup, &ftr_fixup_test4 + 5); | 338 | fixup.end_off = calc_offset(&fixup, ftr_fixup_test4 + 5); |
339 | fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test4_alt); | 339 | fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test4_alt); |
340 | fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test4_alt + 2); | 340 | fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test4_alt + 2); |
341 | 341 | ||
342 | /* Sanity check */ | 342 | /* Sanity check */ |
343 | check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0); | 343 | check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0); |
344 | 344 | ||
345 | /* Check we don't patch if the value matches */ | 345 | /* Check we don't patch if the value matches */ |
346 | patch_feature_section(flag, &fixup); | 346 | patch_feature_section(flag, &fixup); |
347 | check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0); | 347 | check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0); |
348 | 348 | ||
349 | /* Check we do patch if the value doesn't match */ | 349 | /* Check we do patch if the value doesn't match */ |
350 | patch_feature_section(0, &fixup); | 350 | patch_feature_section(0, &fixup); |
351 | check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0); | 351 | check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0); |
352 | 352 | ||
353 | /* Check we do patch if the mask doesn't match */ | 353 | /* Check we do patch if the mask doesn't match */ |
354 | memcpy(&ftr_fixup_test4, &ftr_fixup_test4_orig, size); | 354 | memcpy(ftr_fixup_test4, ftr_fixup_test4_orig, size); |
355 | check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0); | 355 | check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0); |
356 | patch_feature_section(~flag, &fixup); | 356 | patch_feature_section(~flag, &fixup); |
357 | check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0); | 357 | check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0); |
358 | } | 358 | } |
359 | 359 | ||
360 | static void test_alternative_case_with_branch(void) | 360 | static void test_alternative_case_with_branch(void) |
361 | { | 361 | { |
362 | extern unsigned int ftr_fixup_test5; | 362 | extern unsigned int ftr_fixup_test5[]; |
363 | extern unsigned int end_ftr_fixup_test5; | 363 | extern unsigned int end_ftr_fixup_test5[]; |
364 | extern unsigned int ftr_fixup_test5_expected; | 364 | extern unsigned int ftr_fixup_test5_expected[]; |
365 | int size = &end_ftr_fixup_test5 - &ftr_fixup_test5; | 365 | int size = end_ftr_fixup_test5 - ftr_fixup_test5; |
366 | 366 | ||
367 | check(memcmp(&ftr_fixup_test5, &ftr_fixup_test5_expected, size) == 0); | 367 | check(memcmp(ftr_fixup_test5, ftr_fixup_test5_expected, size) == 0); |
368 | } | 368 | } |
369 | 369 | ||
370 | static void test_alternative_case_with_external_branch(void) | 370 | static void test_alternative_case_with_external_branch(void) |
371 | { | 371 | { |
372 | extern unsigned int ftr_fixup_test6; | 372 | extern unsigned int ftr_fixup_test6[]; |
373 | extern unsigned int end_ftr_fixup_test6; | 373 | extern unsigned int end_ftr_fixup_test6[]; |
374 | extern unsigned int ftr_fixup_test6_expected; | 374 | extern unsigned int ftr_fixup_test6_expected[]; |
375 | int size = &end_ftr_fixup_test6 - &ftr_fixup_test6; | 375 | int size = end_ftr_fixup_test6 - ftr_fixup_test6; |
376 | 376 | ||
377 | check(memcmp(&ftr_fixup_test6, &ftr_fixup_test6_expected, size) == 0); | 377 | check(memcmp(ftr_fixup_test6, ftr_fixup_test6_expected, size) == 0); |
378 | } | 378 | } |
379 | 379 | ||
380 | static void test_cpu_macros(void) | 380 | static void test_cpu_macros(void) |
381 | { | 381 | { |
382 | extern u8 ftr_fixup_test_FTR_macros; | 382 | extern u8 ftr_fixup_test_FTR_macros[]; |
383 | extern u8 ftr_fixup_test_FTR_macros_expected; | 383 | extern u8 ftr_fixup_test_FTR_macros_expected[]; |
384 | unsigned long size = &ftr_fixup_test_FTR_macros_expected - | 384 | unsigned long size = ftr_fixup_test_FTR_macros_expected - |
385 | &ftr_fixup_test_FTR_macros; | 385 | ftr_fixup_test_FTR_macros; |
386 | 386 | ||
387 | /* The fixups have already been done for us during boot */ | 387 | /* The fixups have already been done for us during boot */ |
388 | check(memcmp(&ftr_fixup_test_FTR_macros, | 388 | check(memcmp(ftr_fixup_test_FTR_macros, |
389 | &ftr_fixup_test_FTR_macros_expected, size) == 0); | 389 | ftr_fixup_test_FTR_macros_expected, size) == 0); |
390 | } | 390 | } |
391 | 391 | ||
392 | static void test_fw_macros(void) | 392 | static void test_fw_macros(void) |
393 | { | 393 | { |
394 | #ifdef CONFIG_PPC64 | 394 | #ifdef CONFIG_PPC64 |
395 | extern u8 ftr_fixup_test_FW_FTR_macros; | 395 | extern u8 ftr_fixup_test_FW_FTR_macros[]; |
396 | extern u8 ftr_fixup_test_FW_FTR_macros_expected; | 396 | extern u8 ftr_fixup_test_FW_FTR_macros_expected[]; |
397 | unsigned long size = &ftr_fixup_test_FW_FTR_macros_expected - | 397 | unsigned long size = ftr_fixup_test_FW_FTR_macros_expected - |
398 | &ftr_fixup_test_FW_FTR_macros; | 398 | ftr_fixup_test_FW_FTR_macros; |
399 | 399 | ||
400 | /* The fixups have already been done for us during boot */ | 400 | /* The fixups have already been done for us during boot */ |
401 | check(memcmp(&ftr_fixup_test_FW_FTR_macros, | 401 | check(memcmp(ftr_fixup_test_FW_FTR_macros, |
402 | &ftr_fixup_test_FW_FTR_macros_expected, size) == 0); | 402 | ftr_fixup_test_FW_FTR_macros_expected, size) == 0); |
403 | #endif | 403 | #endif |
404 | } | 404 | } |
405 | 405 | ||
406 | static void test_lwsync_macros(void) | 406 | static void test_lwsync_macros(void) |
407 | { | 407 | { |
408 | extern u8 lwsync_fixup_test; | 408 | extern u8 lwsync_fixup_test[]; |
409 | extern u8 end_lwsync_fixup_test; | 409 | extern u8 end_lwsync_fixup_test[]; |
410 | extern u8 lwsync_fixup_test_expected_LWSYNC; | 410 | extern u8 lwsync_fixup_test_expected_LWSYNC[]; |
411 | extern u8 lwsync_fixup_test_expected_SYNC; | 411 | extern u8 lwsync_fixup_test_expected_SYNC[]; |
412 | unsigned long size = &end_lwsync_fixup_test - | 412 | unsigned long size = end_lwsync_fixup_test - |
413 | &lwsync_fixup_test; | 413 | lwsync_fixup_test; |
414 | 414 | ||
415 | /* The fixups have already been done for us during boot */ | 415 | /* The fixups have already been done for us during boot */ |
416 | if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) { | 416 | if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) { |
417 | check(memcmp(&lwsync_fixup_test, | 417 | check(memcmp(lwsync_fixup_test, |
418 | &lwsync_fixup_test_expected_LWSYNC, size) == 0); | 418 | lwsync_fixup_test_expected_LWSYNC, size) == 0); |
419 | } else { | 419 | } else { |
420 | check(memcmp(&lwsync_fixup_test, | 420 | check(memcmp(lwsync_fixup_test, |
421 | &lwsync_fixup_test_expected_SYNC, size) == 0); | 421 | lwsync_fixup_test_expected_SYNC, size) == 0); |
422 | } | 422 | } |
423 | } | 423 | } |
424 | 424 | ||