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; |