#! /bin/sh /usr/share/dpatch/dpatch-run ## 99rdancer_race_creating_temporary_file by Jan Minar ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Fix race condition creating temporary file @DPATCH@ --- screen-4.0.3.orig/fileio.c 2009-01-11 04:35:27.000000000 +0000 +++ screen-4.0.3/fileio.c 2009-01-11 04:35:39.216438580 +0000 @@ -460,9 +460,21 @@ * to share his copy buffer contents, he is free to chmod it after its * creation. * Jan Nordholz , 2007/08/07 - public = !strcmp(fn, DEFAULT_BUFFERFILE); + * + * Race condition fix. It may be necessary to adjust the modifications for + * systems that do not satisfy the HAVE_LSTAT condition. + * Jan Minar 2009-01-11 */ + public = !strcmp(fn, DEFAULT_BUFFERFILE); # ifdef HAVE_LSTAT + /* + * Note: In the time between lstat() and open()/remove() below are + * called, the file can be created/removed/modified. Therefore the + * information lstat() returns is taken into consideration, but not + * relied upon. In particular, the open()/remove() calls can fail, and + * the code must account for that. Symlink attack could be mounted if + * the code is changed carelessly. --rdancer 2009-01-11 + */ exists = !lstat(fn, &stb); if (public && exists && (S_ISLNK(stb.st_mode) || stb.st_nlink > 1)) { @@ -481,28 +493,36 @@ #ifdef COPY_PASTE if (dump == DUMP_EXCHANGE && public) { + /* + * Setting umask to zero is a bad idea -- the user surely doesn't + * expect a publicly readable file in a publicly readable directory + * --rdancer 2009-01-11 + */ + /* old_umask = umask(0); + */ # ifdef HAVE_LSTAT if (exists) - { - if ((fd = open(fn, O_WRONLY, 0666)) >= 0) - { - if (fstat(fd, &stb2) == 0 && stb.st_dev == stb2.st_dev && stb.st_ino == stb2.st_ino) - ftruncate(fd, 0); - else - { - close(fd); - fd = -1; - } - } - } - else - fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0666); - f = fd >= 0 ? fdopen(fd, mode) : 0; + if (remove(fn) == -1) + { + /* Error */ + debug2("WriteFile: File exists and remove(%s) failed: %s\n", + fn, strerror(errno)); + UserReturn(0); + } # else - f = fopen(fn, mode); + (void) remove(fn); # endif + /* + * No r/w permissions for anybody but the user, as the file may be in + * a public directory -- if the user chooses, they can chmod the file + * afterwards. --rdancer 2008-01-11 + */ + fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0600); + f = fd >= 0 ? fdopen(fd, mode) : 0; + /* umask(old_umask); + */ } else #endif /* COPY_PASTE */