commit 0583c4cc97a2206fc4cb5a33bc46d12b934a1c30 from: Stefan Sperling date: Sun Sep 03 12:59:36 2023 UTC avoid potential corruption of ~/.nshenv during saveenv Write to a temporary file and rename on top of ~/.nshenv instead of modifying the file in-place. commit - 44f8036e904cc038f2370d7f1736e16683f7d128 commit + 0583c4cc97a2206fc4cb5a33bc46d12b934a1c30 blob - 6b02de2bf2ad5e613b4eb9949ed3ef62ef6377b2 blob + e1d4d63874e32cdd55d0cd9b33e4d80650fab772 --- commands.c +++ commands.c @@ -2434,10 +2434,10 @@ savevar(void *keyptr, size_t keysize, void *value, siz static int saveenvcmd(int argc, char **argv) { - char path[PATH_MAX]; + char tmppath[PATH_MAX], path[PATH_MAX]; FILE *f; char *home; - int ret; + int ret, fd; if (argc != 1) { printf("%% usage: saveenv\n"); @@ -2459,16 +2459,38 @@ saveenvcmd(int argc, char **argv) return 0; } - f = fopen(path, "w"); + ret = snprintf(tmppath, sizeof(tmppath), "%s/.nshenv-XXXXXXXXXX", home); + if (ret < 0 || (size_t)ret >= sizeof(tmppath)) { + printf("%% path to ~/.nshenv is too long\n"); + return 0; + } + + fd = mkstemp(tmppath); + if (fd == -1) { + printf("%s: mkstemp %s: %s", __func__, tmppath, + strerror(errno)); + return 0; + } + + + f = fdopen(fd, "w"); if (f == NULL) { - printf("%% fopen %s: %s\n", path, strerror(errno)); + printf("%% fopen %s: %s\n", tmppath, strerror(errno)); + close(fd); return 0; } if (fchmod(fileno(f), S_IRUSR | S_IWUSR) == -1) - printf("%% chmod 600 %s: %s\n", path, strerror(errno)); + printf("%% chmod 600 %s: %s\n", tmppath, strerror(errno)); hashtable_foreach(nsh_env, savevar, f); + + if (rename(tmppath, path) == -1) { + printf("%% rename %s %s: %s\n", tmppath, path, strerror(errno)); + if (unlink(tmppath) == -1) + printf("%% unlink %s: %s\n", tmppath, strerror(errno)); + } + fclose(f); return 0;