2010-04-09 Chris Allegretta <chrisa@asty.org>
* files.c (do_writeout): Better security fixes for backup file writing, mangled from submission by Dan Rosenberg <dan.j.rosenberg at gmail>. git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4496 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
dbbf9a052f
commit
7f61a6cb79
|
@ -1,4 +1,8 @@
|
||||||
2010-04-02 Chris Allegretta <chrisa@asty.org>
|
2010-04-09 Chris Allegretta <chrisa@asty.org>
|
||||||
|
* files.c (do_writeout): Better security fixes for backup file writing,
|
||||||
|
mangled from submission by Dan Rosenberg <dan.j.rosenberg at gmail>.
|
||||||
|
|
||||||
|
2010-04-08 Chris Allegretta <chrisa@asty.org>
|
||||||
* files.c (do_writeout): Previous fixes should not cause a crash
|
* files.c (do_writeout): Previous fixes should not cause a crash
|
||||||
when saving a new file. Discovered by Mike Frysinger <vapier@gentoo.org>.
|
when saving a new file. Discovered by Mike Frysinger <vapier@gentoo.org>.
|
||||||
|
|
||||||
|
|
38
src/files.c
38
src/files.c
|
@ -1515,11 +1515,11 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type
|
||||||
if (ISSET(BACKUP_FILE) && !tmp && realexists && ((append !=
|
if (ISSET(BACKUP_FILE) && !tmp && realexists && ((append !=
|
||||||
OVERWRITE || openfile->mark_set) ||
|
OVERWRITE || openfile->mark_set) ||
|
||||||
openfile->current_stat->st_mtime == st.st_mtime)) {
|
openfile->current_stat->st_mtime == st.st_mtime)) {
|
||||||
|
int backup_fd;
|
||||||
FILE *backup_file;
|
FILE *backup_file;
|
||||||
char *backupname;
|
char *backupname;
|
||||||
struct utimbuf filetime;
|
struct utimbuf filetime;
|
||||||
int copy_status;
|
int copy_status;
|
||||||
struct stat backupst;
|
|
||||||
|
|
||||||
/* Save the original file's access and modification times. */
|
/* Save the original file's access and modification times. */
|
||||||
filetime.actime = openfile->current_stat->st_atime;
|
filetime.actime = openfile->current_stat->st_atime;
|
||||||
|
@ -1589,26 +1589,35 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type
|
||||||
sprintf(backupname, "%s~", realname);
|
sprintf(backupname, "%s~", realname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat(backupname, &backupst) != -1 &&
|
/* First, unlink any existing backups. Next, open the backup
|
||||||
(backupst.st_uid != st.st_uid)) {
|
file with O_CREAT and O_EXCL. If it succeeds, we
|
||||||
statusbar(_("Error writing backup file %s: File owner mismatch"), backupname,
|
have a file descriptor to a new backup file. */
|
||||||
|
if (unlink(backupname) < 0 && errno != ENOENT) {
|
||||||
|
statusbar(_("Error writing backup file %s: %s"), backupname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
free(backupname);
|
free(backupname);
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backup_fd = open(backupname, O_WRONLY | O_CREAT | O_APPEND,
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||||
|
/* Now we've got a safe file stream. If the previous open()
|
||||||
|
call failed, this will return NULL. */
|
||||||
|
backup_file = fdopen(backup_fd, "wb");
|
||||||
|
|
||||||
/* Open the destination backup file. Before we write to it, we
|
if (backup_fd < 0 || backup_file == NULL) {
|
||||||
* set its permissions, so no unauthorized person can read it as
|
statusbar(_("Error writing backup file %s: %s"), backupname,
|
||||||
* we write. */
|
strerror(errno));
|
||||||
backup_file = fopen(backupname, "wb");
|
free(backupname);
|
||||||
|
goto cleanup_and_exit;
|
||||||
if (backup_file == NULL || chmod(backupname,
|
}
|
||||||
openfile->current_stat->st_mode) == -1) {
|
|
||||||
|
if (fchmod(backup_fd, openfile->current_stat->st_mode) == -1 ||
|
||||||
|
fchown(backup_fd, openfile->current_stat->st_uid,
|
||||||
|
openfile->current_stat->st_gid) == -1 ) {
|
||||||
statusbar(_("Error writing backup file %s: %s"), backupname,
|
statusbar(_("Error writing backup file %s: %s"), backupname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
free(backupname);
|
free(backupname);
|
||||||
if (backup_file != NULL)
|
|
||||||
fclose(backup_file);
|
fclose(backup_file);
|
||||||
/* If we can't write to the backup, DONT go on, since
|
/* If we can't write to the backup, DONT go on, since
|
||||||
whatever caused the backup file to fail (e.g. disk
|
whatever caused the backup file to fail (e.g. disk
|
||||||
|
@ -1625,10 +1634,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type
|
||||||
copy_status = copy_file(f, backup_file);
|
copy_status = copy_file(f, backup_file);
|
||||||
|
|
||||||
/* And set its metadata. */
|
/* And set its metadata. */
|
||||||
if (copy_status != 0 || chown(backupname,
|
if (copy_status != 0 || utime(backupname, &filetime) == -1) {
|
||||||
openfile->current_stat->st_uid,
|
|
||||||
openfile->current_stat->st_gid) == -1 ||
|
|
||||||
utime(backupname, &filetime) == -1) {
|
|
||||||
if (copy_status == -1) {
|
if (copy_status == -1) {
|
||||||
statusbar(_("Error reading %s: %s"), realname,
|
statusbar(_("Error reading %s: %s"), realname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
|
Loading…
Reference in New Issue