diff options
author | Sebastien Martini <seb@dbzteam.org> | 2010-09-15 00:19:49 +0200 |
---|---|---|
committer | Sebastien Martini <seb@dbzteam.org> | 2010-09-15 00:19:49 +0200 |
commit | 155e2f5d0dfeff210198856b2b03d53d8e810c52 (patch) | |
tree | 48512ea648bbe717f4416bdc8245e420cac64a0e | |
parent | 80e1afc95893350e6e59230993e26376e279327c (diff) | |
download | pyinotify-155e2f5d0dfeff210198856b2b03d53d8e810c52.tar.gz |
Modified the umask's value set in forked processes, tightened all files
creations rights and removed the daemonize option used for killing
processes (security issue reported by Adrian thiefmaster@gamesurge.net).
-rw-r--r-- | python2/examples/daemon.py | 9 | ||||
-rwxr-xr-x | python2/pyinotify.py | 61 | ||||
-rwxr-xr-x | python3/pyinotify.py | 62 |
3 files changed, 47 insertions, 85 deletions
diff --git a/python2/examples/daemon.py b/python2/examples/daemon.py index 26eaffe..aeb5249 100644 --- a/python2/examples/daemon.py +++ b/python2/examples/daemon.py @@ -37,10 +37,7 @@ on_loop_func = functools.partial(on_loop, counter=Counter()) # child process' PID is written to /tmp/pyinotify.pid (it also automatically # deletes it when it exits normally). If no custom pid_file is provided it # would write it more traditionally under /var/run/. /tmp/stdout.txt is used -# as stdout stream thus traces of events will be written in it, force_kill -# means that if there is already an /tmp/pyinotify.pid with a corresponding -# running process it will be killed first. callback is the above function -# and will be called after each event loop. +# as stdout stream thus traces of events will be written in it. callback is +# the above function and will be called after each event loop. notifier.loop(daemonize=True, callback=on_loop_func, - pid_file='/tmp/pyinotify.pid', force_kill=True, - stdout='/tmp/stdout.txt') + pid_file='/tmp/pyinotify.pid', stdout='/tmp/stdout.txt') diff --git a/python2/pyinotify.py b/python2/pyinotify.py index d7fb8af..9c0aafc 100755 --- a/python2/pyinotify.py +++ b/python2/pyinotify.py @@ -970,16 +970,16 @@ class Stats(ProcessEvent): def dump(self, filename): """ - Dumps statistics to file |filename|. + Dumps statistics. - @param filename: pathname. + @param filename: filename where stats will be dumped, filename is + created and must not exist prior to this call. @type filename: string """ - file_obj = file(filename, 'wb') - try: - file_obj.write(str(self)) - finally: - file_obj.close() + flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL + fd = os.open(filename, flags, 0600) + os.write(fd, str(self)) + os.close(fd) def __str__(self, scale=45): stats = self._stats_copy() @@ -1199,11 +1199,10 @@ class Notifier: if self._coalesce: self._eventset.clear() - def __daemonize(self, pid_file=None, force_kill=False, stdin=os.devnull, - stdout=os.devnull, stderr=os.devnull): + def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull, + stderr=os.devnull): """ pid_file: file to which the pid will be written. - force_kill: if True kill the process associated to pid_file. stdin, stdout, stderr: files associated to common streams. """ if pid_file is None: @@ -1211,30 +1210,9 @@ class Notifier: basename = os.path.basename(sys.argv[0]) or 'pyinotify' pid_file = os.path.join(dirname, basename + '.pid') - if os.path.exists(pid_file): - fo = file(pid_file, 'rb') - try: - try: - pid = int(fo.read()) - except ValueError: - pid = None - if pid is not None: - try: - os.kill(pid, 0) - except OSError, err: - if err.errno == errno.ESRCH: - log.debug(err) - else: - log.error(err) - else: - if not force_kill: - s = 'There is already a pid file %s with pid %d' - raise NotifierError(s % (pid_file, pid)) - else: - os.kill(pid, 9) - finally: - fo.close() - + if os.path.lexists(pid_file): + err = 'Cannot daemonize: pid file %s already exists.' % pid_file + raise NotifierError(err) def fork_daemon(): # Adapted from Chad J. Schroeder's recipe @@ -1247,7 +1225,7 @@ class Notifier: if (pid == 0): # child os.chdir('/') - os.umask(0) + os.umask(022) else: # parent 2 os._exit(0) @@ -1257,20 +1235,19 @@ class Notifier: fd_inp = os.open(stdin, os.O_RDONLY) os.dup2(fd_inp, 0) - fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT) + fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0600) os.dup2(fd_out, 1) - fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT) + fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0600) os.dup2(fd_err, 2) # Detach task fork_daemon() # Write pid - file_obj = file(pid_file, 'wb') - try: - file_obj.write(str(os.getpid()) + '\n') - finally: - file_obj.close() + flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL + fd_pid = os.open(pid_file, flags, 0600) + os.write(fd_pid, str(os.getpid()) + '\n') + os.close(fd_pid) atexit.register(lambda : os.unlink(pid_file)) diff --git a/python3/pyinotify.py b/python3/pyinotify.py index 9a7afac..84fa17a 100755 --- a/python3/pyinotify.py +++ b/python3/pyinotify.py @@ -83,6 +83,7 @@ import ctypes import ctypes.util import asyncore import glob +import locale try: from functools import reduce @@ -928,13 +929,16 @@ class Stats(ProcessEvent): def dump(self, filename): """ - Dumps statistics to file |filename|. + Dumps statistics. - @param filename: pathname. + @param filename: filename where stats will be dumped, filename is + created and must not exist prior to this call. @type filename: string """ - with open(filename, 'w') as file_obj: - file_obj.write(str(self)) + flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL + fd = os.open(filename, flags, 0o0600) + os.write(fd, bytes(self.__str__(), locale.getpreferredencoding())) + os.close(fd) def __str__(self, scale=45): stats = self._stats_copy() @@ -1156,11 +1160,10 @@ class Notifier: if self._coalesce: self._eventset.clear() - def __daemonize(self, pid_file=None, force_kill=False, stdin=os.devnull, - stdout=os.devnull, stderr=os.devnull): + def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull, + stderr=os.devnull): """ pid_file: file to which the pid will be written. - force_kill: if True kill the process associated to pid_file. stdin, stdout, stderr: files associated to common streams. """ if pid_file is None: @@ -1168,27 +1171,9 @@ class Notifier: basename = os.path.basename(sys.argv[0]) or 'pyinotify' pid_file = os.path.join(dirname, basename + '.pid') - if os.path.exists(pid_file): - with open(pid_file, 'r') as fo: - try: - pid = int(fo.read()) - except ValueError: - pid = None - if pid is not None: - try: - os.kill(pid, 0) - except OSError as err: - if err.errno == errno.ESRCH: - log.debug(err) - else: - log.error(err) - else: - if not force_kill: - s = 'There is already a pid file %s with pid %d' - raise NotifierError(s % (pid_file, pid)) - else: - os.kill(pid, 9) - + if os.path.lexists(pid_file): + err = 'Cannot daemonize: pid file %s already exists.' % pid_file + raise NotifierError(err) def fork_daemon(): # Adapted from Chad J. Schroeder's recipe @@ -1201,7 +1186,7 @@ class Notifier: if (pid == 0): # child os.chdir('/') - os.umask(0) + os.umask(0o022) else: # parent 2 os._exit(0) @@ -1209,19 +1194,22 @@ class Notifier: # parent 1 os._exit(0) - fd_inp = open(stdin, 'r') - os.dup2(fd_inp.fileno(), 0) - fd_out = open(stdout, 'w') - os.dup2(fd_out.fileno(), 1) - fd_err = open(stderr, 'w') - os.dup2(fd_err.fileno(), 2) + fd_inp = os.open(stdin, os.O_RDONLY) + os.dup2(fd_inp, 0) + fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0o0600) + os.dup2(fd_out, 1) + fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0o0600) + os.dup2(fd_err, 2) # Detach task fork_daemon() # Write pid - with open(pid_file, 'w') as file_obj: - file_obj.write(str(os.getpid()) + '\n') + flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL + fd_pid = os.open(pid_file, flags, 0o0600) + os.write(fd_pid, bytes(str(os.getpid()) + '\n', + locale.getpreferredencoding())) + os.close(fd_pid) atexit.register(lambda : os.unlink(pid_file)) |