diff options
Diffstat (limited to 'lib/asn1_decoder.c')
-rw-r--r-- | lib/asn1_decoder.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 1a000bb050f9..2b3f46c049d4 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c | |||
@@ -24,15 +24,20 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { | |||
24 | [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, | 24 | [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, |
25 | [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, | 25 | [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, |
26 | [ASN1_OP_MATCH_ANY] = 1, | 26 | [ASN1_OP_MATCH_ANY] = 1, |
27 | [ASN1_OP_MATCH_ANY_OR_SKIP] = 1, | ||
27 | [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, | 28 | [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, |
29 | [ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, | ||
28 | [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, | 30 | [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, |
29 | [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, | 31 | [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, |
30 | [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, | 32 | [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, |
31 | [ASN1_OP_COND_MATCH_ANY] = 1, | 33 | [ASN1_OP_COND_MATCH_ANY] = 1, |
34 | [ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1, | ||
32 | [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, | 35 | [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, |
36 | [ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, | ||
33 | [ASN1_OP_COND_FAIL] = 1, | 37 | [ASN1_OP_COND_FAIL] = 1, |
34 | [ASN1_OP_COMPLETE] = 1, | 38 | [ASN1_OP_COMPLETE] = 1, |
35 | [ASN1_OP_ACT] = 1 + 1, | 39 | [ASN1_OP_ACT] = 1 + 1, |
40 | [ASN1_OP_MAYBE_ACT] = 1 + 1, | ||
36 | [ASN1_OP_RETURN] = 1, | 41 | [ASN1_OP_RETURN] = 1, |
37 | [ASN1_OP_END_SEQ] = 1, | 42 | [ASN1_OP_END_SEQ] = 1, |
38 | [ASN1_OP_END_SEQ_OF] = 1 + 1, | 43 | [ASN1_OP_END_SEQ_OF] = 1 + 1, |
@@ -177,6 +182,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, | |||
177 | unsigned char flags = 0; | 182 | unsigned char flags = 0; |
178 | #define FLAG_INDEFINITE_LENGTH 0x01 | 183 | #define FLAG_INDEFINITE_LENGTH 0x01 |
179 | #define FLAG_MATCHED 0x02 | 184 | #define FLAG_MATCHED 0x02 |
185 | #define FLAG_LAST_MATCHED 0x04 /* Last tag matched */ | ||
180 | #define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag | 186 | #define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag |
181 | * - ie. whether or not we are going to parse | 187 | * - ie. whether or not we are going to parse |
182 | * a compound type. | 188 | * a compound type. |
@@ -208,9 +214,9 @@ next_op: | |||
208 | unsigned char tmp; | 214 | unsigned char tmp; |
209 | 215 | ||
210 | /* Skip conditional matches if possible */ | 216 | /* Skip conditional matches if possible */ |
211 | if ((op & ASN1_OP_MATCH__COND && | 217 | if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) || |
212 | flags & FLAG_MATCHED) || | 218 | (op & ASN1_OP_MATCH__SKIP && dp == datalen)) { |
213 | dp == datalen) { | 219 | flags &= ~FLAG_LAST_MATCHED; |
214 | pc += asn1_op_lengths[op]; | 220 | pc += asn1_op_lengths[op]; |
215 | goto next_op; | 221 | goto next_op; |
216 | } | 222 | } |
@@ -302,7 +308,9 @@ next_op: | |||
302 | /* Decide how to handle the operation */ | 308 | /* Decide how to handle the operation */ |
303 | switch (op) { | 309 | switch (op) { |
304 | case ASN1_OP_MATCH_ANY_ACT: | 310 | case ASN1_OP_MATCH_ANY_ACT: |
311 | case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: | ||
305 | case ASN1_OP_COND_MATCH_ANY_ACT: | 312 | case ASN1_OP_COND_MATCH_ANY_ACT: |
313 | case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: | ||
306 | ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); | 314 | ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); |
307 | if (ret < 0) | 315 | if (ret < 0) |
308 | return ret; | 316 | return ret; |
@@ -319,8 +327,10 @@ next_op: | |||
319 | case ASN1_OP_MATCH: | 327 | case ASN1_OP_MATCH: |
320 | case ASN1_OP_MATCH_OR_SKIP: | 328 | case ASN1_OP_MATCH_OR_SKIP: |
321 | case ASN1_OP_MATCH_ANY: | 329 | case ASN1_OP_MATCH_ANY: |
330 | case ASN1_OP_MATCH_ANY_OR_SKIP: | ||
322 | case ASN1_OP_COND_MATCH_OR_SKIP: | 331 | case ASN1_OP_COND_MATCH_OR_SKIP: |
323 | case ASN1_OP_COND_MATCH_ANY: | 332 | case ASN1_OP_COND_MATCH_ANY: |
333 | case ASN1_OP_COND_MATCH_ANY_OR_SKIP: | ||
324 | skip_data: | 334 | skip_data: |
325 | if (!(flags & FLAG_CONS)) { | 335 | if (!(flags & FLAG_CONS)) { |
326 | if (flags & FLAG_INDEFINITE_LENGTH) { | 336 | if (flags & FLAG_INDEFINITE_LENGTH) { |
@@ -422,8 +432,15 @@ next_op: | |||
422 | pc += asn1_op_lengths[op]; | 432 | pc += asn1_op_lengths[op]; |
423 | goto next_op; | 433 | goto next_op; |
424 | 434 | ||
435 | case ASN1_OP_MAYBE_ACT: | ||
436 | if (!(flags & FLAG_LAST_MATCHED)) { | ||
437 | pc += asn1_op_lengths[op]; | ||
438 | goto next_op; | ||
439 | } | ||
425 | case ASN1_OP_ACT: | 440 | case ASN1_OP_ACT: |
426 | ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); | 441 | ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); |
442 | if (ret < 0) | ||
443 | return ret; | ||
427 | pc += asn1_op_lengths[op]; | 444 | pc += asn1_op_lengths[op]; |
428 | goto next_op; | 445 | goto next_op; |
429 | 446 | ||
@@ -431,6 +448,7 @@ next_op: | |||
431 | if (unlikely(jsp <= 0)) | 448 | if (unlikely(jsp <= 0)) |
432 | goto jump_stack_underflow; | 449 | goto jump_stack_underflow; |
433 | pc = jump_stack[--jsp]; | 450 | pc = jump_stack[--jsp]; |
451 | flags |= FLAG_MATCHED | FLAG_LAST_MATCHED; | ||
434 | goto next_op; | 452 | goto next_op; |
435 | 453 | ||
436 | default: | 454 | default: |
@@ -438,7 +456,8 @@ next_op: | |||
438 | } | 456 | } |
439 | 457 | ||
440 | /* Shouldn't reach here */ | 458 | /* Shouldn't reach here */ |
441 | pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op); | 459 | pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n", |
460 | op, pc); | ||
442 | return -EBADMSG; | 461 | return -EBADMSG; |
443 | 462 | ||
444 | data_overrun_error: | 463 | data_overrun_error: |