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: Patrick McHardy <kaber@trash.net>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Chris Wright and committed by Linus Torvalds ddb2c435 efedf51c

+28
+14
fs/cifs/asn1.c
··· 186 186 } 187 187 } 188 188 } 189 + 190 + /* don't trust len bigger than ctx buffer */ 191 + if (*len > ctx->end - ctx->pointer) 192 + return 0; 193 + 189 194 return 1; 190 195 } 191 196 ··· 206 201 return 0; 207 202 208 203 if (!asn1_length_decode(ctx, &def, &len)) 204 + return 0; 205 + 206 + /* primitive shall be definite, indefinite shall be constructed */ 207 + if (*con == ASN1_PRI && !def) 209 208 return 0; 210 209 211 210 if (def) ··· 398 389 unsigned long *optr; 399 390 400 391 size = eoc - ctx->pointer + 1; 392 + 393 + /* first subid actually encodes first two subids */ 394 + if (size < 2 || size > ULONG_MAX/sizeof(unsigned long)) 395 + return 0; 396 + 401 397 *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); 402 398 if (*oid == NULL) 403 399 return 0;
+14
net/ipv4/netfilter/nf_nat_snmp_basic.c
··· 232 232 } 233 233 } 234 234 } 235 + 236 + /* don't trust len bigger than ctx buffer */ 237 + if (*len > ctx->end - ctx->pointer) 238 + return 0; 239 + 235 240 return 1; 236 241 } 237 242 ··· 253 248 254 249 def = len = 0; 255 250 if (!asn1_length_decode(ctx, &def, &len)) 251 + return 0; 252 + 253 + /* primitive shall be definite, indefinite shall be constructed */ 254 + if (*con == ASN1_PRI && !def) 256 255 return 0; 257 256 258 257 if (def) ··· 443 434 unsigned long *optr; 444 435 445 436 size = eoc - ctx->pointer + 1; 437 + 438 + /* first subid actually encodes first two subids */ 439 + if (size < 2 || size > ULONG_MAX/sizeof(unsigned long)) 440 + return 0; 441 + 446 442 *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); 447 443 if (*oid == NULL) { 448 444 if (net_ratelimit())