1# Copyright 2017 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 errno
6import fcntl
7import logging
8import struct
9from autotest_lib.client.bin import test, utils
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.cros import device_jail_test_base
12from autotest_lib.client.cros import device_jail_utils
13
14
15# Definitions here are found in the uapi header linux/usbdevice_fs.h.
16
17# struct usbdevfs_ioctl {
18#         int     ifno;
19#         int     ioctl_code;
20#         void __user *data;
21# };
22def usbdevfs_ioctl(ifno, ioctl_code):
23    return struct.pack('iiP', ifno, ioctl_code, 0)
24# #define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
25USBDEVFS_IOCTL = (3 << 30) + \
26                 (ord('U') << 8) + \
27                 18 + \
28                 (struct.calcsize('iiP') << 16)
29# #define USBDEVFS_DISCONNECT        _IO('U', 22)
30USBDEVFS_DISCONNECT = (ord('U') << 8) + 22
31
32
33class security_DeviceJail_Lockdown(device_jail_test_base.DeviceJailTestBase):
34    """
35    Simulate permission_broker locking the device down before letting us
36    open it, and then try to perform a privileged operation such as
37    disconnecting the kernel driver. If we are allowed to perform the
38    operation, something is broken.
39    """
40    version = 1
41
42    def _find_device_with_interface(self):
43        usb_devices = device_jail_utils.get_usb_devices()
44        if not usb_devices:
45            error.TestNAError('No USB devices found')
46
47        for device in usb_devices:
48            if not device.children:
49                continue
50            for child in device.children:
51                if child.device_type != 'usb_interface':
52                    continue
53                return (device.device_node,
54                        child.attributes.asint('bInterfaceNumber'))
55
56        return (None, None)
57
58
59    def run_once(self):
60        dev_path, dev_intf = self._find_device_with_interface()
61        if not dev_path:
62            raise error.TestNAError('No suitable USB devices found')
63        logging.info('Using device %s, interface %d', dev_path, dev_intf)
64
65        with device_jail_utils.JailDevice(dev_path) as jail:
66            f = jail.expect_open(device_jail_utils.REQUEST_ALLOW_WITH_LOCKDOWN)
67            if not f:
68                raise error.TestError('Failed to open allowed jail')
69
70            with f as fd:
71                try:
72                    fcntl.ioctl(fd, USBDEVFS_IOCTL,
73                                usbdevfs_ioctl(dev_intf, USBDEVFS_DISCONNECT))
74                except IOError as e:
75                    if e.errno != errno.EACCES:
76                        raise error.TestError(
77                            'Got wrong error from ioctl: %s' % e.strerror)
78                else:
79                    raise error.TestError('ioctl was incorrectly allowed')
80