Secure Coding in C and C++ Race conditionsConcurrency and Race conditionRace conditionRace windowTime of Check, Time of UseExampleTOCTOUTOCTUFile lockingSlide 10File System ExploitsSymbolic linking exploitsSlide 13Slide 14Slide 15Slide 16Slide 17Temporary file open exploitsSlide 19Slide 20ulink Race exploitsTrusted filenamesNonunique Temp File NamesMitigation strategiesSlide 25Slide 26Thread safe functionUse of atomic operationsChecking file properties securelySlide 30Eliminating the race objectSlide 32Controlling access to the race objectRace detection toolsSlide 35Secure Coding in C and C++Race conditionsLecture 8Acknowledgement: These slides are based on author Seacord’s original presentationConcurrency and Race conditionConcurrencyExecution of Multiple flows (threads, processes, tasks, etc)If not controlled can lead to nondeterministic behaviorRace conditionsSoftware defect/vulnerability resulting from unanticipated execution ordering of concurrent flowsE.g., two people simultaneously try to modify the same account (withrawing money)Race conditionNecessary properties for a race conditionConcurrency propertyAt least two control flows executing concurrentlyShared object propertyThe concurrent flows must access a common shared race objectChange state propertyAtleast one control flow must alter the state of the race objectRace windowA code segment that accesses the race object in a way that opens a window of opportunity for race conditionSometimes referred to as critical sectionTraditional approachEnsure race windows do not overlapMake them mutually exclusiveLanguage facilities – synchronization primitives (SP)Deadlock is a risk related to SPDenial of serviceTime of Check, Time of UseSource of race conditionsTrusted (tightly coupled threads of execution) or untrusted control flows (separate application or process)ToCToU race conditionsCan occur during file I/OForms a RW by first checking some race object and then using itExampleAssume the program is running with an effective UID of rootint main(int argc, char *argv[]) {FILE *fd; if (access(“/some_file”, W_OK) == 0) { printf("access granted.\n"); fd = fopen(“/some_file”, "wb+"); /* write to the file */ fclose(fd); } else { err(1, "ERROR"); } return 0;} Figure 7-1int main(int argc, char *argv[]) {FILE *fd; if (access(“/some_file”, W_OK) == 0) { printf("access granted.\n"); fd = fopen(“/some_file”, "wb+"); /* write to the file */ fclose(fd); } else { err(1, "ERROR"); } return 0;} Figure 7-1TOCTOUFollowing shell commands during RWrm /some_fileln /myfile /some_fileMitigationReplace access() call by code that does the followingDrops the privilege to the real UIDOpen with fopen() & Check to ensure that the file was opened successfullyTOCTUNot all untrusted RCs are purely TOCTOUE.g., GNU file utilitiesExploit is the following shell commandmv /tmp/a/b/c /tmp/cNote there is no checking here - implicitchdir(“/tmp/a”);chdir(“b”);chdir(“c”); //race windowchdir(“..”);chdir(“c”);ulink(“*”); chdir(“/tmp/a”);chdir(“b”);chdir(“c”); //race windowchdir(“..”);chdir(“c”);ulink(“*”);File lockingSynchronization Primitives cannot be used to resolve RC from independent processesDon’t have shared access to global dataFile locks can be used to synchronize themint lock(char *fn) { int fd; int sleep_time = 100; while (((fd=open(fn, O_WRONLY | O_EXCL | O_CREAT, 0)) == -1) && errno == EEXIST) { usleep(sleep_time); sleep_time *= 2; if (sleep_time > MAX_SLEEP) sleep_time = MAX_SLEEP; } return fd;}void unlock(char *fn) { if (unlink(fn) == -1) { err(1, "file unlock"); }} Figure 7-3int lock(char *fn) { int fd; int sleep_time = 100; while (((fd=open(fn, O_WRONLY | O_EXCL | O_CREAT, 0)) == -1) && errno == EEXIST) { usleep(sleep_time); sleep_time *= 2; if (sleep_time > MAX_SLEEP) sleep_time = MAX_SLEEP; } return fd;}void unlock(char *fn) { if (unlink(fn) == -1) { err(1, "file unlock"); }} Figure 7-3File lockingTwo disadvantagesOpen() does not blockUse sleep_time that doubles at each attempt (also known as spinlock or busy form of waiting)File lock can remain locked indefinitely (e.g., if the locking process crashes)A common fix is to store the PID in the lock file, which is checked against the active PID. Flaws with this fixPID may have been reusedFix itself may contain race conditionsShared resource may also have been corrupted because of the crashFile System ExploitsFiles and directories are common race objectsOpen files are shared by peer threadsFile systems have exposure to other processesAs file permissionsFile naming conventionsFile systems mechanisms Most executing programs leave a file in a corrupted state when it crashes (backup is remedy)ExploitsSymbolic linking exploitsTemporary file open exploitsulink() race exploitTrusted filenamesNonunique temp file namesSymbolic linking exploitsUnix symbolic linking is most commonSymlink is a directory entry that references a target file or directoryVulnerability involves programmatic reference to a filename that unexpectedly turns out to include a symbolic linkIn the RW the attacker alters the meaning of the filename by creating a symlinkSymbolic linking exploitsAttacker does:rm /some_dir/some_fileln –s attacker_file /some_dir/some_file if (stat(“/some_dir/some_file”, &statbuf) == -1) { err(1, "stat"); } if (statbuf.st_size >= MAX_FILE_SIZE) { err(2, "file size"); } if ((fd=open(“/some_dir/some_file”, O_RDONLY)) == -1) { err(3, "open - %s",argv[1]); } Figure 7-4 if (stat(“/some_dir/some_file”, &statbuf) == -1) { err(1, "stat"); } if (statbuf.st_size >= MAX_FILE_SIZE) { err(2, "file size"); } if ((fd=open(“/some_dir/some_file”, O_RDONLY)) == -1) { err(3, "open - %s",argv[1]); } Figure 7-4Symbolic linking exploitsReason for its wide spread use in exploitsCreation of symlink is not checked to ensure that the owner of the link has any permissions for the target file, norIs it even necessary that the target file existsThe attacker only needs write permissions to the directory in which symlink is createdFurther complication introduced by the followingSymlink can reference a
View Full Document