Commit 459c15e5 authored by James Morris's avatar James Morris

Merge tag 'asn1-fixes-20150805' of...

Merge tag 'asn1-fixes-20150805' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into next
parents 730daa16 233ce79d
...@@ -45,23 +45,27 @@ enum asn1_opcode { ...@@ -45,23 +45,27 @@ enum asn1_opcode {
ASN1_OP_MATCH_JUMP = 0x04, ASN1_OP_MATCH_JUMP = 0x04,
ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
ASN1_OP_MATCH_ANY = 0x08, ASN1_OP_MATCH_ANY = 0x08,
ASN1_OP_MATCH_ANY_OR_SKIP = 0x09,
ASN1_OP_MATCH_ANY_ACT = 0x0a, ASN1_OP_MATCH_ANY_ACT = 0x0a,
ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 0x0b,
/* Everything before here matches unconditionally */ /* Everything before here matches unconditionally */
ASN1_OP_COND_MATCH_OR_SKIP = 0x11, ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
ASN1_OP_COND_MATCH_ANY = 0x18, ASN1_OP_COND_MATCH_ANY = 0x18,
ASN1_OP_COND_MATCH_ANY_OR_SKIP = 0x19,
ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 0x1b,
/* Everything before here will want a tag from the data */ /* Everything before here will want a tag from the data */
#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT #define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP
/* These are here to help fill up space */ /* These are here to help fill up space */
ASN1_OP_COND_FAIL = 0x1b, ASN1_OP_COND_FAIL = 0x1c,
ASN1_OP_COMPLETE = 0x1c, ASN1_OP_COMPLETE = 0x1d,
ASN1_OP_ACT = 0x1d, ASN1_OP_ACT = 0x1e,
ASN1_OP_RETURN = 0x1e, ASN1_OP_MAYBE_ACT = 0x1f,
/* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
ASN1_OP_END_SEQ = 0x20, ASN1_OP_END_SEQ = 0x20,
...@@ -76,6 +80,8 @@ enum asn1_opcode { ...@@ -76,6 +80,8 @@ enum asn1_opcode {
#define ASN1_OP_END__OF 0x02 #define ASN1_OP_END__OF 0x02
#define ASN1_OP_END__ACT 0x04 #define ASN1_OP_END__ACT 0x04
ASN1_OP_RETURN = 0x28,
ASN1_OP__NR ASN1_OP__NR
}; };
......
...@@ -24,15 +24,20 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { ...@@ -24,15 +24,20 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
[ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1,
[ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
[ASN1_OP_MATCH_ANY] = 1, [ASN1_OP_MATCH_ANY] = 1,
[ASN1_OP_MATCH_ANY_OR_SKIP] = 1,
[ASN1_OP_MATCH_ANY_ACT] = 1 + 1, [ASN1_OP_MATCH_ANY_ACT] = 1 + 1,
[ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
[ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1,
[ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
[ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
[ASN1_OP_COND_MATCH_ANY] = 1, [ASN1_OP_COND_MATCH_ANY] = 1,
[ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1,
[ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1,
[ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
[ASN1_OP_COND_FAIL] = 1, [ASN1_OP_COND_FAIL] = 1,
[ASN1_OP_COMPLETE] = 1, [ASN1_OP_COMPLETE] = 1,
[ASN1_OP_ACT] = 1 + 1, [ASN1_OP_ACT] = 1 + 1,
[ASN1_OP_MAYBE_ACT] = 1 + 1,
[ASN1_OP_RETURN] = 1, [ASN1_OP_RETURN] = 1,
[ASN1_OP_END_SEQ] = 1, [ASN1_OP_END_SEQ] = 1,
[ASN1_OP_END_SEQ_OF] = 1 + 1, [ASN1_OP_END_SEQ_OF] = 1 + 1,
...@@ -177,6 +182,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -177,6 +182,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
unsigned char flags = 0; unsigned char flags = 0;
#define FLAG_INDEFINITE_LENGTH 0x01 #define FLAG_INDEFINITE_LENGTH 0x01
#define FLAG_MATCHED 0x02 #define FLAG_MATCHED 0x02
#define FLAG_LAST_MATCHED 0x04 /* Last tag matched */
#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag #define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag
* - ie. whether or not we are going to parse * - ie. whether or not we are going to parse
* a compound type. * a compound type.
...@@ -208,9 +214,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -208,9 +214,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
unsigned char tmp; unsigned char tmp;
/* Skip conditional matches if possible */ /* Skip conditional matches if possible */
if ((op & ASN1_OP_MATCH__COND && if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) ||
flags & FLAG_MATCHED) || (op & ASN1_OP_MATCH__SKIP && dp == datalen)) {
dp == datalen) { flags &= ~FLAG_LAST_MATCHED;
pc += asn1_op_lengths[op]; pc += asn1_op_lengths[op];
goto next_op; goto next_op;
} }
...@@ -302,7 +308,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -302,7 +308,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
/* Decide how to handle the operation */ /* Decide how to handle the operation */
switch (op) { switch (op) {
case ASN1_OP_MATCH_ANY_ACT: case ASN1_OP_MATCH_ANY_ACT:
case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:
case ASN1_OP_COND_MATCH_ANY_ACT: case ASN1_OP_COND_MATCH_ANY_ACT:
case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP:
ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -319,8 +327,10 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -319,8 +327,10 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
case ASN1_OP_MATCH: case ASN1_OP_MATCH:
case ASN1_OP_MATCH_OR_SKIP: case ASN1_OP_MATCH_OR_SKIP:
case ASN1_OP_MATCH_ANY: case ASN1_OP_MATCH_ANY:
case ASN1_OP_MATCH_ANY_OR_SKIP:
case ASN1_OP_COND_MATCH_OR_SKIP: case ASN1_OP_COND_MATCH_OR_SKIP:
case ASN1_OP_COND_MATCH_ANY: case ASN1_OP_COND_MATCH_ANY:
case ASN1_OP_COND_MATCH_ANY_OR_SKIP:
skip_data: skip_data:
if (!(flags & FLAG_CONS)) { if (!(flags & FLAG_CONS)) {
if (flags & FLAG_INDEFINITE_LENGTH) { if (flags & FLAG_INDEFINITE_LENGTH) {
...@@ -422,8 +432,15 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -422,8 +432,15 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
pc += asn1_op_lengths[op]; pc += asn1_op_lengths[op];
goto next_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: case ASN1_OP_ACT:
ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
if (ret < 0)
return ret;
pc += asn1_op_lengths[op]; pc += asn1_op_lengths[op];
goto next_op; goto next_op;
...@@ -431,6 +448,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -431,6 +448,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
if (unlikely(jsp <= 0)) if (unlikely(jsp <= 0))
goto jump_stack_underflow; goto jump_stack_underflow;
pc = jump_stack[--jsp]; pc = jump_stack[--jsp];
flags |= FLAG_MATCHED | FLAG_LAST_MATCHED;
goto next_op; goto next_op;
default: default:
...@@ -438,7 +456,8 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -438,7 +456,8 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
} }
/* Shouldn't reach here */ /* 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; return -EBADMSG;
data_overrun_error: data_overrun_error:
......
...@@ -666,7 +666,7 @@ struct element { ...@@ -666,7 +666,7 @@ struct element {
unsigned flags; unsigned flags;
#define ELEMENT_IMPLICIT 0x0001 #define ELEMENT_IMPLICIT 0x0001
#define ELEMENT_EXPLICIT 0x0002 #define ELEMENT_EXPLICIT 0x0002
#define ELEMENT_MARKED 0x0004 #define ELEMENT_TAG_SPECIFIED 0x0004
#define ELEMENT_RENDERED 0x0008 #define ELEMENT_RENDERED 0x0008
#define ELEMENT_SKIPPABLE 0x0010 #define ELEMENT_SKIPPABLE 0x0010
#define ELEMENT_CONDITIONAL 0x0020 #define ELEMENT_CONDITIONAL 0x0020
...@@ -879,6 +879,7 @@ static struct element *parse_type(struct token **_cursor, struct token *end, ...@@ -879,6 +879,7 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
element->tag &= ~0x1f; element->tag &= ~0x1f;
element->tag |= strtoul(cursor->value, &p, 10); element->tag |= strtoul(cursor->value, &p, 10);
element->flags |= ELEMENT_TAG_SPECIFIED;
if (p - cursor->value != cursor->size) if (p - cursor->value != cursor->size)
abort(); abort();
cursor++; cursor++;
...@@ -1376,7 +1377,7 @@ static void render_out_of_line_list(FILE *out) ...@@ -1376,7 +1377,7 @@ static void render_out_of_line_list(FILE *out)
*/ */
static void render_element(FILE *out, struct element *e, struct element *tag) static void render_element(FILE *out, struct element *e, struct element *tag)
{ {
struct element *ec; struct element *ec, *x;
const char *cond, *act; const char *cond, *act;
int entry, skippable = 0, outofline = 0; int entry, skippable = 0, outofline = 0;
...@@ -1400,7 +1401,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag) ...@@ -1400,7 +1401,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
act = e->action ? "_ACT" : ""; act = e->action ? "_ACT" : "";
switch (e->compound) { switch (e->compound) {
case ANY: case ANY:
render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
cond, act, skippable ? "_OR_SKIP" : "");
if (e->name) if (e->name)
render_more(out, "\t\t// %*.*s", render_more(out, "\t\t// %*.*s",
(int)e->name->size, (int)e->name->size, (int)e->name->size, (int)e->name->size,
...@@ -1435,15 +1437,17 @@ static void render_element(FILE *out, struct element *e, struct element *tag) ...@@ -1435,15 +1437,17 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
break; break;
} }
if (e->name) x = tag ?: e;
if (x->name)
render_more(out, "\t\t// %*.*s", render_more(out, "\t\t// %*.*s",
(int)e->name->size, (int)e->name->size, (int)x->name->size, (int)x->name->size,
e->name->value); x->name->value);
render_more(out, "\n"); render_more(out, "\n");
/* Render the tag */ /* Render the tag */
if (!tag) if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
tag = e; tag = e;
if (tag->class == ASN1_UNIV && if (tag->class == ASN1_UNIV &&
tag->tag != 14 && tag->tag != 14 &&
tag->tag != 15 && tag->tag != 15 &&
...@@ -1465,7 +1469,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag) ...@@ -1465,7 +1469,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
case TYPE_REF: case TYPE_REF:
render_element(out, e->type->type->element, tag); render_element(out, e->type->type->element, tag);
if (e->action) if (e->action)
render_opcode(out, "ASN1_OP_ACT,\n"); render_opcode(out, "ASN1_OP_%sACT,\n",
skippable ? "MAYBE_" : "");
break; break;
case SEQUENCE: case SEQUENCE:
...@@ -1539,7 +1544,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) ...@@ -1539,7 +1544,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
case CHOICE: case CHOICE:
for (ec = e->children; ec; ec = ec->next) for (ec = e->children; ec; ec = ec->next)
render_element(out, ec, NULL); render_element(out, ec, ec);
if (!skippable) if (!skippable)
render_opcode(out, "ASN1_OP_COND_FAIL,\n"); render_opcode(out, "ASN1_OP_COND_FAIL,\n");
if (e->action) if (e->action)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment