Example #1
0
    def start(self):
        for e in ['Xephyr', 'matchbox-window-manager']:
            debug("Searching for '%s'" % e)
            rc, report = cmd(['which', e])
            if rc != 0:
                raise AppArmorException("Could not find '%s'" % e)
        '''Run any setup code'''
        SandboxXserver.start(self)
        '''Start a Xephyr server'''
        listener_x = os.fork()
        if listener_x == 0:
            # TODO: break into config file? Which are needed?
            x_exts = [
                '-extension', 'GLX', '-extension', 'MIT-SHM', '-extension',
                'RENDER', '-extension', 'SECURITY', '-extension', 'DAMAGE'
            ]
            # verify_these
            x_extra_args = [
                '-host-cursor',  # less secure?
                '-fakexa',  # for games? seems not needed
                '-nodri',  # more secure?
            ]

            if not self.geometry:
                self.geometry = "640x480"
            x_args = [
                '-nolisten',
                'tcp',
                '-screen',
                self.geometry,
                '-br',  # black background
                '-reset',  # reset after last client exists
                '-terminate',  # terminate at server reset
                '-title',
                self.generate_title(),
            ] + x_exts + x_extra_args

            args = ['/usr/bin/Xephyr'] + x_args + [self.display]
            debug(" ".join(args))
            os.execv(args[0], args)
            sys.exit(0)
        self.pids.append(listener_x)

        time.sleep(1)  # FIXME: detect if running

        # Next, start the window manager
        sys.stdout.flush()
        os.chdir(os.environ["HOME"])
        listener_wm = os.fork()
        if listener_wm == 0:
            # update environment
            set_environ(self.new_environ)

            args = ['/usr/bin/matchbox-window-manager', '-use_titlebar', 'no']
            debug(" ".join(args))
            cmd(args)
            sys.exit(0)

        self.pids.append(listener_wm)
        time.sleep(1)  # FIXME: detect if running
Example #2
0
    def start(self):
        for e in ['Xephyr', 'matchbox-window-manager']:
            debug("Searching for '%s'" % e)
            rc, report = cmd(['which', e])
            if rc != 0:
                raise AppArmorException("Could not find '%s'" % e)

        '''Run any setup code'''
        SandboxXserver.start(self)

        '''Start a Xephyr server'''
        listener_x = os.fork()
        if listener_x == 0:
            # TODO: break into config file? Which are needed?
            x_exts = ['-extension', 'GLX',
                      '-extension', 'MIT-SHM',
                      '-extension', 'RENDER',
                      '-extension', 'SECURITY',
                      '-extension', 'DAMAGE'
                     ]
            # verify_these
            x_extra_args = ['-host-cursor', # less secure?
                            '-fakexa',      # for games? seems not needed
                            '-nodri',       # more secure?
                           ]

            if not self.geometry:
                self.geometry = "640x480"
            x_args = ['-nolisten', 'tcp',
                      '-screen', self.geometry,
                      '-br',        # black background
                      '-reset',     # reset after last client exists
                      '-terminate', # terminate at server reset
                      '-title', self.generate_title(),
                      ] + x_exts + x_extra_args

            args = ['/usr/bin/Xephyr'] + x_args + [self.display]
            debug(" ".join(args))
            os.execv(args[0], args)
            sys.exit(0)
        self.pids.append(listener_x)

        time.sleep(1) # FIXME: detect if running

        # Next, start the window manager
        sys.stdout.flush()
        os.chdir(os.environ["HOME"])
        listener_wm = os.fork()
        if listener_wm == 0:
            # update environment
            set_environ(self.new_environ)

            args = ['/usr/bin/matchbox-window-manager', '-use_titlebar', 'no']
            debug(" ".join(args))
            cmd(args)
            sys.exit(0)

        self.pids.append(listener_wm)
        time.sleep(1) # FIXME: detect if running
Example #3
0
def aa_exec(command, opt, environ={}, verify_rules=[]):
    '''Execute binary under specified policy'''
    if opt.profile != None:
        policy_name = opt.profile
    else:
        opt.ensure_value("template_var", None)
        opt.ensure_value("name", None)
        opt.ensure_value("comment", None)
        opt.ensure_value("author", None)
        opt.ensure_value("copyright", None)

        binary = command[0]
        policy_name = gen_policy_name(binary)
        easyp = apparmor.easyprof.AppArmorEasyProfile(binary, opt)
        params = apparmor.easyprof.gen_policy_params(policy_name, opt)
        policy = easyp.gen_policy(**params)
        debug("\n%s" % policy)

        tmp = tempfile.NamedTemporaryFile(prefix='%s-' % policy_name)
        if sys.version_info[0] >= 3:
            tmp.write(bytes(policy, 'utf-8'))
        else:
            tmp.write(policy)
        tmp.flush()

        debug("using '%s' template" % opt.template)
        # TODO: get rid of this
        if opt.withx:
            rc, report = cmd(
                ['pkexec', 'apparmor_parser', '-r',
                 '%s' % tmp.name])
        else:
            rc, report = cmd(['sudo', 'apparmor_parser', '-r', tmp.name])
        if rc != 0:
            raise AppArmorException("Could not load policy")

        rc, report = cmd(['sudo', 'apparmor_parser', '-p', tmp.name])
        if rc != 0:
            raise AppArmorException("Could not dump policy")

        # Make sure the dynamic profile has the appropriate line for X
        for r in verify_rules:
            found = False
            for line in report.splitlines():
                line = line.strip()
                if r == line:
                    found = True
                    break
            if not found:
                raise AppArmorException("Could not find required rule: %s" % r)

    set_environ(environ)
    args = ['aa-exec', '-p', policy_name, '--'] + command
    rc, report = cmd(args)
    return rc, report
Example #4
0
def aa_exec(command, opt, environ={}, verify_rules=[]):
    '''Execute binary under specified policy'''
    if opt.profile != None:
        policy_name = opt.profile
    else:
        opt.ensure_value("template_var", None)
        opt.ensure_value("name", None)
        opt.ensure_value("comment", None)
        opt.ensure_value("author", None)
        opt.ensure_value("copyright", None)

        binary = command[0]
        policy_name = gen_policy_name(binary)
        easyp = apparmor.easyprof.AppArmorEasyProfile(binary, opt)
        params = apparmor.easyprof.gen_policy_params(policy_name, opt)
        policy = easyp.gen_policy(**params)
        debug("\n%s" % policy)

        tmp = tempfile.NamedTemporaryFile(prefix = '%s-' % policy_name)
        if sys.version_info[0] >= 3:
            tmp.write(bytes(policy, 'utf-8'))
        else:
            tmp.write(policy)
        tmp.flush()

        debug("using '%s' template" % opt.template)
        # TODO: get rid of this
        if opt.withx:
            rc, report = cmd(['pkexec', 'apparmor_parser', '-r', '%s' % tmp.name])
        else:
            rc, report = cmd(['sudo', 'apparmor_parser', '-r', tmp.name])
        if rc != 0:
            raise AppArmorException("Could not load policy")

        rc, report = cmd(['sudo', 'apparmor_parser', '-p', tmp.name])
        if rc != 0:
            raise AppArmorException("Could not dump policy")

        # Make sure the dynamic profile has the appropriate line for X
        for r in verify_rules:
            found = False
            for line in report.splitlines():
                line = line.strip()
                if r == line:
                    found = True
                    break
            if not found:
                raise AppArmorException("Could not find required rule: %s" % r)

    set_environ(environ)
    args = ['aa-exec', '-p', policy_name, '--'] + command
    rc, report = cmd(args)
    return rc, report
Example #5
0
    def find_free_x_display(self):
        '''Find a free X display'''
        old_lang = None
        if 'LANG' in os.environ:
            old_lang = os.environ['LANG']
        os.environ['LANG'] = 'C'

        display = ""
        current = self.old_environ["DISPLAY"]
        for i in range(1, 257):  # TODO: this puts an artificial limit of 256
            #       sandboxed applications
            tmp = ":%d" % i
            os.environ["DISPLAY"] = tmp
            rc, report = cmd(['xset', '-q'])
            if rc != 0 and 'Invalid MIT-MAGIC-COOKIE-1' not in report:
                display = tmp
                break

        if old_lang:
            os.environ['LANG'] = old_lang

        os.environ["DISPLAY"] = current
        if display == "":
            raise AppArmorException("Could not find available X display")

        # Use dedicated .Xauthority file
        xauth = os.path.join(os.path.expanduser('~'), \
                             '.Xauthority-sandbox%s' % display.split(':')[1])

        return display, xauth
Example #6
0
    def start(self):
        '''Start a nested X server (need to override)'''
        # clean up the old one
        if os.path.exists(self.xauth):
            os.unlink(self.xauth)
        rc, cookie = cmd(['mcookie'])
        if rc != 0:
            raise AppArmorException("Could not generate magic cookie")

        rc, out = cmd(['xauth', '-f', self.xauth, \
                       'add', \
                       self.display, \
                       'MIT-MAGIC-COOKIE-1', \
                       cookie.strip()])
        if rc != 0:
            raise AppArmorException("Could not generate '%s'" % self.display)
Example #7
0
    def start(self):
        '''Start a nested X server (need to override)'''
        # clean up the old one
        if os.path.exists(self.xauth):
            os.unlink(self.xauth)
        rc, cookie = cmd(['mcookie'])
        if rc != 0:
            raise AppArmorException("Could not generate magic cookie")

        rc, out = cmd(['xauth', '-f', self.xauth, \
                       'add', \
                       self.display, \
                       'MIT-MAGIC-COOKIE-1', \
                       cookie.strip()])
        if rc != 0:
            raise AppArmorException("Could not generate '%s'" % self.display)
Example #8
0
    def find_free_x_display(self):
        '''Find a free X display'''
        old_lang = None
        if 'LANG' in os.environ:
            old_lang = os.environ['LANG']
        os.environ['LANG'] = 'C'

        display = ""
        current = self.old_environ["DISPLAY"]
        for i in range(1,257): # TODO: this puts an artificial limit of 256
                               #       sandboxed applications
            tmp = ":%d" % i
            os.environ["DISPLAY"] = tmp
            rc, report = cmd(['xset', '-q'])
            if rc != 0 and 'Invalid MIT-MAGIC-COOKIE-1' not in report:
                display = tmp
                break

        if old_lang:
            os.environ['LANG'] = old_lang

        os.environ["DISPLAY"] = current
        if display == "":
            raise AppArmorException("Could not find available X display")

        # Use dedicated .Xauthority file
        xauth = os.path.join(os.path.expanduser('~'), \
                             '.Xauthority-sandbox%s' % display.split(':')[1])

        return display, xauth
Example #9
0
    def reload_profile(self, profile):
        if not self.do_reload:
            return

        cmd_info = cmd([apparmor.parser, '-I%s' % apparmor.profile_dir, '--base', apparmor.profile_dir, '-r', profile])

        if cmd_info[0] != 0:
            raise apparmor.AppArmorException(cmd_info[1])
Example #10
0
    def reload_profile(self, profile):
        if not self.do_reload:
            return

        cmd_info = cmd([apparmor.parser, '-I%s' % apparmor.profile_dir, '--base', apparmor.profile_dir, '-r', profile])

        if cmd_info[0] != 0:
            raise apparmor.AppArmorException(cmd_info[1])
Example #11
0
    def unload_profile(self, profile):
        if not self.do_reload:
            return

        # FIXME: should ensure profile is loaded before unloading
        cmd_info = cmd([apparmor.parser, '-I%s' % apparmor.profile_dir, '--base', apparmor.profile_dir, '-R', profile])

        if cmd_info[0] != 0:
            raise apparmor.AppArmorException(cmd_info[1])
Example #12
0
    def unload_profile(self, profile):
        if not self.do_reload:
            return

        # FIXME: should ensure profile is loaded before unloading
        cmd_info = cmd([apparmor.parser, '-I%s' % apparmor.profile_dir, '--base', apparmor.profile_dir, '-R', profile])

        if cmd_info[0] != 0:
            raise apparmor.AppArmorException(cmd_info[1])
Example #13
0
def check_requirements(binary):
    '''Verify necessary software is installed'''
    exes = ['xset',        # for detecting free X display
            'aa-easyprof', # for templates
            'aa-exec',     # for changing profile
            'sudo',        # eventually get rid of this
            'pkexec',      # eventually get rid of this
            binary]

    for e in exes:
        debug("Searching for '%s'" % e)
        rc, report = cmd(['which', e])
        if rc != 0:
            error("Could not find '%s'" % e, do_exit=False)
            return False

    return True
Example #14
0
def check_requirements(binary):
    '''Verify necessary software is installed'''
    exes = ['xset',        # for detecting free X display
            'aa-easyprof', # for templates
            'aa-exec',     # for changing profile
            'sudo',        # eventually get rid of this
            'pkexec',      # eventually get rid of this
            binary]

    for e in exes:
        debug("Searching for '%s'" % e)
        rc, report = cmd(['which', e])
        if rc != 0:
            error("Could not find '%s'" % e, do_exit=False)
            return False

    return True
Example #15
0
    def cleanup(self):
        sys.stderr.flush()
        listener = os.fork()
        if listener == 0:
            args = ['/usr/bin/xpra', 'stop', self.display]
            debug(" ".join(args))
            os.execv(args[0], args)
            sys.exit(0)
        time.sleep(2)

        # Annoyingly, xpra doesn't clean up itself well if the application
        # failed for some reason. Try to account for that.
        rc, report = cmd(['ps', 'auxww'])
        for line in report.splitlines():
            if '-for-Xpra-%s' % self.display in line:
                self.pids.append(int(line.split()[1]))

        SandboxXserver.cleanup(self)
Example #16
0
    def cleanup(self):
        sys.stderr.flush()
        listener = os.fork()
        if listener == 0:
            args = ['/usr/bin/xpra', 'stop', self.display]
            debug(" ".join(args))
            os.execv(args[0], args)
            sys.exit(0)
        time.sleep(2)

        # Annoyingly, xpra doesn't clean up itself well if the application
        # failed for some reason. Try to account for that.
        rc, report = cmd(['ps', 'auxww'])
        for line in report.splitlines():
            if '-for-Xpra-%s' % self.display in line:
                self.pids.append(int(line.split()[1]))

        SandboxXserver.cleanup(self)
Example #17
0
    def verify_host_setup(self):
        '''Make sure we have everything we need'''
        old_lang = None
        if 'LANG' in os.environ:
            old_lang = os.environ['LANG']

        os.environ['LANG'] = 'C'
        rc, report = cmd(['xhost'])

        if old_lang:
            os.environ['LANG'] = old_lang

        if rc != 0:
            raise AppArmorException("'xhost' exited with error")
        if 'access control enabled' not in report:
            raise AppArmorException("Access control currently disabled. Please enable with 'xhost -'")
        username = pwd.getpwuid(os.geteuid())[0]
        if ':localuser:%s' % username in report:
            raise AppArmorException("Access control allows '%s' full access. Please see 'man aa-sandbox' for details" % username)
Example #18
0
    def verify_host_setup(self):
        '''Make sure we have everything we need'''
        old_lang = None
        if 'LANG' in os.environ:
            old_lang = os.environ['LANG']

        os.environ['LANG'] = 'C'
        rc, report = cmd(['xhost'])

        if old_lang:
            os.environ['LANG'] = old_lang

        if rc != 0:
            raise AppArmorException("'xhost' exited with error")
        if 'access control enabled' not in report:
            raise AppArmorException("Access control currently disabled. Please enable with 'xhost -'")
        username = pwd.getpwuid(os.geteuid())[0]
        if ':localuser:%s' % username in report:
            raise AppArmorException("Access control allows '%s' full access. Please see 'man aa-sandbox' for details" % username)
Example #19
0
    def test_network_keyword_list(self):
        rc, output = cmd('../../common/list_af_names.sh')
        self.assertEqual(rc, 0)

        af_names = []
        af_pairs = output.replace('AF_', '').strip().lower().split(",")
        for af_pair in af_pairs:
            af_name = af_pair.lstrip().split(" ")[0]
            # skip max af name definition
            if len(af_name) > 0 and af_name != "max":
                af_names.append(af_name)

        missing_af_names = []
        for keyword in af_names:
            if keyword not in network_domain_keywords:
                # keywords missing in the system are ok (= older kernel), but network_domain_keywords needs to have the full list
                missing_af_names.append(keyword)

        self.assertEqual(
            missing_af_names, [],
            'Missing af_names in NetworkRule network_domain_keywords. This test is likely running '
            'on an newer kernel and will require updating the list of network domain keywords in utils/apparmor/rule/network.py'
        )
Example #20
0
    def start(self):
        debug("Searching for '%s'" % 'xpra')
        rc, report = cmd(['which', 'xpra'])
        if rc != 0:
            raise AppArmorException("Could not find '%s'" % 'xpra')

        if self.driver == "xdummy":
            # FIXME: is there a better way we can detect this?
            drv = "/usr/lib/xorg/modules/drivers/dummy_drv.so"
            debug("Searching for '%s'" % drv)
            if not os.path.exists(drv):
                raise AppArmorException("Could not find '%s'" % drv)
        '''Run any setup code'''
        SandboxXserver.start(self)

        xvfb_args = self._get_xvfb_args()
        listener_x = os.fork()
        if listener_x == 0:
            os.environ['XAUTHORITY'] = self.xauth

            # This will clean out any dead sessions
            cmd(['xpra', 'list'])

            x_args = [
                '--no-daemon',
                #'--no-mmap', # for security?
                '--no-pulseaudio'
            ]
            if not self.clipboard:
                x_args.append('--no-clipboard')

            if xvfb_args != '':
                x_args.append(" ".join(xvfb_args))

            args = ['/usr/bin/xpra', 'start', self.display] + x_args
            debug(" ".join(args))
            sys.stderr.flush()
            os.execv(args[0], args)
            sys.exit(0)
        self.pids.append(listener_x)

        started = False

        # We need to wait for the xpra socket to exist before attaching
        fn = os.path.join(os.environ['HOME'], '.xpra', '%s-%s' % \
                          (socket.gethostname(), self.display.split(':')[1]))
        for i in range(self.timeout *
                       2):  # up to self.timeout seconds to start
            if os.path.exists(fn):
                debug("Found '%s'! Proceeding to attach" % fn)
                break
            debug("'%s' doesn't exist yet, waiting" % fn)
            time.sleep(0.5)

        if not os.path.exists(fn):
            sys.stdout.flush()
            self.cleanup()
            raise AppArmorException("Could not start xpra (try again with -d)")

        for i in range(self.timeout):  # Up to self.timeout seconds to start
            rc, out = cmd(['xpra', 'list'])

            if 'DEAD session at %s' % self.display in out:
                error("xpra session at '%s' died" % self.display,
                      do_exit=False)
                break

            search = 'LIVE session at %s' % self.display
            if search in out:
                started = True
                break
            time.sleep(0.5)
            debug("Could not find '%s' in:\n" % search)
            debug(out)

        if not started:
            sys.stdout.flush()
            self.cleanup()
            raise AppArmorException("Could not start xpra (try again with -d)")

        # Next, attach to xpra
        sys.stdout.flush()
        os.chdir(os.environ["HOME"])
        listener_attach = os.fork()
        if listener_attach == 0:
            args = [
                '/usr/bin/xpra',
                'attach',
                self.display,
                '--title=%s' % self.generate_title(),
                #'--no-mmap', # for security?
                '--no-tray',
                '--no-pulseaudio'
            ]
            if not self.clipboard:
                args.append('--no-clipboard')

            debug(" ".join(args))
            sys.stderr.flush()
            os.execv(args[0], args)
            sys.exit(0)

        self.pids.append(listener_attach)

        # Make sure that a client has attached
        for i in range(self.timeout):  # up to self.timeout seconds to attach
            time.sleep(1)
            rc, out = cmd(['xpra', 'info', self.display])
            search = 'clients=1'
            if search in out:
                debug("Client successfully attached!")
                break
            debug("Could not find '%s' in:\n" % search)
            debug(out)

        msg("TODO: filter '~/.xpra/run-xpra'")
Example #21
0
    def start(self):
        debug("Searching for '%s'" % 'xpra')
        rc, report = cmd(['which', 'xpra'])
        if rc != 0:
            raise AppArmorException("Could not find '%s'" % 'xpra')

        if self.driver == "xdummy":
            # FIXME: is there a better way we can detect this?
            drv = "/usr/lib/xorg/modules/drivers/dummy_drv.so"
            debug("Searching for '%s'" % drv)
            if not os.path.exists(drv):
                raise AppArmorException("Could not find '%s'" % drv)

        '''Run any setup code'''
        SandboxXserver.start(self)

        xvfb_args = self._get_xvfb_args()
        listener_x = os.fork()
        if listener_x == 0:
            os.environ['XAUTHORITY'] = self.xauth

            # This will clean out any dead sessions
            cmd(['xpra', 'list'])

            x_args = ['--no-daemon',
                      #'--no-mmap', # for security?
                      '--no-pulseaudio']
            if not self.clipboard:
                x_args.append('--no-clipboard')

            if xvfb_args != '':
                x_args.append(" ".join(xvfb_args))

            args = ['/usr/bin/xpra', 'start', self.display] + x_args
            debug(" ".join(args))
            sys.stderr.flush()
            os.execv(args[0], args)
            sys.exit(0)
        self.pids.append(listener_x)

        started = False

        # We need to wait for the xpra socket to exist before attaching
        fn = os.path.join(os.environ['HOME'], '.xpra', '%s-%s' % \
                          (socket.gethostname(), self.display.split(':')[1]))
        for i in range(self.timeout * 2): # up to self.timeout seconds to start
            if os.path.exists(fn):
                debug("Found '%s'! Proceeding to attach" % fn)
                break
            debug("'%s' doesn't exist yet, waiting" % fn)
            time.sleep(0.5)

        if not os.path.exists(fn):
            sys.stdout.flush()
            self.cleanup()
            raise AppArmorException("Could not start xpra (try again with -d)")

        for i in range(self.timeout): # Up to self.timeout seconds to start
            rc, out = cmd(['xpra', 'list'])

            if 'DEAD session at %s' % self.display in out:
                error("xpra session at '%s' died" % self.display, do_exit=False)
                break

            search = 'LIVE session at %s' % self.display
            if search in out:
                started = True
                break
            time.sleep(0.5)
            debug("Could not find '%s' in:\n" % search)
            debug(out)

        if not started:
            sys.stdout.flush()
            self.cleanup()
            raise AppArmorException("Could not start xpra (try again with -d)")

        # Next, attach to xpra
        sys.stdout.flush()
        os.chdir(os.environ["HOME"])
        listener_attach = os.fork()
        if listener_attach == 0:
            args = ['/usr/bin/xpra', 'attach', self.display,
                                     '--title=%s' % self.generate_title(),
                                     #'--no-mmap', # for security?
                                     '--no-tray',
                                     '--no-pulseaudio']
            if not self.clipboard:
                args.append('--no-clipboard')

            debug(" ".join(args))
            sys.stderr.flush()
            os.execv(args[0], args)
            sys.exit(0)

        self.pids.append(listener_attach)

        # Make sure that a client has attached
        for i in range(self.timeout): # up to self.timeout seconds to attach
            time.sleep(1)
            rc, out = cmd (['xpra', 'info', self.display])
            search = 'clients=1'
            if search in out:
                debug("Client successfully attached!")
                break
            debug("Could not find '%s' in:\n" % search)
            debug(out)

        msg("TODO: filter '~/.xpra/run-xpra'")