aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Axtens <dja@axtens.net>2017-07-12 17:36:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-12 19:26:03 -0400
commitc69a48cdb301a18697bc8c9935baf4f32861cf9e (patch)
tree3d680cd46b81c0af90221efe13517e011e8b61d8
parent054f367a32381b5640c5d150fe0b7ba285564998 (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.c180
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
234static void test_basic_patching(void) 234static 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
265static void test_alternative_patching(void) 265static 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
298static void test_alternative_case_too_big(void) 298static 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
324static void test_alternative_case_too_small(void) 324static 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
360static void test_alternative_case_with_branch(void) 360static 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
370static void test_alternative_case_with_external_branch(void) 370static 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
380static void test_cpu_macros(void) 380static 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
392static void test_fw_macros(void) 392static 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
406static void test_lwsync_macros(void) 406static 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