| # Copyright 2017 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import dbus |
| import logging |
| import os.path |
| import pwd |
| import socket |
| |
| from autotest_lib.client.bin import test, utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.cros import constants, login |
| |
| |
| class security_SessionManagerDbusEndpoints(test.test): |
| """Verifies SessionManager DBus endpoints are not exposed. |
| """ |
| version = 1 |
| |
| _FLAGFILE = '/tmp/security_SessionManagerDbusEndpoints_regression' |
| |
| |
| def _set_user_environment(self, username): |
| for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'): |
| if name in os.environ: |
| os.environ[name] = username |
| |
| |
| def _set_user(self, username): |
| user_info = pwd.getpwnam(username) |
| os.setegid(user_info[3]) |
| os.seteuid(user_info[2]) |
| self._set_user_environment(username) |
| |
| |
| def _reset_user(self): |
| uid = os.getuid() |
| username = pwd.getpwuid(uid)[0] |
| os.seteuid(uid) |
| os.setegid(os.getgid()) |
| self._set_user_environment(username) |
| |
| |
| def _ps(self, proc=constants.BROWSER): |
| """Grab the oldest pid for process |proc|.""" |
| pscmd = 'ps -C %s -o pid --no-header | head -1' % proc |
| return utils.system_output(pscmd) |
| |
| |
| def run_once(self): |
| """Main test code.""" |
| login.wait_for_browser() |
| passed_enable_chrome_testing = self.test_enable_chrome_testing() |
| passed_restart_job = self.test_restart_job() |
| |
| if not passed_enable_chrome_testing or not passed_restart_job: |
| raise error.TestFail('SessionManager DBus endpoints can be abused, ' |
| 'see error log') |
| |
| |
| def test_restart_job(self): |
| """Test SessionManager.RestartJob.""" |
| bus = dbus.SystemBus() |
| proxy = bus.get_object('org.chromium.SessionManager', |
| '/org/chromium/SessionManager') |
| session_manager = dbus.Interface(proxy, |
| 'org.chromium.SessionManagerInterface') |
| |
| # Craft a malicious replacement for the target process. |
| cmd = ['touch', self._FLAGFILE] |
| |
| # Try to get our malicious replacement to run via RestartJob. |
| try: |
| remote, local = socket.socketpair(socket.AF_UNIX) |
| logging.info('Calling RestartJob(<socket>, %r)', cmd) |
| session_manager.RestartJob(dbus.types.UnixFd(remote), cmd) |
| # Fails if the RestartJob call doesn't generate an error. |
| logging.error( |
| 'RestartJob did not fail when passed an arbitrary command') |
| return False |
| except dbus.DBusException as e: |
| logging.info(e.get_dbus_message()) |
| pass |
| except OSError as e: |
| raise error.TestError('Could not create sockets for creds: %s', e) |
| finally: |
| try: |
| local.close() |
| except OSError: |
| pass |
| |
| if os.path.exists(self._FLAGFILE): |
| logging.error('RestartJob ran an arbitrary command') |
| return False |
| |
| return True |
| |
| |
| def test_enable_chrome_testing(self): |
| """Test SessionManager.EnableChromeTesting.""" |
| self._set_user('chronos') |
| |
| bus = dbus.SystemBus() |
| proxy = bus.get_object('org.chromium.SessionManager', |
| '/org/chromium/SessionManager') |
| session_manager = dbus.Interface(proxy, |
| 'org.chromium.SessionManagerInterface') |
| |
| chrome_pid = self._ps() |
| |
| # Try DBus call and make sure it fails. |
| try: |
| # DBus cannot infer the type of an empty Python list. |
| # Pass an empty dbus.Array with the correct signature, taken from |
| # platform2/login_manager/dbus_bindings/org.chromium.SessionManagerInterface.xml. |
| empty_string_array = dbus.Array(signature="as") |
| path = session_manager.EnableChromeTesting(True, empty_string_array, |
| empty_string_array) |
| except dbus.exceptions.DBusException as dbe: |
| logging.info(dbe) |
| else: |
| logging.error('EnableChromeTesting ' |
| 'succeeded when it should have failed') |
| return False |
| |
| # Make sure Chrome didn't restart. |
| if chrome_pid != self._ps(): |
| logging.error('Chrome restarted during test.') |
| return False |
| |
| self._reset_user() |
| return True |