|
|
@@ -0,0 +1,267 @@
|
|
|
+From 5ba7e08c4188064286533e896189f75c3d60af57 Mon Sep 17 00:00:00 2001
|
|
|
+From: Stefano Babic <sbabic@denx.de>
|
|
|
+Date: Wed, 5 Apr 2017 17:23:44 +0200
|
|
|
+Subject: [PATCH v1 4/4] env: fix memory leak in fw_env routines
|
|
|
+
|
|
|
+fw_env_open allocates buffers to store the environment, but these
|
|
|
+buffers are never freed. This becomes quite nasty using the fw_ tools as
|
|
|
+library, because each access to the environment (even just reading a
|
|
|
+variable) generates a memory leak equal to the size of the environment.
|
|
|
+
|
|
|
+Fix this renaming fw_env_close() as fw_env_flush(), because the function
|
|
|
+really flushes the environment from RAM to storage, and add a
|
|
|
+fw_env_close function to free the allocated resources.
|
|
|
+
|
|
|
+Signed-off-by: Stefano Babic <sbabic@denx.de>
|
|
|
+---
|
|
|
+
|
|
|
+ tools/env/fw_env.c | 72 ++++++++++++++++++++++++++++++++++++++++++------------
|
|
|
+ tools/env/fw_env.h | 17 ++++++++++---
|
|
|
+ 2 files changed, 70 insertions(+), 19 deletions(-)
|
|
|
+
|
|
|
+diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
|
|
|
+index fc3f4ce..299e0c9 100644
|
|
|
+--- a/tools/env/fw_env.c
|
|
|
++++ b/tools/env/fw_env.c
|
|
|
+@@ -278,6 +278,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
|
|
|
+
|
|
|
+ printf ("%s\n", env);
|
|
|
+ }
|
|
|
++ fw_env_close(opts);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -300,10 +301,12 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
|
|
|
+ printf("%s=%s\n", name, val);
|
|
|
+ }
|
|
|
+
|
|
|
++ fw_env_close(opts);
|
|
|
++
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+-int fw_env_close(struct env_opts *opts)
|
|
|
++int fw_env_flush(struct env_opts *opts)
|
|
|
+ {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+@@ -472,6 +475,7 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
|
|
|
+ char *name, **valv;
|
|
|
+ char *value = NULL;
|
|
|
+ int valc;
|
|
|
++ int ret;
|
|
|
+
|
|
|
+ if (!opts)
|
|
|
+ opts = &default_opts;
|
|
|
+@@ -491,8 +495,10 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
|
|
|
+ valv = argv + 1;
|
|
|
+ valc = argc - 1;
|
|
|
+
|
|
|
+- if (env_flags_validate_env_set_params(name, valv, valc) < 0)
|
|
|
++ if (env_flags_validate_env_set_params(name, valv, valc) < 0) {
|
|
|
++ fw_env_close(opts);
|
|
|
+ return -1;
|
|
|
++ }
|
|
|
+
|
|
|
+ len = 0;
|
|
|
+ for (i = 0; i < valc; ++i) {
|
|
|
+@@ -518,7 +524,10 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
|
|
|
+
|
|
|
+ free(value);
|
|
|
+
|
|
|
+- return fw_env_close(opts);
|
|
|
++ ret = fw_env_flush(opts);
|
|
|
++ fw_env_close(opts);
|
|
|
++
|
|
|
++ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+@@ -639,7 +648,9 @@ int fw_parse_script(char *fname, struct env_opts *opts)
|
|
|
+ if (strcmp(fname, "-") != 0)
|
|
|
+ fclose(fp);
|
|
|
+
|
|
|
+- ret |= fw_env_close(opts);
|
|
|
++ ret |= fw_env_flush(opts);
|
|
|
++
|
|
|
++ fw_env_close(opts);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+@@ -1105,11 +1116,11 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ {
|
|
|
+ int crc0, crc0_ok;
|
|
|
+ unsigned char flag0;
|
|
|
+- void *addr0;
|
|
|
++ void *addr0 = NULL;
|
|
|
+
|
|
|
+ int crc1, crc1_ok;
|
|
|
+ unsigned char flag1;
|
|
|
+- void *addr1;
|
|
|
++ void *addr1 = NULL;
|
|
|
+
|
|
|
+ int ret;
|
|
|
+
|
|
|
+@@ -1120,14 +1131,15 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ opts = &default_opts;
|
|
|
+
|
|
|
+ if (parse_config(opts)) /* should fill envdevices */
|
|
|
+- return -1;
|
|
|
++ return -EINVAL;
|
|
|
+
|
|
|
+ addr0 = calloc(1, CUR_ENVSIZE);
|
|
|
+ if (addr0 == NULL) {
|
|
|
+ fprintf(stderr,
|
|
|
+ "Not enough memory for environment (%ld bytes)\n",
|
|
|
+ CUR_ENVSIZE);
|
|
|
+- return -1;
|
|
|
++ ret = -ENOMEM;
|
|
|
++ goto open_cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* read environment from FLASH to local buffer */
|
|
|
+@@ -1146,8 +1158,10 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ }
|
|
|
+
|
|
|
+ dev_current = 0;
|
|
|
+- if (flash_io (O_RDONLY))
|
|
|
+- return -1;
|
|
|
++ if (flash_io(O_RDONLY)) {
|
|
|
++ ret = -EIO;
|
|
|
++ goto open_cleanup;
|
|
|
++ }
|
|
|
+
|
|
|
+ crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
|
|
|
+
|
|
|
+@@ -1155,7 +1169,7 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ ret = env_aes_cbc_crypt(environment.data, 0,
|
|
|
+ opts->aes_key);
|
|
|
+ if (ret)
|
|
|
+- return ret;
|
|
|
++ goto open_cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ crc0_ok = (crc0 == *environment.crc);
|
|
|
+@@ -1174,7 +1188,8 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ fprintf(stderr,
|
|
|
+ "Not enough memory for environment (%ld bytes)\n",
|
|
|
+ CUR_ENVSIZE);
|
|
|
+- return -1;
|
|
|
++ ret = -ENOMEM;
|
|
|
++ goto open_cleanup;
|
|
|
+ }
|
|
|
+ redundant = addr1;
|
|
|
+
|
|
|
+@@ -1183,8 +1198,10 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ * other pointers in environment still point inside addr0
|
|
|
+ */
|
|
|
+ environment.image = addr1;
|
|
|
+- if (flash_io (O_RDONLY))
|
|
|
+- return -1;
|
|
|
++ if (flash_io(O_RDONLY)) {
|
|
|
++ ret = -EIO;
|
|
|
++ goto open_cleanup;
|
|
|
++ }
|
|
|
+
|
|
|
+ /* Check flag scheme compatibility */
|
|
|
+ if (DEVTYPE(dev_current) == MTD_NORFLASH &&
|
|
|
+@@ -1204,7 +1221,8 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ environment.flag_scheme = FLAG_INCREMENTAL;
|
|
|
+ } else {
|
|
|
+ fprintf (stderr, "Incompatible flash types!\n");
|
|
|
+- return -1;
|
|
|
++ ret = -EINVAL;
|
|
|
++ goto open_cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
|
|
|
+@@ -1213,7 +1231,7 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ ret = env_aes_cbc_crypt(redundant->data, 0,
|
|
|
+ opts->aes_key);
|
|
|
+ if (ret)
|
|
|
+- return ret;
|
|
|
++ goto open_cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ crc1_ok = (crc1 == redundant->crc);
|
|
|
+@@ -1285,6 +1303,28 @@ int fw_env_open(struct env_opts *opts)
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
++
|
|
|
++open_cleanup:
|
|
|
++ if (addr0)
|
|
|
++ free(addr0);
|
|
|
++
|
|
|
++ if (addr1)
|
|
|
++ free(addr0);
|
|
|
++
|
|
|
++ return ret;
|
|
|
++}
|
|
|
++
|
|
|
++/*
|
|
|
++ * Simply free allocated buffer with environment
|
|
|
++ */
|
|
|
++int fw_env_close(struct env_opts *opts)
|
|
|
++{
|
|
|
++ if (environment.image)
|
|
|
++ free(environment.image);
|
|
|
++
|
|
|
++ environment.image = NULL;
|
|
|
++
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int check_device_config(int dev)
|
|
|
+diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
|
|
|
+index cf346b3..04bb646 100644
|
|
|
+--- a/tools/env/fw_env.h
|
|
|
++++ b/tools/env/fw_env.h
|
|
|
+@@ -53,7 +53,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts);
|
|
|
+ * @opts: how to retrieve environment from flash, defaults are used if NULL
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+- * Uses fw_env_open, fw_env_write, fw_env_close
|
|
|
++ * Uses fw_env_open, fw_env_write, fw_env_flush
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ * 0 on success, -1 on failure (modifies errno)
|
|
|
+@@ -70,7 +70,7 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts);
|
|
|
+ * @opts: encryption key, configuration file, defaults are used if NULL
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+- * Uses fw_env_open, fw_env_write, fw_env_close
|
|
|
++ * Uses fw_env_open, fw_env_write, fw_env_flush
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ * 0 success, -1 on failure (modifies errno)
|
|
|
+@@ -138,7 +138,17 @@ char *fw_getenv(char *name);
|
|
|
+ int fw_env_write(char *name, char *value);
|
|
|
+
|
|
|
+ /**
|
|
|
+- * fw_env_close - write the environment from RAM cache back to flash
|
|
|
++ * fw_env_flush - write the environment from RAM cache back to flash
|
|
|
++ *
|
|
|
++ * @opts: encryption key, configuration file, defaults are used if NULL
|
|
|
++ *
|
|
|
++ * Return:
|
|
|
++ * 0 on success, -1 on failure (modifies errno)
|
|
|
++ */
|
|
|
++int fw_env_flush(struct env_opts *opts);
|
|
|
++
|
|
|
++/**
|
|
|
++ * fw_env_close - free allocated structure and close env
|
|
|
+ *
|
|
|
+ * @opts: encryption key, configuration file, defaults are used if NULL
|
|
|
+ *
|
|
|
+@@ -147,6 +157,7 @@ int fw_env_write(char *name, char *value);
|
|
|
+ */
|
|
|
+ int fw_env_close(struct env_opts *opts);
|
|
|
+
|
|
|
++
|
|
|
+ /**
|
|
|
+ * fw_env_version - return the current version of the library
|
|
|
+ *
|
|
|
+--
|
|
|
+2.7.4
|
|
|
+
|