summary refs log tree commit diff
path: root/lib/asn1_decoder.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-10-04 14:21:23 +0100
committerRusty Russell <rusty@rustcorp.com.au>2012-10-10 20:06:39 +1030
commitdbadc17683e6c673a69b236c0f041b931cc55c42 (patch)
treeec29aabfa428ca2c06caba94595b8c5d51a687e7 /lib/asn1_decoder.c
parent2f1c4fef103ef914e266588af263fb42b502b347 (diff)
downloadlinux-dbadc17683e6c673a69b236c0f041b931cc55c42.tar.gz
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>
Diffstat (limited to 'lib/asn1_decoder.c')
-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] = {
 
 /*
  * 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,
-				       const char **_errmsg, size_t *_err_dp)
+				       size_t *_dp, size_t *_len,
+				       const char **_errmsg)
 {
 	unsigned char tag, tmp;
-	size_t dp = 0, len, n;
+	size_t dp = *_dp, len, n;
 	int indef_level = 1;
 
 next_tag:
@@ -67,8 +73,11 @@ next_tag:
 		/* It appears to be an EOC. */
 		if (data[dp++] != 0)
 			goto invalid_eoc;
-		if (--indef_level <= 0)
-			return dp;
+		if (--indef_level <= 0) {
+			*_len = dp - *_dp;
+			*_dp = dp;
+			return 0;
+		}
 		goto next_tag;
 	}
 
@@ -122,7 +131,7 @@ data_overrun_error:
 missing_eoc:
 	*_errmsg = "Missing EOC in indefinite len cons";
 error:
-	*_err_dp = dp;
+	*_dp = dp;
 	return -1;
 }
 
@@ -315,13 +324,14 @@ next_op:
 	skip_data:
 		if (!(flags & FLAG_CONS)) {
 			if (flags & FLAG_INDEFINITE_LENGTH) {
-				len = asn1_find_indefinite_length(
-					data + dp, datalen - dp, &errmsg, &dp);
-				if (len < 0)
+				ret = asn1_find_indefinite_length(
+					data, datalen, &dp, &len, &errmsg);
+				if (ret < 0)
 					goto error;
+			} else {
+				dp += len;
 			}
 			pr_debug("- LEAF: %zu\n", len);
-			dp += len;
 		}
 		pc += asn1_op_lengths[op];
 		goto next_op;