From 5e7a3c2e7e118c7f12d5dfda9f9140f638976aa2 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sun, 28 Apr 2024 10:51:52 +0200 Subject: files: run `chmod` and `chown` on the descriptor, not on the filename This closes a window of opportunity where the emergency file could be replaced by a malicious symlink. The issue was reported by `MartinJM` and `InvisibleMeerkat`. Problem existed since version 2.2.0, commit 123110c5, when chmodding and chowning of the emergency .save file was added. Cherry-picked-by: Lukáš Zaoral Upstream-commit: 5e7a3c2e7e118c7f12d5dfda9f9140f638976aa2 diff --git a/src/nano.h b/src/nano.h index af3a793..55d8235 100644 --- a/src/nano.h +++ b/src/nano.h @@ -157,7 +157,7 @@ typedef enum { } message_type; typedef enum { - OVERWRITE, APPEND, PREPEND + OVERWRITE, APPEND, PREPEND, EMERGENCY } kind_of_writing_type; typedef enum { diff --git a/src/files.c b/src/files.c index 57c2001..584b579 100644 --- a/src/files.c +++ b/src/files.c @@ -1927,7 +1927,19 @@ bool write_file(const char *name, FILE *thefile, bool normal, } unlink(tempname); - } else if (fclose(f) != 0) { + } + +#ifndef NANO_TINY + /* Change permissions and owner of an emergency save file to the values + * of the original file, but ignore any failure as we are in a hurry. */ + if (method == EMERGENCY && fd && openfile->current_stat) { + IGNORE_CALL_RESULT(fchmod(fd, openfile->current_stat->st_mode)); + IGNORE_CALL_RESULT(fchown(fd, openfile->current_stat->st_uid, + openfile->current_stat->st_gid)); + } +#endif + + if (fclose(f) != 0) { statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno)); goto cleanup_and_exit; diff --git a/src/nano.c b/src/nano.c index 90b4a0b..973054f 100644 --- a/src/nano.c +++ b/src/nano.c @@ -644,25 +644,15 @@ void emergency_save(const char *filename) targetname = get_next_filename(die_filename, ".save"); if (*targetname != '\0') - failed = !write_file(targetname, NULL, TRUE, OVERWRITE, FALSE); + failed = !write_file(targetname, NULL, TRUE, EMERGENCY, FALSE); if (!failed) fprintf(stderr, _("\nBuffer written to %s\n"), targetname); else if (*targetname != '\0') fprintf(stderr, _("\nBuffer not written to %s: %s\n"), targetname, strerror(errno)); else fprintf(stderr, _("\nBuffer not written: %s\n"), _("Too many backup files?")); - -#ifndef NANO_TINY - /* Try to chmod/chown the saved file to the values of the original file, - * but ignore any failure as we are in a hurry to get out. */ - if (die_stat) { - IGNORE_CALL_RESULT(chmod(targetname, die_stat->st_mode)); - IGNORE_CALL_RESULT(chown(targetname, die_stat->st_uid, - die_stat->st_gid)); - } -#endif free(targetname); } -- cgit v1.1