Re: curiosities with tempfile.active

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 24.08.22 um 11:35 schrieb Jeff King:
> But here's the interesting twist. Commit 2c2db194bd (tempfile: add
> mks_tempfile_dt(), 2022-04-20) recently taught remove_tempfiles() to
> drop a surrounding directory. And it does so by munging the filename
> buffer. It has to, because we can't allocate a new buffer in a signal
> handler.
>
> But is it also idempotent(-ish)? The directory removal itself is,
> because it checks:
>
>   tempfile->filename.buf[tempfile->directorylen] == '/'
>
> before overwriting that byte with a NUL, so it should only be true once
> (though I note this violates the usual "volatile" rules for signal
> handlers, it's probably OK in practice since we know the NUL will be
> written before we call rmdir()).
>
> But after that happens, the filename buffer now contains a C string that
> points to the directory. And if we end up in remove_tempfiles() again
> due to another signal, we'll try to unlink(p->filename.buf), which will
> now unlink the directory! I'm not sure how that behaves on all systems.
> On Linux it's a noop. And if it just deleted the directory, that would
> be OK. I seem to recall on old versions of SunOS it did bad things
> (maybe because it really did unlink it, but without checking for
> orphaned entries inside).

https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html
says of the unlink(2) parameter: "The path argument shall not name a
directory unless the process has appropriate privileges and the
implementation supports using unlink() on directories."  So we better
not do that..

--- >8 ---
Subject: [PATCH] tempfile: avoid directory cleanup race

The temporary directory created by mks_tempfile_dt() is deleted by first
deleting the file within, then truncating the filename strbuf and
passing the resulting string to rmdir(2).  When the cleanup routine is
invoked concurrently by a signal handler we can end up passing the now
truncated string to unlink(2), however, which could cause problems on
some systems.

Avoid that issue by remembering the directory name separately.  This way
the paths stay unchanged.  A signal handler can still race with normal
cleanup, but deleting the same files and directories twice is harmless.

Reported-by: Jeff King <peff@xxxxxxxx>
Signed-off-by: René Scharfe <l.s.r@xxxxxx>
---
 tempfile.c | 14 ++++++--------
 tempfile.h |  2 +-
 2 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/tempfile.c b/tempfile.c
index 2024c82691..7414c81e31 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -59,14 +59,11 @@ static VOLATILE_LIST_HEAD(tempfile_list);
 static void remove_template_directory(struct tempfile *tempfile,
 				      int in_signal_handler)
 {
-	if (tempfile->directorylen > 0 &&
-	    tempfile->directorylen < tempfile->filename.len &&
-	    tempfile->filename.buf[tempfile->directorylen] == '/') {
-		strbuf_setlen(&tempfile->filename, tempfile->directorylen);
+	if (tempfile->directory) {
 		if (in_signal_handler)
-			rmdir(tempfile->filename.buf);
+			rmdir(tempfile->directory);
 		else
-			rmdir_or_warn(tempfile->filename.buf);
+			rmdir_or_warn(tempfile->directory);
 	}
 }

@@ -115,7 +112,7 @@ static struct tempfile *new_tempfile(void)
 	tempfile->owner = 0;
 	INIT_LIST_HEAD(&tempfile->list);
 	strbuf_init(&tempfile->filename, 0);
-	tempfile->directorylen = 0;
+	tempfile->directory = NULL;
 	return tempfile;
 }

@@ -141,6 +138,7 @@ static void deactivate_tempfile(struct tempfile *tempfile)
 {
 	tempfile->active = 0;
 	strbuf_release(&tempfile->filename);
+	free(tempfile->directory);
 	volatile_list_del(&tempfile->list);
 	free(tempfile);
 }
@@ -254,7 +252,7 @@ struct tempfile *mks_tempfile_dt(const char *directory_template,

 	tempfile = new_tempfile();
 	strbuf_swap(&tempfile->filename, &sb);
-	tempfile->directorylen = directorylen;
+	tempfile->directory = xmemdupz(tempfile->filename.buf, directorylen);
 	tempfile->fd = fd;
 	activate_tempfile(tempfile);
 	return tempfile;
diff --git a/tempfile.h b/tempfile.h
index d7804a214a..5b9e8743dd 100644
--- a/tempfile.h
+++ b/tempfile.h
@@ -82,7 +82,7 @@ struct tempfile {
 	FILE *volatile fp;
 	volatile pid_t owner;
 	struct strbuf filename;
-	size_t directorylen;
+	char *directory;
 };

 /*
--
2.37.2





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux