aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-10-04 09:21:23 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-10-10 05:36:39 -0400
commitdbadc17683e6c673a69b236c0f041b931cc55c42 (patch)
treeec29aabfa428ca2c06caba94595b8c5d51a687e7
parent2f1c4fef103ef914e266588af263fb42b502b347 (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.c28
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 */
50static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, 55static 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
57next_tag: 63next_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:
122missing_eoc: 131missing_eoc:
123 *_errmsg = "Missing EOC in indefinite len cons"; 132 *_errmsg = "Missing EOC in indefinite len cons";
124error: 133error:
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;