c - stat(), fstat(), lstat(), and fopen(); how to write TOCTOU protected system independent code -
i've been dealing problem few weeks updating 20 year code needs system independent (work on both linux , windows). involves time-of-check, time-of-use (toctou) issues. made thread here, didn't go far, , after ruminating on while , searching deeper problem, think understand question bit better. maybe can ask bit better too...
from i've read, code needs check if file exists, if accessible, open file, operations , close file. seems best way call lstat()
, call fopen()
, call fstat()
(to rule out toctou), , operations , closing file.
however, i've been lead believe lstat()
, fstat()
posix defined, not c standard defined, ruling out use system agnostic program, in same way open()
shouldn't used cross-compatibility. how implement this?
if at first post, can see developer 20 years ago used c preprocessor cut code cross-compatible parts, if did that, wouldn't know replace lstat()
or fstat()
(their windows counterparts).
edit: added abreviated code post; if unclear please go original post
#ifdef win32 struct _stat buf; #else struct stat buf; #endif //win32 file *fp; char data[2560]; // make sure file exists , readable #ifdef win32 if (_access(file.c_str(), r_ok) == -1) { #else if (access(file.c_str(), r_ok) == -1) { #endif //win32 char message[2560]; sprintf(message, "file '%s' not found or not readable", file.c_str()); throw message; } // file status information #ifdef win32 if (_stat(file.c_str(), &buf) != 0) { #else if (stat(file.c_str(), &buf) != 0) { #endif //win32 char message[2560]; sprintf(message, "file '%s' no status available", file.c_str()); throw message; } // open file reading fp = fopen(file.c_str(), "r"); if (fp == null) { char message[2560]; sprintf(message, "file '%s' cound not opened", file.c_str()); throw message; } // read file mvstring s, ss; while (fgets(data, sizeof(data), fp) != (char *)0) { s = data; s.trimboth(); if (s.compare( 0, 5, "group" ) == 0) { //size_t t = s.find_last_of( ":" ); size_t t = s.find( ":" ); if (t != string::npos) { ss = s.substr( t+1 ).c_str(); ss.trimboth(); ss = ss.substr( 1, ss.length() - 3 ).c_str(); group_list.push_back( ss ); } } } // close file fclose(fp); }
the reliable way check whether file exists , can opened try opening it. if opened, ok. if not opened, can think spending time analyze went wrong.
the access()
function formally asks different question think; asks 'can real user id or real group id access file', program use effective user id or effective group id access file. if program not running suid or sgid, , not launched program running suid or sgid — , that's normal case — there's no difference. question different.
the use of stat()
or lstat()
doesn't seem helpful. in particular, lstat()
tells whether start @ symlink, code doesn't care that.
both access()
, stat()
calls provide toctou windows of vulnerability; file removed after reported present, or created after reported absent.
you should call fopen()
, see whether works; code simpler , more resistant toctou problems. might need consider whether use open()
controls (o_excl
, etc), , convert file descriptor file pointer (fdopen()
).
all of applies unix side.
the details different, on windows side, still best off trying open file , reacting appropriately failure.
in both systems, make sure options provided open function appropriate.
Comments
Post a Comment