diff options
author | VG <vg@devys.org> | 2017-11-06 09:38:44 +0100 |
---|---|---|
committer | VG <vg@devys.org> | 2017-11-06 09:38:44 +0100 |
commit | 34ad0bf48aa860e42c60660533bf2f003918c178 (patch) | |
tree | bb2760ff3dfcff470a073de8e44196a5c503da03 | |
parent | 0cf7d57bdebd919b3ab185ae4c4de389b11481eb (diff) | |
download | clip-34ad0bf48aa860e42c60660533bf2f003918c178.tar.gz clip-34ad0bf48aa860e42c60660533bf2f003918c178.tar.bz2 clip-34ad0bf48aa860e42c60660533bf2f003918c178.zip |
By using a directory and directory file descriptors, we avoid hardlink
and symlinks attacks.
-rwxr-xr-x | clip | 37 |
1 files changed, 18 insertions, 19 deletions
@@ -19,6 +19,7 @@ Use content: import contextlib +import functools import getpass import os import sys @@ -28,32 +29,30 @@ class Error(Exception): pass class SecurityError(Error): pass -def fileno(filelike): - if getattr(filelike, 'fileno'): - return filelike.fileno() - elif getattr(filelike, 'buffer'): - return filelike.buffer.fileno() - raise Error("fileno not found inside file-like object") +@contextlib.contextmanager +def secure_opendir(dirname): + os.makedirs(dirname, mode=0o700, exist_ok=True) + dfd = os.open(dirname, os.O_RDONLY | os.O_DIRECTORY) + try: + dir_stat = os.stat(dfd) + if (dir_stat.st_uid != os.getuid() or dir_stat.st_mode & 0o777 != 0o700): + raise SecurityError('Wrong directory permissions/owner') + yield dfd + finally: + os.close(dfd) @contextlib.contextmanager -def secure_open(path, mode='r', *l, **kw): - if os.path.islink(path): - raise SecurityError("The clipboard file can not be a symlink") - real_mode = mode.replace('w', 'a') - with open(path, real_mode, *l, **kw) as fo: - if os.fstat(fileno(fo)) != os.stat(path): - raise SecurityError("Intrusion might have been done on %s" % path) - if 'w' in mode: - os.lseek(fileno(fo), 0, os.SEEK_SET) - os.ftruncate(fileno(fo), 0) - os.fchmod(fileno(fo), 0o600) - yield fo +def secure_open(*l, **kw): + with secure_opendir(os.path.dirname(l[0])) as dfd: + _opener = functools.partial(os.open, dir_fd=dfd) + with open(*l, **kw, opener=_opener) as ffd: + yield ffd if __name__ == '__main__': os.umask(0o077) - clipboard_filepath = '/dev/shm/%s-clipboard' % getpass.getuser() + clipboard_filepath = '/dev/shm/%s-clipboard/content' % getpass.getuser() if(sys.stdin.isatty()): # Should write clipboard contents out to stdout try: |