Description: Fixed a classical tempfile symlink attack vulnerability in libuu. See Version: 0.5.20-3.1. Author: Nico Golde Bug-Debian: http://bugs.debian.org/480972 --- a/uulib/uunconc.c +++ b/uulib/uunconc.c @@ -1311,6 +1311,11 @@ UUDecode (uulist *data) char *mode, *ntmp; uufile *iter; size_t bytes; +#ifdef HAVE_MKSTEMP + int tmpfd; + const char *tmpprefix = "uuXXXXXX"; + char *tmpdir = NULL; +#endif /* HAVE_MKSTEMP */ if (data == NULL || data->thisfile == NULL) return UURET_ILLVAL; @@ -1329,13 +1334,35 @@ UUDecode (uulist *data) else mode = "wbx"; /* otherwise in binary */ +#ifdef HAVE_MKSTEMP + if ((getuid()==geteuid()) && (getgid()==getegid())) { + tmpdir=getenv("TMPDIR"); + } + + if (!tmpdir) { + tmpdir = "/tmp"; + } + data->binfile = malloc(strlen(tmpdir)+strlen(tmpprefix)+2); + + if (!data->binfile) { +#else if ((data->binfile = tempnam (NULL, "uu")) == NULL) { +#endif /* HAVE_MKSTEMP */ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, uustring (S_NO_TEMP_NAME)); return UURET_NOMEM; } +#ifdef HAVE_MKSTEMP + strcpy(data->binfile, tmpdir); + strcat(data->binfile, "/"); + strcat(data->binfile, tmpprefix); + + if ((tmpfd = mkstemp(data->binfile)) == -1 || + (dataout = fdopen(tmpfd, mode)) == NULL) { +#else if ((dataout = fopen (data->binfile, mode)) == NULL) { +#endif /* HAVE_MKSTEMP */ /* * we couldn't create a temporary file. Usually this means that TMP * and TEMP aren't set @@ -1343,6 +1370,12 @@ UUDecode (uulist *data) UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, uustring (S_WR_ERR_TARGET), data->binfile, strerror (uu_errno = errno)); +#ifdef HAVE_MKSTEMP + if (tmpfd != -1) { + unlink(data->binfile); + close(tmpfd); + } +#endif /* HAVE_MKSTEMP */ _FP_free (data->binfile); data->binfile = NULL; uu_errno = errno; @@ -1499,7 +1532,13 @@ UUDecode (uulist *data) */ if (data->uudet == BH_ENCODED && data->binfile) { +#ifdef HAVE_MKSTEMP + ntmp = malloc(strlen(tmpdir)+strlen(tmpprefix)+2); + + if (ntmp == NULL) { +#else if ((ntmp = tempnam (NULL, "uu")) == NULL) { +#endif /* HAVE_MKSTEMP */ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, uustring (S_NO_TEMP_NAME)); progress.action = 0; @@ -1513,15 +1552,31 @@ UUDecode (uulist *data) free (ntmp); return UURET_IOERR; } + +#ifdef HAVE_MKSTEMP + strcpy(ntmp, tmpdir); + strcat(ntmp, "/"); + strcat(ntmp, tmpprefix); + if ((tmpfd = mkstemp(ntmp)) == -1 || + (dataout = fdopen(tmpfd, "wb")) == NULL) { +#else if ((dataout = fopen (ntmp, "wb")) == NULL) { +#endif /* HAVE_MKSTEMP */ UUMessage (uunconc_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_TARGET), ntmp, strerror (uu_errno = errno)); progress.action = 0; fclose (datain); +#ifdef HAVE_MKSTEMP + if (tmpfd != -1) { + unlink(ntmp); + close(tmpfd); + } +#endif /* HAVE_MKSTEMP */ free (ntmp); return UURET_IOERR; } + /* * read fork lengths. remember they're in Motorola format */ --- a/uulib/configure.in +++ b/uulib/configure.in @@ -41,6 +41,7 @@ AC_CHECK_HEADERS(io.h sys/time.h) AC_CHECK_FUNCS(gettimeofday) AC_CHECK_FUNC(tempnam,,AC_DEFINE(tempnam,_FP_tempnam)) +AC_CHECK_FUNCS([mkstemp]) # # strerror might be internally defined. this would cause a --- a/unix/uudeview.c +++ b/unix/uudeview.c @@ -443,18 +443,45 @@ proc_stdin (void) FILE *target; size_t bytes; int res; +#ifdef HAVE_MKSTEMP + int tmpfd; + const char *tmpprefix = "uuXXXXXX"; + char *tmpdir = NULL; +#endif /* HAVE_MKSTEMP */ if (stdinput) { fprintf (stderr, "proc_stdin: cannot process stdin twice\n"); return 0; } +#ifdef HAVE_MKSTEMP + if ((getuid()==geteuid()) && (getgid()==getegid())) { + tmpdir=getenv("TMPDIR"); + } + + if (!tmpdir) { + tmpdir = "/tmp"; + } + stdfile = malloc(strlen(tmpdir)+strlen(tmpprefix)+2); + + if (!stdfile) { +#else if ((stdfile = tempnam (NULL, "uu")) == NULL) { +#endif fprintf (stderr, "proc_stdin: cannot get temporary file\n"); return 0; } +#ifdef HAVE_MKSTEMP + strcpy(stdfile, tmpdir); + strcat(stdfile, "/"); + strcat(stdfile, tmpprefix); + + if ((tmpfd = mkstemp(stdfile)) == -1 || + (target = fdopen(tmpfd, "wbx")) == NULL) { +#else if ((target = fopen (stdfile, "wbx")) == NULL) { +#endif fprintf (stderr, "proc_stdin: cannot open temp file %s for writing: %s\n", stdfile, strerror (errno)); _FP_free (stdfile); --- a/configure.in +++ b/configure.in @@ -510,6 +510,7 @@ AC_CHECK_HEADERS(io.h sys/time.h) AC_CHECK_FUNCS(getcwd popen gettimeofday isatty) AC_CHECK_FUNC(tempnam,,AC_DEFINE(tempnam,_FP_tempnam)) +AC_CHECK_FUNCS([mkstemp]) # # strerror might be internally defined. this would cause a