From 3f3af97d8225a58ecdcde7217c030b17e5198226 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 5 Aug 2015 12:54:46 +0100 Subject: ASN.1: Fix actions on CHOICE elements with IMPLICIT tags In an ASN.1 description where there is a CHOICE construct that contains elements with IMPLICIT tags that refer to constructed types, actions to be taken on those elements should be conditional on the corresponding element actually being matched. Currently, however, such actions are performed unconditionally in the middle of processing the CHOICE. For example, look at elements 'b' and 'e' here: A ::= SEQUENCE { CHOICE { b [0] IMPLICIT B ({ do_XXXXXXXXXXXX_b }), c [1] EXPLICIT C ({ do_XXXXXXXXXXXX_c }), d [2] EXPLICIT B ({ do_XXXXXXXXXXXX_d }), e [3] IMPLICIT C ({ do_XXXXXXXXXXXX_e }), f [4] IMPLICIT INTEGER ({ do_XXXXXXXXXXXX_f }) } } ({ do_XXXXXXXXXXXX_A }) B ::= SET OF OBJECT IDENTIFIER ({ do_XXXXXXXXXXXX_oid }) C ::= SET OF INTEGER ({ do_XXXXXXXXXXXX_int }) They each have an action (do_XXXXXXXXXXXX_b and do_XXXXXXXXXXXX_e) that should only be processed if that element is matched. The problem is that there's no easy place to hang the action off in the subclause (type B for element 'b' and type C for element 'e') because subclause opcode sequences can be shared. To fix this, introduce a conditional action opcode(ASN1_OP_MAYBE_ACT) that the decoder only processes if the preceding match was successful. This can be seen in an excerpt from the output of the fixed ASN.1 compiler for the above ASN.1 description: [ 13] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // e [ 14] = _tagn(CONT, CONS, 3), [ 15] = _jump_target(45), // --> C [ 16] = ASN1_OP_MAYBE_ACT, [ 17] = _action(ACT_do_XXXXXXXXXXXX_e), In this, if the op at [13] is matched (ie. element 'e' above) then the action at [16] will be performed. However, if the op at [13] doesn't match or is skipped because it is conditional and some previous op matched, then the action at [16] will be ignored. Note that to make this work in the decoder, the ASN1_OP_RETURN op must set the flag to indicate that a match happened. This is necessary because the _jump_target() seen above introduces a subclause (in this case an object of type 'C') which is likely to alter the flag. Setting the flag here is okay because to process a subclause, a match must have happened and caused a jump. This cannot be tested with the code as it stands, but rather affects future code. Signed-off-by: David Howells Reviewed-by: David Woodhouse --- include/linux/asn1_ber_bytecode.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux/asn1_ber_bytecode.h') diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h index 945d44ae529c..27f35780aecf 100644 --- a/include/linux/asn1_ber_bytecode.h +++ b/include/linux/asn1_ber_bytecode.h @@ -61,7 +61,8 @@ enum asn1_opcode { ASN1_OP_COND_FAIL = 0x1b, ASN1_OP_COMPLETE = 0x1c, ASN1_OP_ACT = 0x1d, - ASN1_OP_RETURN = 0x1e, + ASN1_OP_MAYBE_ACT = 0x1e, + ASN1_OP_RETURN = 0x1f, /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ ASN1_OP_END_SEQ = 0x20, -- cgit v1.2.3