-
-
Notifications
You must be signed in to change notification settings - Fork 29.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
os.makedirs(exist_ok=True) is not thread-safe: umask is set temporary to 0, serious security problem #65281
Comments
http://bugs.python.org/file19849/mkdirs.tr.diff introduced a patch with this code in it: +def _get_masked_mode(mode): This changes the umask of the entire process. If another thread manages to create a file between those two calls then it will be world read/writable, regardless of the original umask of the process. This is not theoretical: I discovered this bug by observing it happen. |
The issue associated with the patch in question is bpo-9299. Adding possibly affected releases and release managers for evaluation. |
yes, this seems bad enough for inclusion in security releases. |
This patch comes from issue bpo-9299: changeset 89cda0833ba6 made in Python 3.2 beta 1. The change was not backported to Python 2.7. |
The shell command "umask" calls umask(022) to get the current umask, and then call umask() with result of the first call. 022 is the default umask, it's probably safer to call umask(0o22) in _get_masked_mode() instead of umask(0). Attached patch makes this change. If you change something, it should be backported to 3.2, 3.3 and 3.4, because I agree that it affects the security. |
I think the behaviour that an error is raised if the permissions are not the same is a nuisance that does not correspond to actual use cases (*). People who care about permissions so much that they expect an error can do the check themselves, or call chmod(). (*) and I got similar errors several times when running setup.py, only I didn't know it was because of that "feature" |
(note that Victor's patch is of course not an actual fix, only a mitigation; if someone is relying on a stricter umask they will still be vulnerable to this) |
I was also surprised that makedirs() checks for the exact permission. We can probably document that makedirs(exists_ok=True) leaves the If the check on permissions is removed, an enhancement would be to Something like: if makedirs("a/b", mod=0o755, exists_ok=True):
os.chmod("a", 0o755)
os.chmod("a/b", 0o755)
# else a and b were created with the permission 0o755 |
See also bpo-19930. Behaviors of os.makedirs() and pathlib.Path.mkdir() are different. pathlib.Path.mkdir() (as the mkdir command) creates parent directories with default mode, and os.makedirs() - with specified mode. |
New changeset 9186f4a18584 by Benjamin Peterson in branch '3.2': New changeset 6370d44013f7 by Benjamin Peterson in branch '3.3': New changeset c24dd53ab4b9 by Benjamin Peterson in branch '3.4': New changeset adfcdc831e98 by Benjamin Peterson in branch 'default': |
I've now removed the offending behavior. exist_ok is still racy because it uses path.isdir() in the exceptional case, but fixing that can be an enhancement elsewhere. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: