aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/lib
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2012-04-12 23:24:27 -0400
committerIngo Molnar <mingo@kernel.org>2012-04-16 02:56:11 -0400
commit6c7b8e82aab75a25581c4d446fc87f96634e9ef9 (patch)
tree088f31f88c85a64304c171eced7b4233cbece6a9 /arch/x86/lib
parent7ea6411f4ceb62e5e53170d59d10996dca20c599 (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')
-rw-r--r--arch/x86/lib/insn.c53
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 */
383static void __get_moffset(struct insn *insn) 383static 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
403err_out: 407err_out:
404 return; 408 return 0;
405} 409}
406 410
407/* Decode imm v32(Iz) */ 411/* Decode imm v32(Iz). Return 0 if failed */
408static void __get_immv32(struct insn *insn) 412static 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
422err_out: 430err_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 */
427static void __get_immv(struct insn *insn) 435static 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;
447err_out: 458err_out:
448 return; 459 return 0;
449} 460}
450 461
451/* Decode ptr16:16/32(Ap) */ 462/* Decode ptr16:16/32(Ap) */
452static void __get_immptr(struct insn *insn) 463static 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;
471err_out: 485err_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);