ASN.1: Fix actions on CHOICE elements with IMPLICIT tags
[cascardo/linux.git] / lib / asn1_decoder.c
index 1a000bb..55980d7 100644 (file)
@@ -33,6 +33,7 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
        [ASN1_OP_COND_FAIL]                     = 1,
        [ASN1_OP_COMPLETE]                      = 1,
        [ASN1_OP_ACT]                           = 1         + 1,
+       [ASN1_OP_MAYBE_ACT]                     = 1         + 1,
        [ASN1_OP_RETURN]                        = 1,
        [ASN1_OP_END_SEQ]                       = 1,
        [ASN1_OP_END_SEQ_OF]                    = 1     + 1,
@@ -177,6 +178,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
        unsigned char flags = 0;
 #define FLAG_INDEFINITE_LENGTH 0x01
 #define FLAG_MATCHED           0x02
+#define FLAG_LAST_MATCHED      0x04 /* Last tag matched */
 #define FLAG_CONS              0x20 /* Corresponds to CONS bit in the opcode tag
                                      * - ie. whether or not we are going to parse
                                      *   a compound type.
@@ -211,6 +213,7 @@ next_op:
                if ((op & ASN1_OP_MATCH__COND &&
                     flags & FLAG_MATCHED) ||
                    dp == datalen) {
+                       flags &= ~FLAG_LAST_MATCHED;
                        pc += asn1_op_lengths[op];
                        goto next_op;
                }
@@ -422,8 +425,15 @@ next_op:
                pc += asn1_op_lengths[op];
                goto next_op;
 
+       case ASN1_OP_MAYBE_ACT:
+               if (!(flags & FLAG_LAST_MATCHED)) {
+                       pc += asn1_op_lengths[op];
+                       goto next_op;
+               }
        case ASN1_OP_ACT:
                ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
+               if (ret < 0)
+                       return ret;
                pc += asn1_op_lengths[op];
                goto next_op;
 
@@ -431,6 +441,7 @@ next_op:
                if (unlikely(jsp <= 0))
                        goto jump_stack_underflow;
                pc = jump_stack[--jsp];
+               flags |= FLAG_MATCHED | FLAG_LAST_MATCHED;
                goto next_op;
 
        default:
@@ -438,7 +449,8 @@ next_op:
        }
 
        /* Shouldn't reach here */
-       pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op);
+       pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n",
+              op, pc);
        return -EBADMSG;
 
 data_overrun_error: