Commit ddb2c435 authored by Chris Wright's avatar Chris Wright Committed by Linus Torvalds

asn1: additional sanity checking during BER decoding

- Don't trust a length which is greater than the working buffer.
  An invalid length could cause overflow when calculating buffer size
  for decoding oid.

- An oid length of zero is invalid and allows for an off-by-one error when
  decoding oid because the first subid actually encodes first 2 subids.

- A primitive encoding may not have an indefinite length.

Thanks to Wei Wang from McAfee for report.

Cc: Steven French <sfrench@us.ibm.com>
Cc: stable@kernel.org
Acked-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarChris Wright <chrisw@sous-sol.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent efedf51c
...@@ -186,6 +186,11 @@ asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) ...@@ -186,6 +186,11 @@ asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
} }
} }
} }
/* don't trust len bigger than ctx buffer */
if (*len > ctx->end - ctx->pointer)
return 0;
return 1; return 1;
} }
...@@ -203,6 +208,10 @@ asn1_header_decode(struct asn1_ctx *ctx, ...@@ -203,6 +208,10 @@ asn1_header_decode(struct asn1_ctx *ctx,
if (!asn1_length_decode(ctx, &def, &len)) if (!asn1_length_decode(ctx, &def, &len))
return 0; return 0;
/* primitive shall be definite, indefinite shall be constructed */
if (*con == ASN1_PRI && !def)
return 0;
if (def) if (def)
*eoc = ctx->pointer + len; *eoc = ctx->pointer + len;
else else
...@@ -389,6 +398,11 @@ asn1_oid_decode(struct asn1_ctx *ctx, ...@@ -389,6 +398,11 @@ asn1_oid_decode(struct asn1_ctx *ctx,
unsigned long *optr; unsigned long *optr;
size = eoc - ctx->pointer + 1; size = eoc - ctx->pointer + 1;
/* first subid actually encodes first two subids */
if (size < 2 || size > ULONG_MAX/sizeof(unsigned long))
return 0;
*oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
if (*oid == NULL) if (*oid == NULL)
return 0; return 0;
......
...@@ -232,6 +232,11 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx, ...@@ -232,6 +232,11 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx,
} }
} }
} }
/* don't trust len bigger than ctx buffer */
if (*len > ctx->end - ctx->pointer)
return 0;
return 1; return 1;
} }
...@@ -250,6 +255,10 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx, ...@@ -250,6 +255,10 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx,
if (!asn1_length_decode(ctx, &def, &len)) if (!asn1_length_decode(ctx, &def, &len))
return 0; return 0;
/* primitive shall be definite, indefinite shall be constructed */
if (*con == ASN1_PRI && !def)
return 0;
if (def) if (def)
*eoc = ctx->pointer + len; *eoc = ctx->pointer + len;
else else
...@@ -434,6 +443,11 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, ...@@ -434,6 +443,11 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx,
unsigned long *optr; unsigned long *optr;
size = eoc - ctx->pointer + 1; size = eoc - ctx->pointer + 1;
/* first subid actually encodes first two subids */
if (size < 2 || size > ULONG_MAX/sizeof(unsigned long))
return 0;
*oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
if (*oid == NULL) { if (*oid == NULL) {
if (net_ratelimit()) if (net_ratelimit())
......
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