Skip to content
Snippets Groups Projects
Commit 33f0086c authored by Stefano Babic's avatar Stefano Babic Committed by Tom Rini
Browse files

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: default avatarStefano Babic <sbabic@denx.de>
parent 00c234f3
No related branches found
No related tags found
No related merge requests found
...@@ -278,6 +278,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts) ...@@ -278,6 +278,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
printf ("%s\n", env); printf ("%s\n", env);
} }
fw_env_close(opts);
return 0; return 0;
} }
...@@ -300,10 +301,12 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts) ...@@ -300,10 +301,12 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
printf("%s=%s\n", name, val); printf("%s=%s\n", name, val);
} }
fw_env_close(opts);
return rc; return rc;
} }
int fw_env_close(struct env_opts *opts) int fw_env_flush(struct env_opts *opts)
{ {
int ret; int ret;
...@@ -472,6 +475,7 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts) ...@@ -472,6 +475,7 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
char *name, **valv; char *name, **valv;
char *value = NULL; char *value = NULL;
int valc; int valc;
int ret;
if (!opts) if (!opts)
opts = &default_opts; opts = &default_opts;
...@@ -491,8 +495,10 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts) ...@@ -491,8 +495,10 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
valv = argv + 1; valv = argv + 1;
valc = argc - 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; return -1;
}
len = 0; len = 0;
for (i = 0; i < valc; ++i) { for (i = 0; i < valc; ++i) {
...@@ -518,7 +524,10 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts) ...@@ -518,7 +524,10 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
free(value); 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) ...@@ -639,7 +648,9 @@ int fw_parse_script(char *fname, struct env_opts *opts)
if (strcmp(fname, "-") != 0) if (strcmp(fname, "-") != 0)
fclose(fp); fclose(fp);
ret |= fw_env_close(opts); ret |= fw_env_flush(opts);
fw_env_close(opts);
return ret; return ret;
} }
...@@ -1105,11 +1116,11 @@ int fw_env_open(struct env_opts *opts) ...@@ -1105,11 +1116,11 @@ int fw_env_open(struct env_opts *opts)
{ {
int crc0, crc0_ok; int crc0, crc0_ok;
unsigned char flag0; unsigned char flag0;
void *addr0; void *addr0 = NULL;
int crc1, crc1_ok; int crc1, crc1_ok;
unsigned char flag1; unsigned char flag1;
void *addr1; void *addr1 = NULL;
int ret; int ret;
...@@ -1120,14 +1131,15 @@ int fw_env_open(struct env_opts *opts) ...@@ -1120,14 +1131,15 @@ int fw_env_open(struct env_opts *opts)
opts = &default_opts; opts = &default_opts;
if (parse_config(opts)) /* should fill envdevices */ if (parse_config(opts)) /* should fill envdevices */
return -1; return -EINVAL;
addr0 = calloc(1, CUR_ENVSIZE); addr0 = calloc(1, CUR_ENVSIZE);
if (addr0 == NULL) { if (addr0 == NULL) {
fprintf(stderr, fprintf(stderr,
"Not enough memory for environment (%ld bytes)\n", "Not enough memory for environment (%ld bytes)\n",
CUR_ENVSIZE); CUR_ENVSIZE);
return -1; ret = -ENOMEM;
goto open_cleanup;
} }
/* read environment from FLASH to local buffer */ /* read environment from FLASH to local buffer */
...@@ -1146,8 +1158,10 @@ int fw_env_open(struct env_opts *opts) ...@@ -1146,8 +1158,10 @@ int fw_env_open(struct env_opts *opts)
} }
dev_current = 0; dev_current = 0;
if (flash_io (O_RDONLY)) if (flash_io(O_RDONLY)) {
return -1; ret = -EIO;
goto open_cleanup;
}
crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
...@@ -1155,7 +1169,7 @@ int fw_env_open(struct env_opts *opts) ...@@ -1155,7 +1169,7 @@ int fw_env_open(struct env_opts *opts)
ret = env_aes_cbc_crypt(environment.data, 0, ret = env_aes_cbc_crypt(environment.data, 0,
opts->aes_key); opts->aes_key);
if (ret) if (ret)
return ret; goto open_cleanup;
} }
crc0_ok = (crc0 == *environment.crc); crc0_ok = (crc0 == *environment.crc);
...@@ -1174,7 +1188,8 @@ int fw_env_open(struct env_opts *opts) ...@@ -1174,7 +1188,8 @@ int fw_env_open(struct env_opts *opts)
fprintf(stderr, fprintf(stderr,
"Not enough memory for environment (%ld bytes)\n", "Not enough memory for environment (%ld bytes)\n",
CUR_ENVSIZE); CUR_ENVSIZE);
return -1; ret = -ENOMEM;
goto open_cleanup;
} }
redundant = addr1; redundant = addr1;
...@@ -1183,8 +1198,10 @@ int fw_env_open(struct env_opts *opts) ...@@ -1183,8 +1198,10 @@ int fw_env_open(struct env_opts *opts)
* other pointers in environment still point inside addr0 * other pointers in environment still point inside addr0
*/ */
environment.image = addr1; environment.image = addr1;
if (flash_io (O_RDONLY)) if (flash_io(O_RDONLY)) {
return -1; ret = -EIO;
goto open_cleanup;
}
/* Check flag scheme compatibility */ /* Check flag scheme compatibility */
if (DEVTYPE(dev_current) == MTD_NORFLASH && if (DEVTYPE(dev_current) == MTD_NORFLASH &&
...@@ -1204,7 +1221,8 @@ int fw_env_open(struct env_opts *opts) ...@@ -1204,7 +1221,8 @@ int fw_env_open(struct env_opts *opts)
environment.flag_scheme = FLAG_INCREMENTAL; environment.flag_scheme = FLAG_INCREMENTAL;
} else { } else {
fprintf (stderr, "Incompatible flash types!\n"); fprintf (stderr, "Incompatible flash types!\n");
return -1; ret = -EINVAL;
goto open_cleanup;
} }
crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
...@@ -1213,7 +1231,7 @@ int fw_env_open(struct env_opts *opts) ...@@ -1213,7 +1231,7 @@ int fw_env_open(struct env_opts *opts)
ret = env_aes_cbc_crypt(redundant->data, 0, ret = env_aes_cbc_crypt(redundant->data, 0,
opts->aes_key); opts->aes_key);
if (ret) if (ret)
return ret; goto open_cleanup;
} }
crc1_ok = (crc1 == redundant->crc); crc1_ok = (crc1 == redundant->crc);
...@@ -1285,6 +1303,28 @@ int fw_env_open(struct env_opts *opts) ...@@ -1285,6 +1303,28 @@ int fw_env_open(struct env_opts *opts)
#endif #endif
} }
return 0; 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) static int check_device_config(int dev)
......
...@@ -53,7 +53,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts); ...@@ -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 * @opts: how to retrieve environment from flash, defaults are used if NULL
* *
* Description: * Description:
* Uses fw_env_open, fw_env_write, fw_env_close * Uses fw_env_open, fw_env_write, fw_env_flush
* *
* Return: * Return:
* 0 on success, -1 on failure (modifies errno) * 0 on success, -1 on failure (modifies errno)
...@@ -70,7 +70,7 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts); ...@@ -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 * @opts: encryption key, configuration file, defaults are used if NULL
* *
* Description: * Description:
* Uses fw_env_open, fw_env_write, fw_env_close * Uses fw_env_open, fw_env_write, fw_env_flush
* *
* Return: * Return:
* 0 success, -1 on failure (modifies errno) * 0 success, -1 on failure (modifies errno)
...@@ -138,7 +138,17 @@ char *fw_getenv(char *name); ...@@ -138,7 +138,17 @@ char *fw_getenv(char *name);
int fw_env_write(char *name, char *value); 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 * @opts: encryption key, configuration file, defaults are used if NULL
* *
...@@ -147,6 +157,7 @@ int fw_env_write(char *name, char *value); ...@@ -147,6 +157,7 @@ int fw_env_write(char *name, char *value);
*/ */
int fw_env_close(struct env_opts *opts); int fw_env_close(struct env_opts *opts);
/** /**
* fw_env_version - return the current version of the library * fw_env_version - return the current version of the library
* *
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment