Commit dbadc176 authored by David Howells's avatar David Howells Committed by Rusty Russell

X.509: Fix indefinite length element skip error handling

asn1_find_indefinite_length() returns an error indicator of -1, which the
caller asn1_ber_decoder() places in a size_t (which is usually unsigned) and
then checks to see whether it is less than 0 (which it can't be).  This can
lead to the following warning:

	lib/asn1_decoder.c:320 asn1_ber_decoder()
		warn: unsigned 'len' is never less than zero.

Instead, asn1_find_indefinite_length() update the caller's idea of the data
cursor and length separately from returning the error code.
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 2f1c4fef
...@@ -46,12 +46,18 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { ...@@ -46,12 +46,18 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
/* /*
* Find the length of an indefinite length object * Find the length of an indefinite length object
* @data: The data buffer
* @datalen: The end of the innermost containing element in the buffer
* @_dp: The data parse cursor (updated before returning)
* @_len: Where to return the size of the element.
* @_errmsg: Where to return a pointer to an error message on error
*/ */
static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen,
const char **_errmsg, size_t *_err_dp) size_t *_dp, size_t *_len,
const char **_errmsg)
{ {
unsigned char tag, tmp; unsigned char tag, tmp;
size_t dp = 0, len, n; size_t dp = *_dp, len, n;
int indef_level = 1; int indef_level = 1;
next_tag: next_tag:
...@@ -67,8 +73,11 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen ...@@ -67,8 +73,11 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
/* It appears to be an EOC. */ /* It appears to be an EOC. */
if (data[dp++] != 0) if (data[dp++] != 0)
goto invalid_eoc; goto invalid_eoc;
if (--indef_level <= 0) if (--indef_level <= 0) {
return dp; *_len = dp - *_dp;
*_dp = dp;
return 0;
}
goto next_tag; goto next_tag;
} }
...@@ -122,7 +131,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen ...@@ -122,7 +131,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
missing_eoc: missing_eoc:
*_errmsg = "Missing EOC in indefinite len cons"; *_errmsg = "Missing EOC in indefinite len cons";
error: error:
*_err_dp = dp; *_dp = dp;
return -1; return -1;
} }
...@@ -315,13 +324,14 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -315,13 +324,14 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
skip_data: skip_data:
if (!(flags & FLAG_CONS)) { if (!(flags & FLAG_CONS)) {
if (flags & FLAG_INDEFINITE_LENGTH) { if (flags & FLAG_INDEFINITE_LENGTH) {
len = asn1_find_indefinite_length( ret = asn1_find_indefinite_length(
data + dp, datalen - dp, &errmsg, &dp); data, datalen, &dp, &len, &errmsg);
if (len < 0) if (ret < 0)
goto error; goto error;
} else {
dp += len;
} }
pr_debug("- LEAF: %zu\n", len); pr_debug("- LEAF: %zu\n", len);
dp += len;
} }
pc += asn1_op_lengths[op]; pc += asn1_op_lengths[op];
goto next_op; goto next_op;
......
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