| #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; |
| } |