From: Dmitry Goncharov Date: Sun, 13 Nov 2022 21:20:33 +0000 (-0500) Subject: [SV 63333] Be more lenient when failing to create temporary files X-Git-Tag: 4.4.0.90~42 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=1b51ba1f5d448281ddeea5a252814bdec56a86fa;p=thirdparty%2Fmake.git [SV 63333] Be more lenient when failing to create temporary files If make cannot create a temporary lock file for output sync, continue without output sync enabled rather than dying. However, if make cannot store a makefile from stdin to a temporary file that is still a fatal error. * misc.c (get_tmppath): Keep running on failure to generate a temporary file name. (get_tmpfd): Keep running on failure to get a temporary file. (get_tmpfile): Keep running on failure to open a temporary file. Ensure memory is freed if we return an error. * posixos.c (os_anontmp): Keep running on failure to open an anonymous temporary file. * output.c (setup_tmpfile): Print an error on failure to create an output sync lock file. * main.c (main): Die on failure to store makefile from stdin to a temporary file. * tests/scripts/features/output-sync: Add tests. * tests/scripts/features/temp_stdin: Ditto. --- diff --git a/src/main.c b/src/main.c index f2caf7a8..78729de1 100644 --- a/src/main.c +++ b/src/main.c @@ -1928,6 +1928,9 @@ main (int argc, char **argv, char **envp) _("Makefile from standard input specified twice")); outfile = get_tmpfile (&newnm); + if (!outfile) + O (fatal, NILF, + _("cannot store makefile from stdin to a temporary file")); while (!feof (stdin) && ! ferror (stdin)) { diff --git a/src/misc.c b/src/misc.c index 8264fe9f..00dce749 100644 --- a/src/misc.c +++ b/src/misc.c @@ -20,8 +20,7 @@ this program. If not, see . */ #include "os.h" #include "debug.h" -/* GNU make no longer supports pre-ANSI89 environments. */ - +#include #include #ifdef WINDOWS32 @@ -650,11 +649,19 @@ get_tmppath () # ifdef HAVE_MKTEMP path = get_tmptemplate (); if (*mktemp (path) == '\0') - pfatal_with_name ("mktemp"); + { + OSS (error, NILF, + _("cannot generate temp path from %s: %s"), path, strerror (errno)); + return NULL; + } # else path = xmalloc (L_tmpnam + 1); if (tmpnam (path) == NULL) - pfatal_with_name ("tmpnam"); + { + OS (error, NILF, + _("cannot generate temp name: %s"), strerror (errno)); + return NULL; + } # endif return path; @@ -662,7 +669,9 @@ get_tmppath () #endif /* Generate a temporary file and return an fd for it. If name is NULL then - the temp file is anonymous and will be deleted when the process exits. */ + the temp file is anonymous and will be deleted when the process exits. If + name is not null then *name will point to an allocated buffer, or set to + NULL on failure. */ int get_tmpfd (char **name) { @@ -670,9 +679,11 @@ get_tmpfd (char **name) char *tmpnm; mode_t mask; - /* If there's an os-specific way to get an anoymous temp file use it. */ - if (!name) + if (name) + *name = NULL; + else { + /* If there's an os-specific way to get an anoymous temp file use it. */ fd = os_anontmp (); if (fd >= 0) return fd; @@ -689,13 +700,19 @@ get_tmpfd (char **name) EINTRLOOP (fd, mkstemp (tmpnm)); #else tmpnm = get_tmppath (); + if (!tmpnm) + return -1; /* Can't use mkstemp(), but try to guard against a race condition. */ EINTRLOOP (fd, open (tmpnm, O_CREAT|O_EXCL|O_RDWR, 0600)); #endif if (fd < 0) - OSS (fatal, NILF, - _("create temporary file %s: %s"), tmpnm, strerror (errno)); + { + OSS (error, NILF, + _("cannot create temporary file %s: %s"), tmpnm, strerror (errno)); + free (tmpnm); + return -1; + } if (name) *name = tmpnm; @@ -704,8 +721,8 @@ get_tmpfd (char **name) int r; EINTRLOOP (r, unlink (tmpnm)); if (r < 0) - OSS (fatal, NILF, - _("unlink temporary file %s: %s"), tmpnm, strerror (errno)); + OSS (error, NILF, + _("cannot unlink temporary file %s: %s"), tmpnm, strerror (errno)); free (tmpnm); } @@ -715,8 +732,8 @@ get_tmpfd (char **name) } /* Return a FILE* for a temporary file, opened in the safest way possible. - Set name to point to an allocated buffer containing the name of the file. - Note, this cannot be NULL! */ + Set name to point to an allocated buffer containing the name of the file, + or NULL on failure. Note, name cannot be NULL! */ FILE * get_tmpfile (char **name) { @@ -725,26 +742,37 @@ get_tmpfile (char **name) FILE *file; #if defined(HAVE_FDOPEN) - int fd = get_tmpfd (name); + int fd; + assert (name); + fd = get_tmpfd (name); + if (fd < 0) + return NULL; + assert (*name); ENULLLOOP (file, fdopen (fd, tmpfile_mode)); if (file == NULL) - OSS (fatal, NILF, + OSS (error, NILF, _("fdopen: temporary file %s: %s"), *name, strerror (errno)); #else /* Preserve the current umask, and set a restrictive one for temp files. */ mode_t mask = umask (0077); - int err; + assert (name); *name = get_tmppath (); + if (!*name) + return NULL; /* Although this fopen is insecure, it is executed only on non-fdopen platforms, which should be a rarity nowadays. */ ENULLLOOP (file, fopen (*name, tmpfile_mode)); if (file == NULL) - OSS (fatal, NILF, - _("fopen: temporary file %s: %s"), *name, strerror (errno)); + { + OSS (error, NILF, + _("fopen: temporary file %s: %s"), *name, strerror (errno)); + free (*name); + *name = NULL; + } umask (mask); #endif diff --git a/src/output.c b/src/output.c index 43eb2f06..22387dff 100644 --- a/src/output.c +++ b/src/output.c @@ -248,6 +248,9 @@ setup_tmpfile (struct output *out) /* If we failed to create a temp file, disable output sync going forward. */ error: + O (error, NILF, + _("cannot open output-sync lock file, suppressing output-sync.")); + output_close (out); output_sync = OUTPUT_SYNC_NONE; osync_clear (); diff --git a/src/posixos.c b/src/posixos.c index 3d7d6614..78358dd8 100644 --- a/src/posixos.c +++ b/src/posixos.c @@ -872,12 +872,15 @@ os_anontmp () FILE *tfile; ENULLLOOP (tfile, tmpfile ()); if (!tfile) - pfatal_with_name ("tmpfile"); + { + OS (error, NILF, "tmpfile: %s", strerror (errno)); + return -1; + } umask (mask); EINTRLOOP (fd, dup (fileno (tfile))); if (fd < 0) - pfatal_with_name ("dup"); + OS (error, NILF, "dup: %s", strerror (errno)); fclose (tfile); } #endif diff --git a/tests/scripts/features/output-sync b/tests/scripts/features/output-sync index 40546994..18c85c0a 100644 --- a/tests/scripts/features/output-sync +++ b/tests/scripts/features/output-sync @@ -363,8 +363,24 @@ pid:=$(shell echo $$PPID) all:; @#HELPER# term $(pid) sleep 10 !, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM); } - unlink($fout); + +# SV 63333. Test that make continues to run without output sync when we +# cannot create a temporary file. +# Create a non-writable temporary directory. +# Run the test twice, because run_make_test cannot match a regex againt a +# multiline input. +my $tdir = 'test_tmp_dir'; +mkdir($tdir, 0500); +$ENV{'TMPDIR'} = $tdir; + +run_make_test(q! +all:; $(info hello, world) +!, '-Orecurse', "/suppressing output-sync/"); + +run_make_test(undef, '-Orecurse', "/#MAKE#: 'all' is up to date./"); + +rmdir($tdir); } # This tells the test driver that the perl test script executed properly. diff --git a/tests/scripts/features/temp_stdin b/tests/scripts/features/temp_stdin index c01d627c..3bd53e02 100644 --- a/tests/scripts/features/temp_stdin +++ b/tests/scripts/features/temp_stdin @@ -109,6 +109,21 @@ force: @make_command = @make_orig; unlink($makecopy); rmdir($tmakedir); + +# SV 63333. Test that make exits with an error message if we cannot store a +# makefile from stdin to a temporary file. +# Create a non-writable temporary directory. + +my $tdir = 'test_tmp_dir'; +mkdir($tdir, 0500); +$ENV{'TMPDIR'} = $tdir; +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; + +run_make_test(q! +all:; $(info hello, world) +!, '-f-', '/cannot store makefile from stdin to a temporary file. Stop./', 512); +rmdir($tdir); } close(STDIN);