Browse Source

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
Marek Marczykowski-Górecki 6 years ago
parent
commit
e2789ca2d7
1 changed files with 15 additions and 18 deletions
  1. 15 18
      qubes-rpc/vm-file-editor.c

+ 15 - 18
qubes-rpc/vm-file-editor.c

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