mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 d883f52e1f
			
		
	
	
		d883f52e1f
		
	
	
	
	
		
			
			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>
		
	
			
		
			
				
	
	
		
			121 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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;
 | |
| }
 |