summaryrefslogtreecommitdiffstats
path: root/src/core/settings.c
diff options
context:
space:
mode:
authorMichael Brown2013-07-17 15:00:38 +0200
committerMichael Brown2013-07-18 16:50:02 +0200
commit3880ebeb182208f03db32464b954dba1b8b8338b (patch)
tree64894c1c273e02b97172210fc960a9291c20f296 /src/core/settings.c
parent[settings] Clarify usage of the term "named setting" (diff)
downloadipxe-3880ebeb182208f03db32464b954dba1b8b8338b.tar.gz
ipxe-3880ebeb182208f03db32464b954dba1b8b8338b.tar.xz
ipxe-3880ebeb182208f03db32464b954dba1b8b8338b.zip
[settings] Avoid potentially large stack allocations
Avoid potentially large stack allocations in fetchf_setting() and storef_setting(). Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core/settings.c')
-rw-r--r--src/core/settings.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/src/core/settings.c b/src/core/settings.c
index 6d0c854f..891e7b3a 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -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;
}
/******************************************************************************