#!/usr/bin/python # -*- coding: utf-8 -*- # better-mousetrapfs: Filesystem that logs and kills any accessors # version 1.0, released 2010-03-31 # Copyright © 2010 Anders Kaseorg # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the “Software”), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import errno import fuse import grp import os import pwd import signal import stat import syslog fuse.fuse_python_api = (0, 2) class BetterMousetrapFS(fuse.Fuse): def __init__(self, *args, **kwargs): syslog.openlog('better-mousetrapfs') fuse.Fuse.__init__(self, *args, **kwargs) def getattr(self, path): if path == '/': return fuse.Stat(st_mode = stat.S_IFDIR | 0755, st_nlink = 2) else: return -errno.EACCES def opendir(self, path): self.spring(fuse.FuseGetContext()) return -errno.EACCES def spring(self, context): pid = context['pid'] uid = context['uid'] gid = context['gid'] try: user = '%d %r' % (uid, pwd.getpwuid(uid).pw_name) except KeyError: user = '%d' % uid try: group = '%d %r' % (gid, grp.getgrgid(gid).gr_name) except KeyError: group = '%d' % gid cmdline = open('/proc/%d/cmdline' % pid).read().split('\0')[:-1] exe = os.readlink('/proc/%d/exe' % pid) status = dict(tuple(v.strip() for v in l.split(':', 1)) for l in open('/proc/%d/status' % pid).readlines()) cwd = os.readlink('/proc/%d/cwd' % pid) syslog.syslog( syslog.LOG_WARNING | 80, # 80 = LOG_AUTHPRIV 'mousetrap caught process %d, uid=%s, gid=%s, exe=%r, cmdline=%r, cwd=%r' % (pid, user, group, exe, cmdline, cwd)) try: nonlocal_gid = grp.getgrnam('nss-nonlocal-users').gr_gid except KeyError: nonlocal_gid = None if str(nonlocal_gid) in status['Groups'].split(): os.kill(pid, signal.SIGKILL) pass if __name__ == '__main__': fs = BetterMousetrapFS() fs.parse(errex=1) fs.fuse_args.add('allow_other') fs.fuse_args.add('ro') fs.main()