Skip to content

Commit 6c7b8e8

Browse files
mhiramathitachiIngo Molnar
authored andcommitted
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 <[email protected]> Signed-off-by: Masami Hiramatsu <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Ananth N Mavinakayanahalli <[email protected]> Cc: Jim Keniston <[email protected]> Cc: Linux-mm <[email protected]> Cc: Oleg Nesterov <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Anton Arapov <[email protected]> Cc: Srikar Dronamraju <[email protected]> Cc: [email protected] Cc: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 7ea6411 commit 6c7b8e8

File tree

1 file changed

+36
-17
lines changed

1 file changed

+36
-17
lines changed

arch/x86/lib/insn.c

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,8 @@ void insn_get_displacement(struct insn *insn)
379379
return;
380380
}
381381

382-
/* Decode moffset16/32/64 */
383-
static void __get_moffset(struct insn *insn)
382+
/* Decode moffset16/32/64. Return 0 if failed */
383+
static int __get_moffset(struct insn *insn)
384384
{
385385
switch (insn->addr_bytes) {
386386
case 2:
@@ -397,15 +397,19 @@ static void __get_moffset(struct insn *insn)
397397
insn->moffset2.value = get_next(int, insn);
398398
insn->moffset2.nbytes = 4;
399399
break;
400+
default: /* opnd_bytes must be modified manually */
401+
goto err_out;
400402
}
401403
insn->moffset1.got = insn->moffset2.got = 1;
402404

405+
return 1;
406+
403407
err_out:
404-
return;
408+
return 0;
405409
}
406410

407-
/* Decode imm v32(Iz) */
408-
static void __get_immv32(struct insn *insn)
411+
/* Decode imm v32(Iz). Return 0 if failed */
412+
static int __get_immv32(struct insn *insn)
409413
{
410414
switch (insn->opnd_bytes) {
411415
case 2:
@@ -417,14 +421,18 @@ static void __get_immv32(struct insn *insn)
417421
insn->immediate.value = get_next(int, insn);
418422
insn->immediate.nbytes = 4;
419423
break;
424+
default: /* opnd_bytes must be modified manually */
425+
goto err_out;
420426
}
421427

428+
return 1;
429+
422430
err_out:
423-
return;
431+
return 0;
424432
}
425433

426-
/* Decode imm v64(Iv/Ov) */
427-
static void __get_immv(struct insn *insn)
434+
/* Decode imm v64(Iv/Ov), Return 0 if failed */
435+
static int __get_immv(struct insn *insn)
428436
{
429437
switch (insn->opnd_bytes) {
430438
case 2:
@@ -441,15 +449,18 @@ static void __get_immv(struct insn *insn)
441449
insn->immediate2.value = get_next(int, insn);
442450
insn->immediate2.nbytes = 4;
443451
break;
452+
default: /* opnd_bytes must be modified manually */
453+
goto err_out;
444454
}
445455
insn->immediate1.got = insn->immediate2.got = 1;
446456

457+
return 1;
447458
err_out:
448-
return;
459+
return 0;
449460
}
450461

451462
/* Decode ptr16:16/32(Ap) */
452-
static void __get_immptr(struct insn *insn)
463+
static int __get_immptr(struct insn *insn)
453464
{
454465
switch (insn->opnd_bytes) {
455466
case 2:
@@ -462,14 +473,17 @@ static void __get_immptr(struct insn *insn)
462473
break;
463474
case 8:
464475
/* ptr16:64 is not exist (no segment) */
465-
return;
476+
return 0;
477+
default: /* opnd_bytes must be modified manually */
478+
goto err_out;
466479
}
467480
insn->immediate2.value = get_next(unsigned short, insn);
468481
insn->immediate2.nbytes = 2;
469482
insn->immediate1.got = insn->immediate2.got = 1;
470483

484+
return 1;
471485
err_out:
472-
return;
486+
return 0;
473487
}
474488

475489
/**
@@ -489,7 +503,8 @@ void insn_get_immediate(struct insn *insn)
489503
insn_get_displacement(insn);
490504

491505
if (inat_has_moffset(insn->attr)) {
492-
__get_moffset(insn);
506+
if (!__get_moffset(insn))
507+
goto err_out;
493508
goto done;
494509
}
495510

@@ -517,16 +532,20 @@ void insn_get_immediate(struct insn *insn)
517532
insn->immediate2.nbytes = 4;
518533
break;
519534
case INAT_IMM_PTR:
520-
__get_immptr(insn);
535+
if (!__get_immptr(insn))
536+
goto err_out;
521537
break;
522538
case INAT_IMM_VWORD32:
523-
__get_immv32(insn);
539+
if (!__get_immv32(insn))
540+
goto err_out;
524541
break;
525542
case INAT_IMM_VWORD:
526-
__get_immv(insn);
543+
if (!__get_immv(insn))
544+
goto err_out;
527545
break;
528546
default:
529-
break;
547+
/* Here, insn must have an immediate, but failed */
548+
goto err_out;
530549
}
531550
if (inat_has_second_immediate(insn->attr)) {
532551
insn->immediate2.value = get_next(char, insn);

0 commit comments

Comments
 (0)