diff options
author | John Johansen <john.johansen@canonical.com> | 2017-08-08 16:01:01 -0400 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2018-02-09 14:30:02 -0500 |
commit | d901d6a298dc6e9105b9dc091d65b043e9f8c9a6 (patch) | |
tree | a57465d5598a1dbdba3f165e85f74b0a4d407326 | |
parent | 031dcc8f4e84fea37dc6f78fdc7288aa7f8386c3 (diff) |
apparmor: dfa split verification of table headers
separate the different types of verification so they are logically
separate and can be reused separate of each other.
Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r-- | security/apparmor/match.c | 116 |
1 files changed, 68 insertions, 48 deletions
diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 70cdcb3c3b25..7ae6ed9d69dd 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c | |||
@@ -136,8 +136,8 @@ fail: | |||
136 | } | 136 | } |
137 | 137 | ||
138 | /** | 138 | /** |
139 | * verify_dfa - verify that transitions and states in the tables are in bounds. | 139 | * verify_table_headers - verify that the tables headers are as expected |
140 | * @dfa: dfa to test (NOT NULL) | 140 | * @tables - array of dfa tables to check (NOT NULL) |
141 | * @flags: flags controlling what type of accept table are acceptable | 141 | * @flags: flags controlling what type of accept table are acceptable |
142 | * | 142 | * |
143 | * Assumes dfa has gone through the first pass verification done by unpacking | 143 | * Assumes dfa has gone through the first pass verification done by unpacking |
@@ -145,83 +145,98 @@ fail: | |||
145 | * | 145 | * |
146 | * Returns: %0 else error code on failure to verify | 146 | * Returns: %0 else error code on failure to verify |
147 | */ | 147 | */ |
148 | static int verify_dfa(struct aa_dfa *dfa, int flags) | 148 | static int verify_table_headers(struct table_header **tables, int flags) |
149 | { | 149 | { |
150 | size_t i, state_count, trans_count; | 150 | size_t state_count, trans_count; |
151 | int error = -EPROTO; | 151 | int error = -EPROTO; |
152 | 152 | ||
153 | /* check that required tables exist */ | 153 | /* check that required tables exist */ |
154 | if (!(dfa->tables[YYTD_ID_DEF] && | 154 | if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] && |
155 | dfa->tables[YYTD_ID_BASE] && | 155 | tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK])) |
156 | dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK])) | ||
157 | goto out; | 156 | goto out; |
158 | 157 | ||
159 | /* accept.size == default.size == base.size */ | 158 | /* accept.size == default.size == base.size */ |
160 | state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; | 159 | state_count = tables[YYTD_ID_BASE]->td_lolen; |
161 | if (ACCEPT1_FLAGS(flags)) { | 160 | if (ACCEPT1_FLAGS(flags)) { |
162 | if (!dfa->tables[YYTD_ID_ACCEPT]) | 161 | if (!tables[YYTD_ID_ACCEPT]) |
163 | goto out; | 162 | goto out; |
164 | if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen) | 163 | if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen) |
165 | goto out; | 164 | goto out; |
166 | } | 165 | } |
167 | if (ACCEPT2_FLAGS(flags)) { | 166 | if (ACCEPT2_FLAGS(flags)) { |
168 | if (!dfa->tables[YYTD_ID_ACCEPT2]) | 167 | if (!tables[YYTD_ID_ACCEPT2]) |
169 | goto out; | 168 | goto out; |
170 | if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen) | 169 | if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen) |
171 | goto out; | 170 | goto out; |
172 | } | 171 | } |
173 | if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen) | 172 | if (state_count != tables[YYTD_ID_DEF]->td_lolen) |
174 | goto out; | 173 | goto out; |
175 | 174 | ||
176 | /* next.size == chk.size */ | 175 | /* next.size == chk.size */ |
177 | trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; | 176 | trans_count = tables[YYTD_ID_NXT]->td_lolen; |
178 | if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen) | 177 | if (trans_count != tables[YYTD_ID_CHK]->td_lolen) |
179 | goto out; | 178 | goto out; |
180 | 179 | ||
181 | /* if equivalence classes then its table size must be 256 */ | 180 | /* if equivalence classes then its table size must be 256 */ |
182 | if (dfa->tables[YYTD_ID_EC] && | 181 | if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256) |
183 | dfa->tables[YYTD_ID_EC]->td_lolen != 256) | ||
184 | goto out; | 182 | goto out; |
185 | 183 | ||
186 | if (flags & DFA_FLAG_VERIFY_STATES) { | 184 | error = 0; |
187 | for (i = 0; i < state_count; i++) { | 185 | out: |
188 | if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && | 186 | return error; |
189 | (DEFAULT_TABLE(dfa)[i] >= state_count)) | 187 | } |
190 | goto out; | ||
191 | if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { | ||
192 | printk(KERN_ERR "AppArmor DFA next/check upper " | ||
193 | "bounds error\n"); | ||
194 | goto out; | ||
195 | } | ||
196 | } | ||
197 | 188 | ||
198 | for (i = 0; i < trans_count; i++) { | 189 | /** |
199 | if (NEXT_TABLE(dfa)[i] >= state_count) | 190 | * verify_dfa - verify that transitions and states in the tables are in bounds. |
200 | goto out; | 191 | * @dfa: dfa to test (NOT NULL) |
201 | if (CHECK_TABLE(dfa)[i] >= state_count) | 192 | * |
202 | goto out; | 193 | * Assumes dfa has gone through the first pass verification done by unpacking |
194 | * NOTE: this does not valid accept table values | ||
195 | * | ||
196 | * Returns: %0 else error code on failure to verify | ||
197 | */ | ||
198 | static int verify_dfa(struct aa_dfa *dfa) | ||
199 | { | ||
200 | size_t i, state_count, trans_count; | ||
201 | int error = EPROTO; | ||
202 | |||
203 | state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; | ||
204 | trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen; | ||
205 | for (i = 0; i < state_count; i++) { | ||
206 | if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) && | ||
207 | (DEFAULT_TABLE(dfa)[i] >= state_count)) | ||
208 | goto out; | ||
209 | if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { | ||
210 | pr_err("AppArmor DFA next/check upper bounds error\n"); | ||
211 | goto out; | ||
203 | } | 212 | } |
204 | } | 213 | } |
205 | 214 | ||
215 | for (i = 0; i < trans_count; i++) { | ||
216 | if (NEXT_TABLE(dfa)[i] >= state_count) | ||
217 | goto out; | ||
218 | if (CHECK_TABLE(dfa)[i] >= state_count) | ||
219 | goto out; | ||
220 | } | ||
221 | |||
206 | /* Now that all the other tables are verified, verify diffencoding */ | 222 | /* Now that all the other tables are verified, verify diffencoding */ |
207 | if (flags & DFA_FLAG_VERIFY_STATES) { | 223 | for (i = 0; i < state_count; i++) { |
208 | size_t j, k; | 224 | size_t j, k; |
209 | 225 | ||
210 | for (i = 0; i < state_count; i++) { | 226 | for (j = i; |
211 | for (j = i; | 227 | (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && |
212 | (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) && | 228 | !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); |
213 | !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE); | 229 | j = k) { |
214 | j = k) { | 230 | k = DEFAULT_TABLE(dfa)[j]; |
215 | k = DEFAULT_TABLE(dfa)[j]; | 231 | if (j == k) |
216 | if (j == k) | 232 | goto out; |
217 | goto out; | 233 | if (k < j) |
218 | if (k < j) | 234 | break; /* already verified */ |
219 | break; /* already verified */ | 235 | BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; |
220 | BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE; | ||
221 | } | ||
222 | } | 236 | } |
223 | } | 237 | } |
224 | error = 0; | 238 | error = 0; |
239 | |||
225 | out: | 240 | out: |
226 | return error; | 241 | return error; |
227 | } | 242 | } |
@@ -338,11 +353,16 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) | |||
338 | size -= table_size(table->td_lolen, table->td_flags); | 353 | size -= table_size(table->td_lolen, table->td_flags); |
339 | table = NULL; | 354 | table = NULL; |
340 | } | 355 | } |
341 | 356 | error = verify_table_headers(dfa->tables, flags); | |
342 | error = verify_dfa(dfa, flags); | ||
343 | if (error) | 357 | if (error) |
344 | goto fail; | 358 | goto fail; |
345 | 359 | ||
360 | if (flags & DFA_FLAG_VERIFY_STATES) { | ||
361 | error = verify_dfa(dfa); | ||
362 | if (error) | ||
363 | goto fail; | ||
364 | } | ||
365 | |||
346 | return dfa; | 366 | return dfa; |
347 | 367 | ||
348 | fail: | 368 | fail: |