OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 #include <assert.h> | |
8 #include <elf.h> | |
9 #include <inttypes.h> | |
10 #include <stddef.h> | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <string.h> | |
14 #include "validator.h" | |
15 | |
16 #undef TRUE | |
17 #define TRUE 1 | |
18 | |
19 #undef FALSE | |
20 #define FALSE 0 | |
21 | |
22 #define check_jump_dest \ | |
23 if ((jump_dest & bundle_mask) != bundle_mask) { \ | |
24 if (jump_dest >= size) { \ | |
25 printf("direct jump out of range: %zx\n", jump_dest); \ | |
26 result = 1; \ | |
27 goto error_detected; \ | |
28 } else { \ | |
29 BitmapSetBit(jump_dests, jump_dest + 1); \ | |
30 } \ | |
31 } | |
32 | |
33 %%{ | |
34 machine x86_64_decoder; | |
35 alphtype unsigned char; | |
36 | |
37 action rel8_operand { | |
38 int8_t offset = (uint8_t) (p[0]); | |
39 size_t jump_dest = offset + (p - data); | |
40 check_jump_dest; | |
41 } | |
42 action rel16_operand { | |
43 assert(FALSE); | |
44 } | |
45 action rel32_operand { | |
46 int32_t offset = | |
47 (uint32_t) (p[-3] + 256U * (p[-2] + 256U * (p[-1] + 256U * (p[0])))); | |
48 size_t jump_dest = offset + (p - data); | |
49 check_jump_dest; | |
50 } | |
51 | |
52 # Do nothing when IMM operand is detected for now. Will be used later for | |
53 # dynamic code modification support. | |
54 action imm2_operand { } | |
55 action imm8_operand { } | |
56 action imm16_operand { } | |
57 action imm32_operand { } | |
58 action imm64_operand { } | |
59 action imm8_second_operand { } | |
60 action imm16_second_operand { } | |
61 action imm32_second_operand { } | |
62 action imm64_second_operand { } | |
63 | |
64 include decode_x86_32 "validator-x86_32-instruction.rl"; | |
65 | |
66 special_instruction = | |
67 (0x83 0xe0 0xe0 0xff (0xd0|0xe0) | # naclcall/jmp %acx | |
68 0x83 0xe1 0xe0 0xff (0xd1|0xe1) | # naclcall %ecx | |
69 0x83 0xe2 0xe0 0xff (0xd2|0xe2) | # naclcall %edx | |
70 0x83 0xe3 0xe0 0xff (0xd3|0xe3) | # naclcall %ebx | |
71 0x83 0xe4 0xe0 0xff (0xd4|0xe4) | # naclcall %esp | |
72 0x83 0xe5 0xe0 0xff (0xd5|0xe5) | # naclcall %ebp | |
73 0x83 0xe6 0xe0 0xff (0xd6|0xe6) | # naclcall %esi | |
74 0x83 0xe7 0xe0 0xff (0xd7|0xe7)) # naclcall %edi | |
75 @{ BitmapClearBit(valid_targets, (p - data) - 1); | |
76 }; | |
77 | |
78 main := ((one_instruction | special_instruction) >{ | |
79 BitmapSetBit(valid_targets, p - data); | |
80 })* | |
81 $!{ process_error(p, userdata); | |
82 result = 1; | |
83 goto error_detected; | |
84 }; | |
85 | |
86 }%% | |
87 | |
88 %% write data; | |
89 | |
90 /* Ignore this information for now. */ | |
91 #define data16_prefix if (0) result | |
92 #define lock_prefix if (0) result | |
93 #define repz_prefix if (0) result | |
94 #define repnz_prefix if (0) result | |
95 #define branch_not_taken if (0) result | |
96 #define branch_taken if (0) result | |
97 #define vex_prefix3 if (0) result | |
98 #define disp if (0) p | |
99 #define disp_type if (0) result | |
100 | |
101 enum disp_mode { | |
102 DISPNONE, | |
103 DISP8, | |
104 DISP16, | |
105 DISP32 | |
106 }; | |
107 | |
108 static const int kBitsPerByte = 8; | |
109 | |
110 static inline uint8_t *BitmapAllocate(uint32_t indexes) { | |
111 uint32_t byte_count = (indexes + kBitsPerByte - 1) / kBitsPerByte; | |
112 uint8_t *bitmap = malloc(byte_count); | |
113 if (bitmap != NULL) { | |
114 memset(bitmap, 0, byte_count); | |
115 } | |
116 return bitmap; | |
117 } | |
118 | |
119 static inline int BitmapIsBitSet(uint8_t *bitmap, uint32_t index) { | |
120 return (bitmap[index / kBitsPerByte] & (1 << (index % kBitsPerByte))) != 0; | |
121 } | |
122 | |
123 static inline void BitmapSetBit(uint8_t *bitmap, uint32_t index) { | |
124 bitmap[index / kBitsPerByte] |= 1 << (index % kBitsPerByte); | |
125 } | |
126 | |
127 static inline void BitmapClearBit(uint8_t *bitmap, uint32_t index) { | |
128 bitmap[index / kBitsPerByte] &= ~(1 << (index % kBitsPerByte)); | |
129 } | |
130 | |
131 static int CheckJumpTargets(uint8_t *valid_targets, uint8_t *jump_dests, | |
132 size_t size) { | |
133 size_t i; | |
134 for (i = 0; i < size / 32; i++) { | |
135 uint32_t jump_dest_mask = ((uint32_t *) jump_dests)[i]; | |
136 uint32_t valid_target_mask = ((uint32_t *) valid_targets)[i]; | |
137 if ((jump_dest_mask & ~valid_target_mask) != 0) { | |
138 printf("bad jump to around %x\n", (unsigned)(i * 32)); | |
139 return 1; | |
140 } | |
141 } | |
142 return 0; | |
143 } | |
144 | |
145 int ValidateChunkIA32(const uint8_t *data, size_t size, | |
146 process_error_func process_error, void *userdata) { | |
147 const size_t bundle_size = 32; | |
148 const size_t bundle_mask = bundle_size - 1; | |
149 | |
150 uint8_t *valid_targets = BitmapAllocate(size); | |
151 uint8_t *jump_dests = BitmapAllocate(size); | |
152 | |
153 const uint8_t *p = data; | |
154 /* const uint8_t *begin;*/ | |
155 | |
156 int result = 0; | |
157 | |
158 assert(size % bundle_size == 0); | |
159 | |
160 while (p < data + size) { | |
161 const uint8_t *pe = p + bundle_size; | |
162 const uint8_t *eof = pe; | |
163 int cs; | |
164 | |
165 %% write init; | |
166 %% write exec; | |
167 } | |
168 | |
169 if (CheckJumpTargets(valid_targets, jump_dests, size)) { | |
170 result = 1; | |
171 goto error_detected; | |
172 } | |
173 | |
174 error_detected: | |
175 return result; | |
176 } | |
OLD | NEW |