-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
usb: devio: Add ioctl to disallow detaching kernel USB drivers.
The new USBDEVFS_DROP_PRIVILEGES ioctl allows a process to voluntarily relinquish the ability to issue other ioctls that may interfere with other processes and drivers that have claimed an interface on the device. This commit also includes a simple utility to be able to test the ioctl, located at Documentation/usb/usbdevfs-drop-permissions.c Example (with qemu-kvm's input device): $ lsusb ... Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd $ usb-devices ... C: #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=02 Driver=usbhid $ sudo ./usbdevfs-drop-permissions /dev/bus/usb/001/002 OK: privileges dropped! Available options: [0] Exit now [1] Reset device. Should fail if device is in use [2] Claim 4 interfaces. Should succeed where not in use [3] Narrow interface permission mask Which option shall I run?: 1 ERROR: USBDEVFS_RESET failed! (1 - Operation not permitted) Which test shall I run next?: 2 ERROR claiming if 0 (1 - Operation not permitted) ERROR claiming if 1 (1 - Operation not permitted) ERROR claiming if 2 (1 - Operation not permitted) ERROR claiming if 3 (1 - Operation not permitted) Which test shall I run next?: 0 After unbinding usbhid: $ usb-devices ... I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=02 Driver=(none) $ sudo ./usbdevfs-drop-permissions /dev/bus/usb/001/002 ... Which option shall I run?: 2 OK: claimed if 0 ERROR claiming if 1 (1 - Operation not permitted) ERROR claiming if 2 (1 - Operation not permitted) ERROR claiming if 3 (1 - Operation not permitted) Which test shall I run next?: 1 OK: USBDEVFS_RESET succeeded Which test shall I run next?: 0 After unbinding usbhid and restricting the mask: $ sudo ./usbdevfs-drop-permissions /dev/bus/usb/001/002 ... Which option shall I run?: 3 Insert new mask: 0 OK: privileges dropped! Which test shall I run next?: 2 ERROR claiming if 0 (1 - Operation not permitted) ERROR claiming if 1 (1 - Operation not permitted) ERROR claiming if 2 (1 - Operation not permitted) ERROR claiming if 3 (1 - Operation not permitted) Signed-off-by: Reilly Grant <reillyg@chromium.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Emilio López <emilio.lopez@collabora.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- Loading branch information
Reilly Grant
authored and
Greg Kroah-Hartman
committed
Mar 5, 2016
1 parent
3d0712d
commit d883f52
Showing
4 changed files
with
192 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#include <sys/ioctl.h> | ||
#include <sys/types.h> | ||
#include <sys/stat.h> | ||
#include <fcntl.h> | ||
#include <stdio.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
#include <inttypes.h> | ||
#include <unistd.h> | ||
|
||
#include <linux/usbdevice_fs.h> | ||
|
||
/* For building without an updated set of headers */ | ||
#ifndef USBDEVFS_DROP_PRIVILEGES | ||
#define USBDEVFS_DROP_PRIVILEGES _IOW('U', 30, __u32) | ||
#define USBDEVFS_CAP_DROP_PRIVILEGES 0x40 | ||
#endif | ||
|
||
void drop_privileges(int fd, uint32_t mask) | ||
{ | ||
int res; | ||
|
||
res = ioctl(fd, USBDEVFS_DROP_PRIVILEGES, &mask); | ||
if (res) | ||
printf("ERROR: USBDEVFS_DROP_PRIVILEGES returned %d\n", res); | ||
else | ||
printf("OK: privileges dropped!\n"); | ||
} | ||
|
||
void reset_device(int fd) | ||
{ | ||
int res; | ||
|
||
res = ioctl(fd, USBDEVFS_RESET); | ||
if (!res) | ||
printf("OK: USBDEVFS_RESET succeeded\n"); | ||
else | ||
printf("ERROR: reset failed! (%d - %s)\n", | ||
-res, strerror(-res)); | ||
} | ||
|
||
void claim_some_intf(int fd) | ||
{ | ||
int i, res; | ||
|
||
for (i = 0; i < 4; i++) { | ||
res = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &i); | ||
if (!res) | ||
printf("OK: claimed if %d\n", i); | ||
else | ||
printf("ERROR claiming if %d (%d - %s)\n", | ||
i, -res, strerror(-res)); | ||
} | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
uint32_t mask, caps; | ||
int c, fd; | ||
|
||
fd = open(argv[1], O_RDWR); | ||
if (fd < 0) { | ||
printf("Failed to open file\n"); | ||
goto err_fd; | ||
} | ||
|
||
/* | ||
* check if dropping privileges is supported, | ||
* bail on systems where the capability is not present | ||
*/ | ||
ioctl(fd, USBDEVFS_GET_CAPABILITIES, &caps); | ||
if (!(caps & USBDEVFS_CAP_DROP_PRIVILEGES)) { | ||
printf("DROP_PRIVILEGES not supported\n"); | ||
goto err; | ||
} | ||
|
||
/* | ||
* Drop privileges but keep the ability to claim all | ||
* free interfaces (i.e., those not used by kernel drivers) | ||
*/ | ||
drop_privileges(fd, -1U); | ||
|
||
printf("Available options:\n" | ||
"[0] Exit now\n" | ||
"[1] Reset device. Should fail if device is in use\n" | ||
"[2] Claim 4 interfaces. Should succeed where not in use\n" | ||
"[3] Narrow interface permission mask\n" | ||
"Which option shall I run?: "); | ||
|
||
while (scanf("%d", &c) == 1) { | ||
switch (c) { | ||
case 0: | ||
goto exit; | ||
case 1: | ||
reset_device(fd); | ||
break; | ||
case 2: | ||
claim_some_intf(fd); | ||
break; | ||
case 3: | ||
printf("Insert new mask: "); | ||
scanf("%x", &mask); | ||
drop_privileges(fd, mask); | ||
break; | ||
default: | ||
printf("I don't recognize that\n"); | ||
} | ||
|
||
printf("Which test shall I run next?: "); | ||
} | ||
|
||
exit: | ||
close(fd); | ||
return 0; | ||
|
||
err: | ||
close(fd); | ||
err_fd: | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters