コード例 #1
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
コード例 #2
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
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
コード例 #3
0
def run_xsandbox(command, opt):
    '''Run X application in a sandbox'''
    old_cwd = os.getcwd()

    # first, start X
    if opt.xserver.lower() == "xephyr":
        x = SandboxXephyr(command[0],
                          geometry=opt.xephyr_geometry,
                          xauth=opt.xauthority)
    elif opt.xserver.lower() == "xpra3d":
        x = SandboxXpra(command[0],
                        geometry=None,
                        driver="xdummy",
                        xauth=opt.xauthority,
                        clipboard=opt.with_clipboard)
    else:
        x = SandboxXpra(command[0],
                        geometry=None,
                        xauth=opt.xauthority,
                        clipboard=opt.with_clipboard)

    x.verify_host_setup()

    # Debug: show old environment
    keys = x.old_environ.keys()
    keys.sort()
    for k in keys:
        debug("Old: %s=%s" % (k, x.old_environ[k]))

    try:
        x.start()
    except Exception as e:
        error(e)
    os.chdir(old_cwd)

    if not opt.read_path:
        opt.read_path = []
    opt.read_path.append(x.xauth)

    # Only used with dynamic profiles
    required_rules = ['audit deny @{HOME}/.Xauthority mrwlk,']

    # aa-exec
    try:
        rc, report = aa_exec(command, opt, x.new_environ, required_rules)
    except Exception:
        x.cleanup()
        raise
    x.cleanup()

    return rc, report
コード例 #4
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
def run_xsandbox(command, opt):
    '''Run X application in a sandbox'''
    old_cwd = os.getcwd()

    # first, start X
    if opt.xserver.lower() == "xephyr":
        x = SandboxXephyr(command[0], geometry=opt.xephyr_geometry,
                                      xauth=opt.xauthority)
    elif opt.xserver.lower() == "xpra3d":
        x = SandboxXpra(command[0], geometry=None,
                                    driver="xdummy",
                                    xauth=opt.xauthority,
                                    clipboard=opt.with_clipboard)
    else:
        x = SandboxXpra(command[0], geometry=None,
                                    xauth=opt.xauthority,
                                    clipboard=opt.with_clipboard)

    x.verify_host_setup()

    # Debug: show old environment
    keys = x.old_environ.keys()
    keys.sort()
    for k in keys:
        debug ("Old: %s=%s" % (k, x.old_environ[k]))

    try:
        x.start()
    except Exception as e:
        error(e)
    os.chdir(old_cwd)

    if not opt.read_path:
        opt.read_path = []
    opt.read_path.append(x.xauth)

    # Only used with dynamic profiles
    required_rules = ['audit deny @{HOME}/.Xauthority mrwlk,']

    # aa-exec
    try:
        rc, report = aa_exec(command, opt, x.new_environ, required_rules)
    except Exception as e:
        x.cleanup()
        raise
    x.cleanup()

    return rc, report
コード例 #5
0
ファイル: sandbox.py プロジェクト: pexip/os-apparmor
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
コード例 #6
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
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
コード例 #7
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)
コード例 #8
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
    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)
コード例 #9
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
コード例 #10
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
    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
コード例 #11
0
    def cleanup(self):
        '''Cleanup our forked pids, reset the environment, etc'''
        self.pids.reverse()
        debug(self.pids)
        for pid in self.pids:
            # Kill server with TERM
            debug("kill %d" % pid)
            os.kill(pid, signal.SIGTERM)

        for pid in self.pids:
            # Shoot the server dead
            debug("kill -9 %d" % pid)
            os.kill(pid, signal.SIGKILL)

        for t in self.tempfiles:
            if os.path.exists(t):
                os.unlink(t)

        if os.path.exists(self.xauth):
            os.unlink(self.xauth)

        # Reset our environment
        set_environ(self.old_environ)
コード例 #12
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
    def cleanup(self):
        '''Cleanup our forked pids, reset the environment, etc'''
        self.pids.reverse()
        debug(self.pids)
        for pid in self.pids:
            # Kill server with TERM
            debug("kill %d" % pid)
            os.kill(pid, signal.SIGTERM)

        for pid in self.pids:
            # Shoot the server dead
            debug("kill -9 %d" % pid)
            os.kill(pid, signal.SIGKILL)

        for t in self.tempfiles:
            if os.path.exists(t):
                os.unlink(t)

        if os.path.exists(self.xauth):
            os.unlink(self.xauth)

        # Reset our environment
        set_environ(self.old_environ)
コード例 #13
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'")
コード例 #14
0
ファイル: sandbox.py プロジェクト: crossbuild/apparmor
    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'")