diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2012-04-12 23:24:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-04-16 02:56:11 -0400 |
commit | 6c7b8e82aab75a25581c4d446fc87f96634e9ef9 (patch) | |
tree | 088f31f88c85a64304c171eced7b4233cbece6a9 /arch/x86/lib/insn.c | |
parent | 7ea6411f4ceb62e5e53170d59d10996dca20c599 (diff) |
x86: Handle failures of parsing immediate operands in the instruction decoder
This can happen if the instruction is much longer than the maximum length,
or if insn->opnd_bytes is manually changed.
This patch also fixes warnings from -Wswitch-default flag.
Reported-by: Prashanth Nageshappa <prashanth@linux.vnet.ibm.com>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com>
Cc: Linux-mm <linux-mm@kvack.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Anton Arapov <anton@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: yrl.pp-manager.tt@hitachi.com
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20120413032427.32577.42602.stgit@localhost.localdomain
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/lib/insn.c')
-rw-r--r-- | arch/x86/lib/insn.c | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c index 25feb1ae71c5..b1e6c4b2e8eb 100644 --- a/arch/x86/lib/insn.c +++ b/arch/x86/lib/insn.c | |||
@@ -379,8 +379,8 @@ err_out: | |||
379 | return; | 379 | return; |
380 | } | 380 | } |
381 | 381 | ||
382 | /* Decode moffset16/32/64 */ | 382 | /* Decode moffset16/32/64. Return 0 if failed */ |
383 | static void __get_moffset(struct insn *insn) | 383 | static int __get_moffset(struct insn *insn) |
384 | { | 384 | { |
385 | switch (insn->addr_bytes) { | 385 | switch (insn->addr_bytes) { |
386 | case 2: | 386 | case 2: |
@@ -397,15 +397,19 @@ static void __get_moffset(struct insn *insn) | |||
397 | insn->moffset2.value = get_next(int, insn); | 397 | insn->moffset2.value = get_next(int, insn); |
398 | insn->moffset2.nbytes = 4; | 398 | insn->moffset2.nbytes = 4; |
399 | break; | 399 | break; |
400 | default: /* opnd_bytes must be modified manually */ | ||
401 | goto err_out; | ||
400 | } | 402 | } |
401 | insn->moffset1.got = insn->moffset2.got = 1; | 403 | insn->moffset1.got = insn->moffset2.got = 1; |
402 | 404 | ||
405 | return 1; | ||
406 | |||
403 | err_out: | 407 | err_out: |
404 | return; | 408 | return 0; |
405 | } | 409 | } |
406 | 410 | ||
407 | /* Decode imm v32(Iz) */ | 411 | /* Decode imm v32(Iz). Return 0 if failed */ |
408 | static void __get_immv32(struct insn *insn) | 412 | static int __get_immv32(struct insn *insn) |
409 | { | 413 | { |
410 | switch (insn->opnd_bytes) { | 414 | switch (insn->opnd_bytes) { |
411 | case 2: | 415 | case 2: |
@@ -417,14 +421,18 @@ static void __get_immv32(struct insn *insn) | |||
417 | insn->immediate.value = get_next(int, insn); | 421 | insn->immediate.value = get_next(int, insn); |
418 | insn->immediate.nbytes = 4; | 422 | insn->immediate.nbytes = 4; |
419 | break; | 423 | break; |
424 | default: /* opnd_bytes must be modified manually */ | ||
425 | goto err_out; | ||
420 | } | 426 | } |
421 | 427 | ||
428 | return 1; | ||
429 | |||
422 | err_out: | 430 | err_out: |
423 | return; | 431 | return 0; |
424 | } | 432 | } |
425 | 433 | ||
426 | /* Decode imm v64(Iv/Ov) */ | 434 | /* Decode imm v64(Iv/Ov), Return 0 if failed */ |
427 | static void __get_immv(struct insn *insn) | 435 | static int __get_immv(struct insn *insn) |
428 | { | 436 | { |
429 | switch (insn->opnd_bytes) { | 437 | switch (insn->opnd_bytes) { |
430 | case 2: | 438 | case 2: |
@@ -441,15 +449,18 @@ static void __get_immv(struct insn *insn) | |||
441 | insn->immediate2.value = get_next(int, insn); | 449 | insn->immediate2.value = get_next(int, insn); |
442 | insn->immediate2.nbytes = 4; | 450 | insn->immediate2.nbytes = 4; |
443 | break; | 451 | break; |
452 | default: /* opnd_bytes must be modified manually */ | ||
453 | goto err_out; | ||
444 | } | 454 | } |
445 | insn->immediate1.got = insn->immediate2.got = 1; | 455 | insn->immediate1.got = insn->immediate2.got = 1; |
446 | 456 | ||
457 | return 1; | ||
447 | err_out: | 458 | err_out: |
448 | return; | 459 | return 0; |
449 | } | 460 | } |
450 | 461 | ||
451 | /* Decode ptr16:16/32(Ap) */ | 462 | /* Decode ptr16:16/32(Ap) */ |
452 | static void __get_immptr(struct insn *insn) | 463 | static int __get_immptr(struct insn *insn) |
453 | { | 464 | { |
454 | switch (insn->opnd_bytes) { | 465 | switch (insn->opnd_bytes) { |
455 | case 2: | 466 | case 2: |
@@ -462,14 +473,17 @@ static void __get_immptr(struct insn *insn) | |||
462 | break; | 473 | break; |
463 | case 8: | 474 | case 8: |
464 | /* ptr16:64 is not exist (no segment) */ | 475 | /* ptr16:64 is not exist (no segment) */ |
465 | return; | 476 | return 0; |
477 | default: /* opnd_bytes must be modified manually */ | ||
478 | goto err_out; | ||
466 | } | 479 | } |
467 | insn->immediate2.value = get_next(unsigned short, insn); | 480 | insn->immediate2.value = get_next(unsigned short, insn); |
468 | insn->immediate2.nbytes = 2; | 481 | insn->immediate2.nbytes = 2; |
469 | insn->immediate1.got = insn->immediate2.got = 1; | 482 | insn->immediate1.got = insn->immediate2.got = 1; |
470 | 483 | ||
484 | return 1; | ||
471 | err_out: | 485 | err_out: |
472 | return; | 486 | return 0; |
473 | } | 487 | } |
474 | 488 | ||
475 | /** | 489 | /** |
@@ -489,7 +503,8 @@ void insn_get_immediate(struct insn *insn) | |||
489 | insn_get_displacement(insn); | 503 | insn_get_displacement(insn); |
490 | 504 | ||
491 | if (inat_has_moffset(insn->attr)) { | 505 | if (inat_has_moffset(insn->attr)) { |
492 | __get_moffset(insn); | 506 | if (!__get_moffset(insn)) |
507 | goto err_out; | ||
493 | goto done; | 508 | goto done; |
494 | } | 509 | } |
495 | 510 | ||
@@ -517,16 +532,20 @@ void insn_get_immediate(struct insn *insn) | |||
517 | insn->immediate2.nbytes = 4; | 532 | insn->immediate2.nbytes = 4; |
518 | break; | 533 | break; |
519 | case INAT_IMM_PTR: | 534 | case INAT_IMM_PTR: |
520 | __get_immptr(insn); | 535 | if (!__get_immptr(insn)) |
536 | goto err_out; | ||
521 | break; | 537 | break; |
522 | case INAT_IMM_VWORD32: | 538 | case INAT_IMM_VWORD32: |
523 | __get_immv32(insn); | 539 | if (!__get_immv32(insn)) |
540 | goto err_out; | ||
524 | break; | 541 | break; |
525 | case INAT_IMM_VWORD: | 542 | case INAT_IMM_VWORD: |
526 | __get_immv(insn); | 543 | if (!__get_immv(insn)) |
544 | goto err_out; | ||
527 | break; | 545 | break; |
528 | default: | 546 | default: |
529 | break; | 547 | /* Here, insn must have an immediate, but failed */ |
548 | goto err_out; | ||
530 | } | 549 | } |
531 | if (inat_has_second_immediate(insn->attr)) { | 550 | if (inat_has_second_immediate(insn->attr)) { |
532 | insn->immediate2.value = get_next(char, insn); | 551 | insn->immediate2.value = get_next(char, insn); |