Writing Secure Code

One of the first steps toward redemption is to understand how to correctly write reentrant code. Even if you dont think the application will be running in a threaded environment, if people ever try to port the application, or overcome application hangs by using multiple threads, theyll appreciate it when you dont program with side effects. One portability consideration is that Windows doesnt properly implement fork(), creating new processes under Windows is very expensive, and creating new threads is very cheap.

While the choice of using processes or threads varies depending on the operating system you choose, and the application, code that doesnt depend on side effects will be more portable and much less prone to race conditions.

If youre trying to deal with concurrent execution contexts, whether through forked processes or threads, you need to carefully guard against both the lack of locking shared resources, and incorrectly locking resources. This subject has been covered in much more detail elsewhere, so well only deal with it briefly here. Things to consider:

If youre executing a signal handler or exception handler, the only really safe thing to do may be to call exit(). The best advice weve seen on the subject is from Michal Zalewskis paper, Delivering Signals for Fun and Profit: Understanding, Exploiting and Preventing Signal-Handling Related Vulnerabilities:

In order to deal with TOCTOU issues, one of the best defenses is to create files in places where ordinary users do not have write access. In the case of directories, you may not always have this option. When programming for Windows platforms, remember that a security descriptor can be attached to a file (or any other object) at the time of creation. Supplying the access controls at the time of creation eliminates race conditions between creation and applying the access controls. In order to avoid race conditions between checking to see if an object exists and creating a new one, you have a couple of options, depending on the type of object. The best option, which can be used with files, is to specify the CREATE_NEW flag to the CreateFile API. If the file exists, the call will fail. Creating directories is simpler: all calls to CreateDirectory will fail if the directory already exists. Even so, there is an opportunity for problems. Lets say that you put your app in C:\Program Files\MyApp, but an attacker has already created the directory. The attacker will now have full control access to the directory, which includes the right to delete files within the directory, even if the file itself doesnt grant delete access to that user . The API calls to create several other types of objects do not allow passing in a parameter to determine create new versus open always semantics, and these APIs will succeed but return ERROR_ ALREADY_EXISTS to GetLastError. The correct way to deal with this if you want to ensure that you do not open an existing object is to write code like this:

HANDLE hMutex = CreateMutex(...args...); if(hMutex == NULL) return false; if(GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(hMutex); return false; }

Категории