Fix removing temporary file after editing in (Disp)VM

Fix removing the file - do not free its filename just before unlink call
(scheduled with atexit function).
At the same time, place the temporary file in a unique directory,
making it possible to edit multiple files with the same name at once.
Remove that directory at exit too.

Fixes QubesOS/qubes-issues#3112
This commit is contained in:
Marek Marczykowski-Górecki 2017-10-19 15:18:20 +02:00
parent 2068299126
commit e2789ca2d7
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -15,6 +15,7 @@
// #define DEBUG // #define DEBUG
static const char *cleanup_filename = NULL; static const char *cleanup_filename = NULL;
static const char *cleanup_dirname = NULL;
static void cleanup_file(void) static void cleanup_file(void)
{ {
@ -23,6 +24,11 @@ static void cleanup_file(void)
fprintf(stderr, "Failed to remove file at exit\n"); fprintf(stderr, "Failed to remove file at exit\n");
cleanup_filename = NULL; cleanup_filename = NULL;
} }
if (cleanup_dirname) {
if (rmdir(cleanup_dirname) < 0)
fprintf(stderr, "Failed to remove directory at exit\n");
cleanup_dirname = NULL;
}
} }
const char *gettime(void) const char *gettime(void)
@ -40,8 +46,7 @@ static char *get_directory(void)
const char *remote_domain; const char *remote_domain;
char *dir; char *dir;
size_t len; size_t len;
struct stat dstat; char *ret;
int ret;
remote_domain = getenv("QREXEC_REMOTE_DOMAIN"); remote_domain = getenv("QREXEC_REMOTE_DOMAIN");
if (!remote_domain) { if (!remote_domain) {
@ -53,29 +58,21 @@ static char *get_directory(void)
if (!strcmp(remote_domain, ".") || !strcmp(remote_domain, "..")) if (!strcmp(remote_domain, ".") || !strcmp(remote_domain, ".."))
goto fail; goto fail;
len = strlen("/tmp")+1+strlen(remote_domain)+1; len = strlen("/tmp/-XXXXXX")+strlen(remote_domain)+1;
dir = malloc(len); dir = malloc(len);
if (!dir) { if (!dir) {
fprintf(stderr, "Cannot allocate memory\n"); fprintf(stderr, "Cannot allocate memory\n");
exit(1); exit(1);
} }
snprintf(dir, len, "/tmp/%s", remote_domain); snprintf(dir, len, "/tmp/%s-XXXXXX", remote_domain);
ret=mkdir(dir, 0777); ret = mkdtemp(dir);
if (ret<0 && errno!=EEXIST) { if (ret == NULL) {
perror("mkdir"); perror("mkdtemp");
exit(1); exit(1);
} }
if (stat(dir, &dstat)) { cleanup_dirname = strdup(ret);
perror("stat dir"); return ret;
exit(1);
}
if (!S_ISDIR(dstat.st_mode)) {
fprintf(stderr, "%s exists and is not a directory\n", dir);
exit(1);
}
return dir;
fail: fail:
fprintf(stderr, "Invalid remote domain name: %s\n", remote_domain); fprintf(stderr, "Invalid remote domain name: %s\n", remote_domain);
@ -122,7 +119,7 @@ void copy_file_by_name(const char *filename)
exit(1); exit(1);
} }
/* we now have created a new file, ensure we delete it at the end */ /* we now have created a new file, ensure we delete it at the end */
cleanup_filename = filename; cleanup_filename = strdup(filename);
atexit(cleanup_file); atexit(cleanup_file);
if (!copy_fd_all(fd, 0)) if (!copy_fd_all(fd, 0))
exit(1); exit(1);