Fix an arbitrary out-of-bounds stack read in v2i_IPAddrBlocks()
authortb <tb@openbsd.org>
Thu, 23 Dec 2021 23:41:26 +0000 (23:41 +0000)
committertb <tb@openbsd.org>
Thu, 23 Dec 2021 23:41:26 +0000 (23:41 +0000)
Switch an insufficiently checked strtoul() to strtonum(). This can
be used to trigger a read of a user-controlled size from the stack.

$ openssl req -new -addext 'sbgp-ipAddrBlock = IPv4:192.0.2.0/12341234'
Segmentation fault (core dumped)

The bogus prefix length 12341234 is fed into X509v3_addr_add_prefix() and
used to read (prefixlen + 7) / 8 bytes from the stack variable 'min[16]'
that ends up as 'data' in the memmove in ASN1_STRING_set().

The full fix will add length checks to X509v3_addr_add_prefix() and
make_addressPrefix() and will be dealt with later. The entire
X509v3_{addr,asid}_* API will need a thorough review before it can be
exposed.

This code is only enabled in -current and can only be reached from
openssl.cnf files that contain sbgp-ipAddrBlock or from the openssl(1)
command line.

ok jsing

lib/libcrypto/x509/x509_addr.c

index d543bdd..f628009 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: x509_addr.c,v 1.20 2021/12/18 16:58:20 tb Exp $ */
+/*     $OpenBSD: x509_addr.c,v 1.21 2021/12/23 23:41:26 tb Exp $ */
 /*
  * Contributed to the OpenSSL Project by the American Registry for
  * Internet Numbers ("ARIN").
@@ -1181,6 +1181,7 @@ v2i_IPAddrBlocks(const struct v3_ext_method *method, struct v3_ext_ctx *ctx,
                unsigned char min[ADDR_RAW_BUF_LEN], max[ADDR_RAW_BUF_LEN];
                unsigned afi, *safi = NULL, safi_;
                const char *addr_chars = NULL;
+               const char *errstr;
                int prefixlen, i1, i2, delim, length;
 
                if (!name_cmp(val->name, "IPv4")) {
@@ -1260,8 +1261,11 @@ v2i_IPAddrBlocks(const struct v3_ext_method *method, struct v3_ext_ctx *ctx,
 
                switch (delim) {
                case '/':
-                       prefixlen = (int)strtoul(s + i2, &t, 10);
-                       if (t == s + i2 || *t != '\0') {
+                       /* length contains the size of the address in bytes. */
+                       if (length != 4 && length != 16)
+                               goto err;
+                       prefixlen = strtonum(s + i2, 0, 8 * length, &errstr);
+                       if (errstr != NULL) {
                                X509V3error(X509V3_R_EXTENSION_VALUE_ERROR);
                                X509V3_conf_err(val);
                                goto err;