]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[settings] Avoid potentially large stack allocations
authorMichael Brown <mcb30@ipxe.org>
Wed, 17 Jul 2013 13:00:38 +0000 (14:00 +0100)
committerMichael Brown <mcb30@ipxe.org>
Thu, 18 Jul 2013 14:50:02 +0000 (15:50 +0100)
Avoid potentially large stack allocations in fetchf_setting() and
storef_setting().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/core/settings.c

index 6d0c854f5f710a97ef9761f62a5d3b9e9b7d4de0..891e7b3a96d37e0a5cd87559492ccad617da01a3 100644 (file)
@@ -1046,28 +1046,32 @@ int setting_cmp ( struct setting *a, struct setting *b ) {
  */
 int fetchf_setting ( struct settings *settings, struct setting *setting,
                     char *buf, size_t len ) {
+       void *raw;
        int raw_len;
-       int check_len;
-       int rc;
+       int ret;
 
        /* Fetch raw value */
-       raw_len = fetch_setting_len ( settings, setting );
+       raw_len = fetch_setting_copy ( settings, setting, &raw );
        if ( raw_len < 0 ) {
-               rc = raw_len;
-               return rc;
-       } else {
-               uint8_t raw[raw_len];
-
-               /* Fetch raw value */
-               check_len = fetch_setting ( settings, setting, raw,
-                                           sizeof ( raw ) );
-               if ( check_len < 0 )
-                       return check_len;
-               assert ( check_len == raw_len );
+               ret = raw_len;
+               goto err_fetch_copy;
+       }
 
-               /* Format value */
-               return setting->type->format ( raw, sizeof ( raw ), buf, len );
+       /* Return error if setting does not exist */
+       if ( ! raw ) {
+               ret = -ENOENT;
+               goto err_exists;
        }
+
+       /* Format setting */
+       if ( ( ret = setting->type->format ( raw, raw_len, buf, len ) ) < 0 )
+               goto err_format;
+
+ err_format:
+       free ( raw );
+ err_exists:
+ err_fetch_copy:
+       return ret;
 }
 
 /**
@@ -1080,6 +1084,7 @@ int fetchf_setting ( struct settings *settings, struct setting *setting,
  */
 int storef_setting ( struct settings *settings, struct setting *setting,
                     const char *value ) {
+       void *raw;
        int raw_len;
        int check_len;
        int rc;
@@ -1088,21 +1093,33 @@ int storef_setting ( struct settings *settings, struct setting *setting,
        if ( ( ! value ) || ( ! value[0] ) )
                return delete_setting ( settings, setting );
 
-       /* Parse formatted value */
+       /* Get raw value length */
        raw_len = setting->type->parse ( value, NULL, 0 );
        if ( raw_len < 0 ) {
                rc = raw_len;
-               return rc;
-       } else {
-               uint8_t raw[raw_len];
-
-               /* Parse formatted value */
-               check_len = setting->type->parse ( value, raw, sizeof ( raw ) );
-               assert ( check_len == raw_len );
+               goto err_parse_len;
+       }
 
-               /* Store raw value */
-               return store_setting ( settings, setting, raw, sizeof ( raw ) );
+       /* Allocate buffer for raw value */
+       raw = malloc ( raw_len );
+       if ( ! raw ) {
+               rc = -ENOMEM;
+               goto err_alloc_raw;
        }
+
+       /* Parse formatted value */
+       check_len = setting->type->parse ( value, raw, raw_len );
+       assert ( check_len == raw_len );
+
+       /* Store raw value */
+       if ( ( rc = store_setting ( settings, setting, raw, raw_len ) ) != 0 )
+               goto err_store;
+
+ err_store:
+       free ( raw );
+ err_alloc_raw:
+ err_parse_len:
+       return rc;
 }
 
 /******************************************************************************