summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Kluyver <takowl@gmail.com>2014-01-23 15:09:51 -0800
committerThomas Kluyver <takowl@gmail.com>2014-01-23 15:09:51 -0800
commitbd999c1c3fe7ee5f30ede2cf704cf03e400347b4 (patch)
tree3716ae20aa80f1942cd34e48a7e8ef220fedd0f6
parentfc61714c67981945a9cd5632288558d229dabbef (diff)
Improve security of get_runtime_dir(strict=False)
Fixes fd.o bug #73878.
-rw-r--r--xdg/BaseDirectory.py31
1 files changed, 23 insertions, 8 deletions
diff --git a/xdg/BaseDirectory.py b/xdg/BaseDirectory.py
index cececa3..a7c31b1 100644
--- a/xdg/BaseDirectory.py
+++ b/xdg/BaseDirectory.py
@@ -25,7 +25,7 @@ Typical usage:
Note: see the rox.Options module for a higher-level API for managing options.
"""
-import os
+import os, stat
_home = os.path.expanduser('~')
xdg_data_home = os.environ.get('XDG_DATA_HOME') or \
@@ -131,15 +131,30 @@ def get_runtime_dir(strict=True):
import getpass
fallback = '/tmp/pyxdg-runtime-dir-fallback-' + getpass.getuser()
+ create = False
+
try:
- os.mkdir(fallback, 0o700)
+ # This must be a real directory, not a symlink, so attackers can't
+ # point it elsewhere. So we use lstat to check it.
+ st = os.lstat(fallback)
except OSError as e:
import errno
- if e.errno == errno.EEXIST:
- # Already exists - set 700 permissions again.
- import stat
- os.chmod(fallback, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR)
- else: # pragma: no cover
+ if e.errno == errno.ENOENT:
+ create = True
+ else:
raise
-
+ else:
+ # The fallback must be a directory
+ if not stat.S_ISDIR(st.st_mode):
+ os.unlink(fallback)
+ create = True
+ # Must be owned by the user and not accessible by anyone else
+ elif (st.st_uid != os.getuid()) \
+ or (st.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
+ os.rmdir(fallback)
+ create = True
+
+ if create:
+ os.mkdir(fallback, 0o700)
+
return fallback