Skip to content

Commit

Permalink
Modified the umask's value set in forked processes, tightened all files
Browse files Browse the repository at this point in the history
creations rights and removed the daemonize option used for killing
processes (security issue reported by Adrian thiefmaster@gamesurge.net).
  • Loading branch information
seb-m committed Sep 14, 2010
1 parent 80e1afc commit 155e2f5
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 85 deletions.
9 changes: 3 additions & 6 deletions python2/examples/daemon.py
Expand Up @@ -37,10 +37,7 @@ def on_loop(notifier, 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')
61 changes: 19 additions & 42 deletions python2/pyinotify.py
Expand Up @@ -970,16 +970,16 @@ def __repr__(self):

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()
Expand Down Expand Up @@ -1199,42 +1199,20 @@ def process_events(self):
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:
dirname = '/var/run/'
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
Expand All @@ -1247,7 +1225,7 @@ def fork_daemon():
if (pid == 0):
# child
os.chdir('/')
os.umask(0)
os.umask(022)
else:
# parent 2
os._exit(0)
Expand All @@ -1257,20 +1235,19 @@ def fork_daemon():

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))

Expand Down
62 changes: 25 additions & 37 deletions python3/pyinotify.py
Expand Up @@ -83,6 +83,7 @@ def __init__(self):
import ctypes.util
import asyncore
import glob
import locale

try:
from functools import reduce
Expand Down Expand Up @@ -928,13 +929,16 @@ def __repr__(self):

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()
Expand Down Expand Up @@ -1156,39 +1160,20 @@ def process_events(self):
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:
dirname = '/var/run/'
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
Expand All @@ -1201,27 +1186,30 @@ def fork_daemon():
if (pid == 0):
# child
os.chdir('/')
os.umask(0)
os.umask(0o022)
else:
# parent 2
os._exit(0)
else:
# 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))

Expand Down

0 comments on commit 155e2f5

Please sign in to comment.