1# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import dbus
6import logging
7import os.path
8import socket
9
10from autotest_lib.client.bin import test, utils
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.cros import constants, cros_ui, login
13
14
15class security_RestartJob(test.test):
16    """Verifies that RestartJob cannot be abused to execute arbitrary processes.
17    """
18    version = 1
19
20
21    _FLAGFILE = '/tmp/security_RestartJob_regression'
22
23
24    def _ps(self, proc=constants.BROWSER):
25        """Grab the oldest pid for a process named |proc|."""
26        pscmd = 'ps -C %s -o pid --no-header | head -1' % proc
27        return utils.system_output(pscmd)
28
29
30    def run_once(self):
31        """Main test code."""
32        login.wait_for_browser()
33        bus = dbus.SystemBus()
34        proxy = bus.get_object('org.chromium.SessionManager',
35                               '/org/chromium/SessionManager')
36        sessionmanager = dbus.Interface(proxy,
37                                        'org.chromium.SessionManagerInterface')
38
39        # Craft a malicious replacement for the target process.
40        cmd = ['touch', self._FLAGFILE]
41
42        # Try to get our malicious replacement to run via RestartJob.
43        try:
44            remote, local = socket.socketpair(socket.AF_UNIX)
45            logging.info('Calling RestartJob(<socket>, %r)', cmd)
46            sessionmanager.RestartJob(dbus.types.UnixFd(remote), cmd)
47            # Fails if the RestartJob call doesn't generate an error.
48            raise error.TestFail('RestartJob regression!')
49        except dbus.DBusException as e:
50            logging.info(e.get_dbus_message())
51            pass
52        except OSError as e:
53            raise error.TestError('Could not create sockets for creds: %s', e)
54        finally:
55            try:
56                local.close()
57            except OSError:
58                pass
59
60        if os.path.exists(self._FLAGFILE):
61            raise error.TestFail('RestartJobWithAuth regression!')
62
63
64    def cleanup(self):
65        """Reset the UI, since this test killed Chrome."""
66        cros_ui.nuke()
67