s4-dsdb: use safe length limiting in string->integer conversion
authorAndrew Tridgell <tridge@samba.org>
Tue, 29 Dec 2009 00:38:17 +0000 (11:38 +1100)
committerAndrew Tridgell <tridge@samba.org>
Fri, 1 Jan 2010 21:16:55 +0000 (08:16 +1100)
The ldap.py test suite could trigger a read past the end of the struct
ldb_val buffer

source4/lib/ldb-samba/ldif_handlers.c

index 39fc93af9570dc6511b80561d6ce37c4b2ccf682..7ddc8e57a750c0a967f126e92cca302fe58d1a17 100644 (file)
@@ -678,20 +678,43 @@ static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
                                  v1, v2);
 }
 
-/* Canonicalisation of two 32-bit integers */
-static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
-                       const struct ldb_val *in, struct ldb_val *out)
+/* length limited conversion of a ldb_val to a int32_t */
+static int val_to_int32(const struct ldb_val *in, int32_t *v)
 {
        char *end;
+       char buf[64];
+
+       /* make sure we don't read past the end of the data */
+       if (in->length > sizeof(buf)-1) {
+               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+       }
+       strncpy(buf, (char *)in->data, in->length);
+       buf[in->length] = 0;
+
        /* We've to use "strtoll" here to have the intended overflows.
         * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
-       int32_t i = (int32_t) strtoll((char *)in->data, &end, 0);
+       *v = (int32_t) strtoll(buf, &end, 0);
        if (*end != 0) {
-               return -1;
+               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+       }
+       return LDB_SUCCESS;
+}
+
+/* Canonicalisation of two 32-bit integers */
+static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
+                       const struct ldb_val *in, struct ldb_val *out)
+{
+       int32_t i;
+       int ret;
+
+       ret = val_to_int32(in, &i);
+       if (ret != LDB_SUCCESS) {
+               return ret;
        }
        out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
        if (out->data == NULL) {
-               return -1;
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
        out->length = strlen((char *)out->data);
        return 0;
@@ -699,12 +722,13 @@ static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
 
 /* Comparison of two 32-bit integers */
 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
-                       const struct ldb_val *v1, const struct ldb_val *v2)
+                                const struct ldb_val *v1, const struct ldb_val *v2)
 {
-       /* We've to use "strtoll" here to have the intended overflows.
-        * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
-       return (int32_t) strtoll((char *)v1->data, NULL, 0)
-        - (int32_t) strtoll((char *)v2->data, NULL, 0);
+       int32_t i1=0, i2=0;
+       val_to_int32(v1, &i1);
+       val_to_int32(v2, &i2);
+       if (i1 == i2) return 0;
+       return i1 > i2? 1 : -1;
 }
 
 /*