-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 16/04/10 10:08, Fabian Knittel wrote: > Hi David, > > David Sommerseth schrieb: >> As promised in the meeting today, a patch for hardening >> create_temp_filename(). > > Great! :) > >> I've added more checks to what create_temp_filename() returns where it >> is called in addition, to make it even safer. > >> + do { >> uint8_t rndbytes[16]; >> const char *rndstr; >> >> + attempts++; >> + mutex_lock_static (L_CREATE_TEMP); >> + ++counter; >> + mutex_unlock_static (L_CREATE_TEMP); >> + >> prng_bytes (rndbytes, sizeof (rndbytes)); >> rndstr = format_hex_ex (rndbytes, sizeof (rndbytes), 40, 0, NULL, gc); >> buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr); >> + >> + retfname = gen_path (directory, BSTR (&fname), gc); >> + if( !retfname ) { >> + msg (M_FATAL, "Failed to create temporary filename and path"); >> + return NULL; >> + } >> + } while ( test_file (retfname) && (attempts < 6) ); >> + >> + if( attempts > 5 ) { >> + msg (M_FATAL, "Failed to create temporary file after %i attempts", >> attempts); >> + return NULL; >> + } >> + >> + /* Create the tempfile to avoid a race condition */ >> + fd = creat (retfname, S_IRUSR | S_IWUSR); >> + if( fd == -1 ) { > > You'll probably want to add O_EXCL to creat()'s mode flags: > > | O_EXCL Ensure that this call creates the file: if this flag is > speciā > | fied in conjunction with O_CREAT, and pathname already > exists, > | then open() will fail. The behavior of O_EXCL is > undefined if > | O_CREAT is not specified. > > Otherwise, there would be a race-condition between test_file() and > creat() and someone could create a symlink under you feet.
I honestly doubt that O_EXCL would help much, as the file will be closed immediately. > And as the important "does it exist?" test thereby moves to creat(), I > would like to suggest that you move the creat() call into the loop. The > exit condition would then be "successful creat()" or "max attempts". I agree that there is a tiny theoretical possibility for this to happen. The only possible place where you can manage this, is to create a symlink is after the test_file() in the while() loop and before the the creat(), in between there are only two integer checks (attempts > 6 and attempts < 5). We're basically talking about a handful set of CPU cycles. And in these cycles, a malicious process needs to access the memory region of OpenVPN where the newly decided temp filename is stored and to create a symlink just before creat() is called. Of course this is more doable if you're able to preempt the OpenVPN process just before creat(). But if you have a malicious process being able to preempt OpenVPN or even read the memory regions of OpenVPN, I'd say you have a much bigger problem than this code section in OpenVPN. Especially if you have configured OpenVPN properly, meaning that the temp directory it uses is not world writable. By default, OpenVPN do not use /tmp for that, AFAIK. I think "fixing" this is to be overly paranoid, as you will only narrow the whole "attack scope" by a few CPU cycles and you will still not remove the "attack scope". It is still possible to manage that even if you're inside the while() loop, it's just two integer comparisons being skipped. But please render me wrong, if you think I'm overseeing something here! On the other hand, if such a change renders the code more readable, that's another question - but then that should be the argument. > PS: Is there some kind of code style guide for OpenVPN? I notice that > you're using a different style than I expected to see... Uhh ... I am trying to follow the existing style as best as I can ... but I see I've "failed" on parentheses around the 'if' statements. Or was it something else you noticed? Could maybe be tab vs space? kind regards, David Sommerseth -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iEYEARECAAYFAkvIJNEACgkQDC186MBRfroycwCfQqmYQnSjuAa4Io4toU9e8zOp GGYAoIj3VOCz/t0BKG285JMQtmdNZoN/ =7Hq1 -----END PGP SIGNATURE-----