diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 4ab83f4c47cf..6d09db9c84ab 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c | |||
@@ -68,6 +68,8 @@ | |||
68 | 68 | ||
69 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | 69 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) |
70 | 70 | ||
71 | #define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) | ||
72 | |||
71 | #define PSR_fs (PSR_f|PSR_s) | 73 | #define PSR_fs (PSR_f|PSR_s) |
72 | 74 | ||
73 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ | 75 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ |
@@ -897,6 +899,9 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
897 | static enum kprobe_insn __kprobes | 899 | static enum kprobe_insn __kprobes |
898 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 900 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
899 | { | 901 | { |
902 | if (is_r15(insn, 12)) | ||
903 | return INSN_REJECTED; /* Rd is PC */ | ||
904 | |||
900 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | 905 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ |
901 | asi->insn[0] = insn; | 906 | asi->insn[0] = insn; |
902 | asi->insn_handler = emulate_rd12rm0; | 907 | asi->insn_handler = emulate_rd12rm0; |
@@ -907,6 +912,9 @@ static enum kprobe_insn __kprobes | |||
907 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | 912 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, |
908 | struct arch_specific_insn *asi) | 913 | struct arch_specific_insn *asi) |
909 | { | 914 | { |
915 | if (is_r15(insn, 12)) | ||
916 | return INSN_REJECTED; /* Rd is PC */ | ||
917 | |||
910 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | 918 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ |
911 | insn |= 0x00000001; /* Rm = r1 */ | 919 | insn |= 0x00000001; /* Rm = r1 */ |
912 | asi->insn[0] = insn; | 920 | asi->insn[0] = insn; |
@@ -918,6 +926,9 @@ static enum kprobe_insn __kprobes | |||
918 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | 926 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, |
919 | struct arch_specific_insn *asi) | 927 | struct arch_specific_insn *asi) |
920 | { | 928 | { |
929 | if (is_r15(insn, 16)) | ||
930 | return INSN_REJECTED; /* Rd is PC */ | ||
931 | |||
921 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | 932 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ |
922 | insn |= 0x00000001; /* Rm = r1 */ | 933 | insn |= 0x00000001; /* Rm = r1 */ |
923 | asi->insn[0] = insn; | 934 | asi->insn[0] = insn; |
@@ -929,6 +940,9 @@ static enum kprobe_insn __kprobes | |||
929 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | 940 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, |
930 | struct arch_specific_insn *asi) | 941 | struct arch_specific_insn *asi) |
931 | { | 942 | { |
943 | if (is_r15(insn, 16)) | ||
944 | return INSN_REJECTED; /* Rd is PC */ | ||
945 | |||
932 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | 946 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ |
933 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | 947 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ |
934 | asi->insn[0] = insn; | 948 | asi->insn[0] = insn; |
@@ -940,6 +954,9 @@ static enum kprobe_insn __kprobes | |||
940 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | 954 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, |
941 | struct arch_specific_insn *asi) | 955 | struct arch_specific_insn *asi) |
942 | { | 956 | { |
957 | if (is_r15(insn, 16) || is_r15(insn, 12)) | ||
958 | return INSN_REJECTED; /* RdHi or RdLo is PC */ | ||
959 | |||
943 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | 960 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ |
944 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | 961 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ |
945 | asi->insn[0] = insn; | 962 | asi->insn[0] = insn; |
@@ -1035,6 +1052,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1035 | 1052 | ||
1036 | /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ | 1053 | /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ |
1037 | if ((insn & 0x0ff000f0) == 0x01000000) { | 1054 | if ((insn & 0x0ff000f0) == 0x01000000) { |
1055 | if (is_r15(insn, 12)) | ||
1056 | return INSN_REJECTED; /* Rd is PC */ | ||
1038 | asi->insn_handler = simulate_mrs; | 1057 | asi->insn_handler = simulate_mrs; |
1039 | return INSN_GOOD_NO_SLOT; | 1058 | return INSN_GOOD_NO_SLOT; |
1040 | } | 1059 | } |
@@ -1065,6 +1084,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1065 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | 1084 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ |
1066 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | 1085 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ |
1067 | if ((insn & 0x0ff000d0) == 0x01200010) { | 1086 | if ((insn & 0x0ff000d0) == 0x01200010) { |
1087 | if ((insn & 0x0ff000ff) == 0x0120003f) | ||
1088 | return INSN_REJECTED; /* BLX pc */ | ||
1068 | asi->insn_handler = simulate_blx2bx; | 1089 | asi->insn_handler = simulate_blx2bx; |
1069 | return INSN_GOOD_NO_SLOT; | 1090 | return INSN_GOOD_NO_SLOT; |
1070 | } | 1091 | } |
@@ -1234,6 +1255,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1234 | { | 1255 | { |
1235 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ | 1256 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ |
1236 | if ((insn & 0x0ff000f0) == 0x068000b0) { | 1257 | if ((insn & 0x0ff000f0) == 0x068000b0) { |
1258 | if (is_r15(insn, 12)) | ||
1259 | return INSN_REJECTED; /* Rd is PC */ | ||
1237 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | 1260 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ |
1238 | insn |= 0x00000001; /* Rm = r1 */ | 1261 | insn |= 0x00000001; /* Rm = r1 */ |
1239 | asi->insn[0] = insn; | 1262 | asi->insn[0] = insn; |
@@ -1247,6 +1270,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1247 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ | 1270 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ |
1248 | if ((insn & 0x0fa00030) == 0x06a00010 || | 1271 | if ((insn & 0x0fa00030) == 0x06a00010 || |
1249 | (insn & 0x0fb000f0) == 0x06a00030) { | 1272 | (insn & 0x0fb000f0) == 0x06a00030) { |
1273 | if (is_r15(insn, 12)) | ||
1274 | return INSN_REJECTED; /* Rd is PC */ | ||
1250 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | 1275 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ |
1251 | asi->insn[0] = insn; | 1276 | asi->insn[0] = insn; |
1252 | asi->insn_handler = emulate_sat; | 1277 | asi->insn_handler = emulate_sat; |
@@ -1384,6 +1409,9 @@ space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1384 | { | 1409 | { |
1385 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | 1410 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ |
1386 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | 1411 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ |
1412 | if (is_r15(insn, 16) || is_r15(insn, 12)) | ||
1413 | return INSN_REJECTED; /* Rn or Rd is PC */ | ||
1414 | |||
1387 | insn &= 0xfff00fff; | 1415 | insn &= 0xfff00fff; |
1388 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | 1416 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ |
1389 | asi->insn[0] = insn; | 1417 | asi->insn[0] = insn; |