diff options
| author | David Howells <dhowells@redhat.com> | 2012-10-04 09:21:23 -0400 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-10-10 05:36:39 -0400 |
| commit | dbadc17683e6c673a69b236c0f041b931cc55c42 (patch) | |
| tree | ec29aabfa428ca2c06caba94595b8c5d51a687e7 | |
| parent | 2f1c4fef103ef914e266588af263fb42b502b347 (diff) | |
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: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
| -rw-r--r-- | lib/asn1_decoder.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 2e4196ddf06f..de2c8b5a715b 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c | |||
| @@ -46,12 +46,18 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { | |||
| 46 | 46 | ||
| 47 | /* | 47 | /* |
| 48 | * Find the length of an indefinite length object | 48 | * Find the length of an indefinite length object |
| 49 | * @data: The data buffer | ||
| 50 | * @datalen: The end of the innermost containing element in the buffer | ||
| 51 | * @_dp: The data parse cursor (updated before returning) | ||
| 52 | * @_len: Where to return the size of the element. | ||
| 53 | * @_errmsg: Where to return a pointer to an error message on error | ||
| 49 | */ | 54 | */ |
| 50 | static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, | 55 | static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, |
| 51 | const char **_errmsg, size_t *_err_dp) | 56 | size_t *_dp, size_t *_len, |
| 57 | const char **_errmsg) | ||
| 52 | { | 58 | { |
| 53 | unsigned char tag, tmp; | 59 | unsigned char tag, tmp; |
| 54 | size_t dp = 0, len, n; | 60 | size_t dp = *_dp, len, n; |
| 55 | int indef_level = 1; | 61 | int indef_level = 1; |
| 56 | 62 | ||
| 57 | next_tag: | 63 | next_tag: |
| @@ -67,8 +73,11 @@ next_tag: | |||
| 67 | /* It appears to be an EOC. */ | 73 | /* It appears to be an EOC. */ |
| 68 | if (data[dp++] != 0) | 74 | if (data[dp++] != 0) |
| 69 | goto invalid_eoc; | 75 | goto invalid_eoc; |
| 70 | if (--indef_level <= 0) | 76 | if (--indef_level <= 0) { |
| 71 | return dp; | 77 | *_len = dp - *_dp; |
| 78 | *_dp = dp; | ||
| 79 | return 0; | ||
| 80 | } | ||
| 72 | goto next_tag; | 81 | goto next_tag; |
| 73 | } | 82 | } |
| 74 | 83 | ||
| @@ -122,7 +131,7 @@ data_overrun_error: | |||
| 122 | missing_eoc: | 131 | missing_eoc: |
| 123 | *_errmsg = "Missing EOC in indefinite len cons"; | 132 | *_errmsg = "Missing EOC in indefinite len cons"; |
| 124 | error: | 133 | error: |
| 125 | *_err_dp = dp; | 134 | *_dp = dp; |
| 126 | return -1; | 135 | return -1; |
| 127 | } | 136 | } |
| 128 | 137 | ||
| @@ -315,13 +324,14 @@ next_op: | |||
| 315 | skip_data: | 324 | skip_data: |
| 316 | if (!(flags & FLAG_CONS)) { | 325 | if (!(flags & FLAG_CONS)) { |
| 317 | if (flags & FLAG_INDEFINITE_LENGTH) { | 326 | if (flags & FLAG_INDEFINITE_LENGTH) { |
| 318 | len = asn1_find_indefinite_length( | 327 | ret = asn1_find_indefinite_length( |
| 319 | data + dp, datalen - dp, &errmsg, &dp); | 328 | data, datalen, &dp, &len, &errmsg); |
| 320 | if (len < 0) | 329 | if (ret < 0) |
| 321 | goto error; | 330 | goto error; |
| 331 | } else { | ||
| 332 | dp += len; | ||
| 322 | } | 333 | } |
| 323 | pr_debug("- LEAF: %zu\n", len); | 334 | pr_debug("- LEAF: %zu\n", len); |
| 324 | dp += len; | ||
| 325 | } | 335 | } |
| 326 | pc += asn1_op_lengths[op]; | 336 | pc += asn1_op_lengths[op]; |
| 327 | goto next_op; | 337 | goto next_op; |
