summaryrefslogtreecommitdiff
blob: d94c0a42bddb6f83792b1d5130e16f1e53fa9e2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Improve security of get_runtime_dir(strict=False) 
https://github.com/takluyver/pyxdg/commit/bd999c1c3fe7ee5f30ede2cf704cf03e400347b4
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 @@
 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