linux_dsm_epyc7002/drivers/usb/core/devio.c

2802 lines
68 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0+
/*****************************************************************************/
/*
* devio.c -- User space communication with USB devices.
*
* Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This file implements the usbfs/x/y files, where
* x is the bus number and y the device number.
*
* It allows user space programs/"drivers" to communicate directly
* with USB devices without intervening kernel driver.
*
* Revision history
* 22.12.1999 0.1 Initial release (split from proc_usb.c)
* 04.01.2000 0.2 Turned into its own filesystem
* 30.09.2005 0.3 Fix user-triggerable oops in async URB delivery
* (CAN-2005-3055)
*/
/*****************************************************************************/
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h> /* for usbcore internals */
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
#include <linux/cdev.h>
#include <linux/notifier.h>
#include <linux/security.h>
#include <linux/user_namespace.h>
#include <linux/scatterlist.h>
#include <linux/uaccess.h>
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
#include <linux/dma-mapping.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
#include "usb.h"
#ifdef CONFIG_PM
#define MAYBE_CAP_SUSPEND USBDEVFS_CAP_SUSPEND
#else
#define MAYBE_CAP_SUSPEND 0
#endif
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
#define USB_MAXBUS 64
#define USB_DEVICE_MAX (USB_MAXBUS * 128)
#define USB_SG_SIZE 16384 /* split-size for large txs */
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
/* Mutual exclusion for ps->list in resume vs. release and remove */
static DEFINE_MUTEX(usbfs_mutex);
struct usb_dev_state {
struct list_head list; /* state list */
struct usb_device *dev;
struct file *file;
spinlock_t lock; /* protects the async urb lists */
struct list_head async_pending;
struct list_head async_completed;
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
struct list_head memory_list;
wait_queue_head_t wait; /* wake up if a request completed */
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
wait_queue_head_t wait_for_resume; /* wake up upon runtime resume */
unsigned int discsignr;
struct pid *disc_pid;
const struct cred *cred;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
sigval_t disccontext;
unsigned long ifclaimed;
u32 disabled_bulk_eps;
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>
2016-02-22 04:38:01 +07:00
unsigned long interface_allowed_mask;
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
int not_yet_resumed;
bool suspend_allowed;
bool privileges_dropped;
};
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
struct usb_memory {
struct list_head memlist;
int vma_use_count;
int urb_use_count;
u32 size;
void *mem;
dma_addr_t dma_handle;
unsigned long vm_start;
struct usb_dev_state *ps;
};
struct async {
struct list_head asynclist;
struct usb_dev_state *ps;
struct pid *pid;
const struct cred *cred;
unsigned int signr;
unsigned int ifnum;
void __user *userbuffer;
void __user *userurb;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
sigval_t userurb_sigval;
struct urb *urb;
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
struct usb_memory *usbm;
unsigned int mem_usage;
int status;
u8 bulk_addr;
u8 bulk_status;
};
static bool usbfs_snoop;
module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
static unsigned usbfs_snoop_max = 65536;
module_param(usbfs_snoop_max, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(usbfs_snoop_max,
"maximum number of bytes to print while snooping");
#define snoop(dev, format, arg...) \
do { \
if (usbfs_snoop) \
dev_info(dev, format, ## arg); \
} while (0)
enum snoop_when {
SUBMIT, COMPLETE
};
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
/* Limit on the total amount of memory we can allocate for transfers */
static u32 usbfs_memory_mb = 16;
module_param(usbfs_memory_mb, uint, 0644);
MODULE_PARM_DESC(usbfs_memory_mb,
"maximum MB allowed for usbfs buffers (0 = no limit)");
/* Hard limit, necessary to avoid arithmetic overflow */
#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */
/* Check whether it's okay to allocate more memory for a transfer */
static int usbfs_increase_memory_usage(u64 amount)
{
u64 lim;
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE() Please do not apply this to mainline directly, instead please re-run the coccinelle script shown below and apply its output. For several reasons, it is desirable to use {READ,WRITE}_ONCE() in preference to ACCESS_ONCE(), and new code is expected to use one of the former. So far, there's been no reason to change most existing uses of ACCESS_ONCE(), as these aren't harmful, and changing them results in churn. However, for some features, the read/write distinction is critical to correct operation. To distinguish these cases, separate read/write accessors must be used. This patch migrates (most) remaining ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following coccinelle script: ---- // Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and // WRITE_ONCE() // $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch virtual patch @ depends on patch @ expression E1, E2; @@ - ACCESS_ONCE(E1) = E2 + WRITE_ONCE(E1, E2) @ depends on patch @ expression E; @@ - ACCESS_ONCE(E) + READ_ONCE(E) ---- Signed-off-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: davem@davemloft.net Cc: linux-arch@vger.kernel.org Cc: mpe@ellerman.id.au Cc: shuah@kernel.org Cc: snitzer@redhat.com Cc: thor.thayer@linux.intel.com Cc: tj@kernel.org Cc: viro@zeniv.linux.org.uk Cc: will.deacon@arm.com Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-24 04:07:29 +07:00
lim = READ_ONCE(usbfs_memory_mb);
lim <<= 20;
atomic64_add(amount, &usbfs_memory_usage);
if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) {
atomic64_sub(amount, &usbfs_memory_usage);
return -ENOMEM;
}
return 0;
}
/* Memory for a transfer is being deallocated */
static void usbfs_decrease_memory_usage(u64 amount)
{
atomic64_sub(amount, &usbfs_memory_usage);
}
static int connected(struct usb_dev_state *ps)
{
return (!list_empty(&ps->list) &&
ps->dev->state != USB_STATE_NOTATTACHED);
}
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
{
struct usb_dev_state *ps = usbm->ps;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
--*count;
if (usbm->urb_use_count == 0 && usbm->vma_use_count == 0) {
list_del(&usbm->memlist);
spin_unlock_irqrestore(&ps->lock, flags);
usb_free_coherent(ps->dev, usbm->size, usbm->mem,
usbm->dma_handle);
usbfs_decrease_memory_usage(
usbm->size + sizeof(struct usb_memory));
kfree(usbm);
} else {
spin_unlock_irqrestore(&ps->lock, flags);
}
}
static void usbdev_vm_open(struct vm_area_struct *vma)
{
struct usb_memory *usbm = vma->vm_private_data;
unsigned long flags;
spin_lock_irqsave(&usbm->ps->lock, flags);
++usbm->vma_use_count;
spin_unlock_irqrestore(&usbm->ps->lock, flags);
}
static void usbdev_vm_close(struct vm_area_struct *vma)
{
struct usb_memory *usbm = vma->vm_private_data;
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
}
static const struct vm_operations_struct usbdev_vm_ops = {
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
.open = usbdev_vm_open,
.close = usbdev_vm_close
};
static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
{
struct usb_memory *usbm = NULL;
struct usb_dev_state *ps = file->private_data;
size_t size = vma->vm_end - vma->vm_start;
void *mem;
unsigned long flags;
dma_addr_t dma_handle;
int ret;
ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
if (ret)
goto error;
usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
if (!usbm) {
ret = -ENOMEM;
goto error_decrease_mem;
}
usb: devio, do not warn when allocation fails usbdev_mmap allocates a buffer. The size of the buffer is determined by a user. So with this code (no need to be root): int fd = open("/dev/bus/usb/001/001", O_RDONLY); mmap(NULL, 0x800000, PROT_READ, MAP_SHARED, fd, 0); we can see a warning: WARNING: CPU: 0 PID: 21771 at ../mm/page_alloc.c:3563 __alloc_pages_slowpath+0x1036/0x16e0() ... Call Trace: [<ffffffff8117a3ae>] ? warn_slowpath_null+0x2e/0x40 [<ffffffff815178b6>] ? __alloc_pages_slowpath+0x1036/0x16e0 [<ffffffff81516880>] ? warn_alloc_failed+0x250/0x250 [<ffffffff8151226b>] ? get_page_from_freelist+0x75b/0x28b0 [<ffffffff815184e3>] ? __alloc_pages_nodemask+0x583/0x6b0 [<ffffffff81517f60>] ? __alloc_pages_slowpath+0x16e0/0x16e0 [<ffffffff810565d4>] ? dma_generic_alloc_coherent+0x104/0x220 [<ffffffffa0269e56>] ? hcd_buffer_alloc+0x1d6/0x3e0 [usbcore] [<ffffffffa0269c80>] ? hcd_buffer_destroy+0xa0/0xa0 [usbcore] [<ffffffffa0228f05>] ? usb_alloc_coherent+0x65/0x90 [usbcore] [<ffffffffa0275c05>] ? usbdev_mmap+0x1a5/0x770 [usbcore] ... Allocations like this one should be marked as __GFP_NOWARN. So do so. The size could be also clipped by something like: if (size >= (1 << (MAX_ORDER + PAGE_SHIFT - 1))) return -ENOMEM; But I think the overall limit of 16M (by usbfs_increase_memory_usage) is enough, so that we only silence the warning here. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Steinar H. Gunderson <sesse@google.com> Cc: Markus Rechberger <mrechberger@gmail.com> Fixes: f7d34b445a (USB: Add support for usbfs zerocopy.) Cc: 4.6+ <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-06-15 20:56:11 +07:00
mem = usb_alloc_coherent(ps->dev, size, GFP_USER | __GFP_NOWARN,
&dma_handle);
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
if (!mem) {
ret = -ENOMEM;
goto error_free_usbm;
}
memset(mem, 0, size);
usbm->mem = mem;
usbm->dma_handle = dma_handle;
usbm->size = size;
usbm->ps = ps;
usbm->vm_start = vma->vm_start;
usbm->vma_use_count = 1;
INIT_LIST_HEAD(&usbm->memlist);
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(usbm->mem) >> PAGE_SHIFT,
size, vma->vm_page_prot) < 0) {
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
return -EAGAIN;
}
vma->vm_flags |= VM_IO;
vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &usbdev_vm_ops;
vma->vm_private_data = usbm;
spin_lock_irqsave(&ps->lock, flags);
list_add_tail(&usbm->memlist, &ps->memory_list);
spin_unlock_irqrestore(&ps->lock, flags);
return 0;
error_free_usbm:
kfree(usbm);
error_decrease_mem:
usbfs_decrease_memory_usage(size + sizeof(struct usb_memory));
error:
return ret;
}
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
struct usb_dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
loff_t pos;
int i;
pos = *ppos;
usb_lock_device(dev);
if (!connected(ps)) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
ret = -EINVAL;
goto err;
}
if (pos < sizeof(struct usb_device_descriptor)) {
/* 18 bytes - fits on the stack */
struct usb_device_descriptor temp_desc;
memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
le16_to_cpus(&temp_desc.bcdUSB);
le16_to_cpus(&temp_desc.idVendor);
le16_to_cpus(&temp_desc.idProduct);
le16_to_cpus(&temp_desc.bcdDevice);
len = sizeof(struct usb_device_descriptor) - pos;
if (len > nbytes)
len = nbytes;
if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
ret = -EFAULT;
goto err;
}
*ppos += len;
buf += len;
nbytes -= len;
ret += len;
}
pos = sizeof(struct usb_device_descriptor);
for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
struct usb_config_descriptor *config =
(struct usb_config_descriptor *)dev->rawdescriptors[i];
unsigned int length = le16_to_cpu(config->wTotalLength);
if (*ppos < pos + length) {
/* The descriptor may claim to be longer than it
* really is. Here is the actual allocated length. */
unsigned alloclen =
le16_to_cpu(dev->config[i].desc.wTotalLength);
len = length - (*ppos - pos);
if (len > nbytes)
len = nbytes;
/* Simply don't write (skip over) unallocated parts */
if (alloclen > (*ppos - pos)) {
alloclen -= (*ppos - pos);
if (copy_to_user(buf,
dev->rawdescriptors[i] + (*ppos - pos),
min(len, alloclen))) {
ret = -EFAULT;
goto err;
}
}
*ppos += len;
buf += len;
nbytes -= len;
ret += len;
}
pos += length;
}
err:
usb_unlock_device(dev);
return ret;
}
/*
* async list handling
*/
static struct async *alloc_async(unsigned int numisoframes)
{
struct async *as;
as = kzalloc(sizeof(struct async), GFP_KERNEL);
if (!as)
return NULL;
as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
if (!as->urb) {
kfree(as);
return NULL;
}
return as;
}
static void free_async(struct async *as)
{
int i;
put_pid(as->pid);
usbfs: Fix oops related to user namespace conversion. When running the Point Grey "flycap" program for their USB 3.0 camera (which was running as a USB 2.0 device for some reason), I trigger this oops whenever I try to open a video stream: Dec 15 16:48:34 puck kernel: [ 1798.715559] BUG: unable to handle kernel NULL pointer dereference at (null) Dec 15 16:48:34 puck kernel: [ 1798.719153] IP: [<ffffffff8147841e>] free_async+0x1e/0x70 Dec 15 16:48:34 puck kernel: [ 1798.720991] PGD 6f833067 PUD 6fc56067 PMD 0 Dec 15 16:48:34 puck kernel: [ 1798.722815] Oops: 0002 [#1] SMP Dec 15 16:48:34 puck kernel: [ 1798.724627] CPU 0 Dec 15 16:48:34 puck kernel: [ 1798.724636] Modules linked in: ecryptfs encrypted_keys sha1_generic trusted binfmt_misc sha256_generic aesni_intel cryptd aes_x86_64 aes_generic parport_pc dm_crypt ppdev joydev snd_hda_codec_hdmi snd_hda_codec_conexant arc4 iwlwifi snd_hda_intel snd_hda_codec snd_hwdep snd_pcm thinkpad_acpi mac80211 snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer btusb uvcvideo snd_seq_device bluetooth videodev psmouse snd v4l2_compat_ioctl32 serio_raw tpm_tis cfg80211 tpm tpm_bios nvram soundcore snd_page_alloc lp parport i915 xhci_hcd ahci libahci drm_kms_helper drm sdhci_pci sdhci e1000e i2c_algo_bit video Dec 15 16:48:34 puck kernel: [ 1798.734212] Dec 15 16:48:34 puck kernel: [ 1798.736162] Pid: 2713, comm: FlyCap2 Not tainted 3.2.0-rc5+ #28 LENOVO 4286CTO/4286CTO Dec 15 16:48:34 puck kernel: [ 1798.738148] RIP: 0010:[<ffffffff8147841e>] [<ffffffff8147841e>] free_async+0x1e/0x70 Dec 15 16:48:34 puck kernel: [ 1798.740134] RSP: 0018:ffff88005715fd78 EFLAGS: 00010296 Dec 15 16:48:34 puck kernel: [ 1798.742118] RAX: 00000000fffffff4 RBX: ffff88006fe8f900 RCX: 0000000000004118 Dec 15 16:48:34 puck kernel: [ 1798.744116] RDX: 0000000001000000 RSI: 0000000000016390 RDI: 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.746087] RBP: ffff88005715fd88 R08: 0000000000000000 R09: ffffffff8146f22e Dec 15 16:48:34 puck kernel: [ 1798.748018] R10: ffff88006e520ac0 R11: 0000000000000001 R12: ffff88005715fe28 Dec 15 16:48:34 puck kernel: [ 1798.749916] R13: ffff88005d31df00 R14: ffff88006fe8f900 R15: 00007f688c995cb8 Dec 15 16:48:34 puck kernel: [ 1798.751785] FS: 00007f68a366da40(0000) GS:ffff880100200000(0000) knlGS:0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.753659] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 Dec 15 16:48:34 puck kernel: [ 1798.755509] CR2: 0000000000000000 CR3: 00000000706bb000 CR4: 00000000000406f0 Dec 15 16:48:34 puck kernel: [ 1798.757334] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.759124] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Dec 15 16:48:34 puck kernel: [ 1798.760871] Process FlyCap2 (pid: 2713, threadinfo ffff88005715e000, task ffff88006c675b80) Dec 15 16:48:34 puck kernel: [ 1798.762605] Stack: Dec 15 16:48:34 puck kernel: [ 1798.764297] ffff88005715fe28 0000000000000000 ffff88005715fe08 ffffffff81479058 Dec 15 16:48:34 puck kernel: [ 1798.766020] 0000000000000000 ffffea0000004000 ffff880000004118 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.767750] ffff880000000001 ffff88006e520ac0 fffffff46fd81180 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.769472] Call Trace: Dec 15 16:48:34 puck kernel: [ 1798.771147] [<ffffffff81479058>] proc_do_submiturb+0x778/0xa00 Dec 15 16:48:34 puck kernel: [ 1798.772798] [<ffffffff8147a5fd>] usbdev_do_ioctl+0x24d/0x1200 Dec 15 16:48:34 puck kernel: [ 1798.774410] [<ffffffff8147b5de>] usbdev_ioctl+0xe/0x20 Dec 15 16:48:34 puck kernel: [ 1798.775975] [<ffffffff81189259>] do_vfs_ioctl+0x99/0x600 Dec 15 16:48:34 puck kernel: [ 1798.777534] [<ffffffff81189851>] sys_ioctl+0x91/0xa0 Dec 15 16:48:34 puck kernel: [ 1798.779088] [<ffffffff816247c2>] system_call_fastpath+0x16/0x1b ec 15 16:48:34 puck kernel: [ 1798.780634] Code: 51 ff ff ff e9 29 ff ff ff 0f 1f 40 00 55 48 89 e5 53 48 83 ec 08 66 66 66 66 90 48 89 fb 48 8b 7f 18 e8 a6 ea c0 ff 4 8 8b 7b 20 <f0> ff 0f 0f 94 c0 84 c0 74 05 e8 d3 99 c1 ff 48 8b 43 40 48 8b Dec 15 16:48:34 puck kernel: [ 1798.783970] RIP [<ffffffff8147841e>] free_async+0x1e/0x70 Dec 15 16:48:34 puck kernel: [ 1798.785630] RSP <ffff88005715fd78> Dec 15 16:48:34 puck kernel: [ 1798.787274] CR2: 0000000000000000 Dec 15 16:48:34 puck kernel: [ 1798.794728] ---[ end trace 52894d3355f88d19 ]--- markup_oops.pl says the oops is in put_cred: ffffffff81478401: 48 89 e5 mov %rsp,%rbp ffffffff81478404: 53 push %rbx ffffffff81478405: 48 83 ec 08 sub $0x8,%rsp ffffffff81478409: e8 f2 c0 1a 00 callq ffffffff81624500 <mcount> ffffffff8147840e: 48 89 fb mov %rdi,%rbx | %ebx => ffff88006fe8f900 put_pid(as->pid); ffffffff81478411: 48 8b 7f 18 mov 0x18(%rdi),%rdi ffffffff81478415: e8 a6 ea c0 ff callq ffffffff81086ec0 <put_pid> put_cred(as->cred); ffffffff8147841a: 48 8b 7b 20 mov 0x20(%rbx),%rdi | %edi => 0 %ebx = ffff88006fe8f900 */ static inline int atomic_dec_and_test(atomic_t *v) { unsigned char c; asm volatile(LOCK_PREFIX "decl %0; sete %1" *ffffffff8147841e: f0 ff 0f lock decl (%rdi) | %edi = 0 <--- faulting instruction ffffffff81478421: 0f 94 c0 sete %al static inline void put_cred(const struct cred *_cred) { struct cred *cred = (struct cred *) _cred; validate_creds(cred); if (atomic_dec_and_test(&(cred)->usage)) ffffffff81478424: 84 c0 test %al,%al ffffffff81478426: 74 05 je ffffffff8147842d <free_async+0x2d> __put_cred(cred); ffffffff81478428: e8 d3 99 c1 ff callq ffffffff81091e00 <__put_cred> kfree(as->urb->transfer_buffer); ffffffff8147842d: 48 8b 43 40 mov 0x40(%rbx),%rax ffffffff81478431: 48 8b 78 68 mov 0x68(%rax),%rdi ffffffff81478435: e8 a6 e1 ce ff callq ffffffff811665e0 <kfree> kfree(as->urb->setup_packet); ffffffff8147843a: 48 8b 43 40 mov 0x40(%rbx),%rax ffffffff8147843e: 48 8b b8 90 00 00 00 mov 0x90(%rax),%rdi ffffffff81478445: e8 96 e1 ce ff callq ffffffff811665e0 <kfree> usb_free_urb(as->urb); ffffffff8147844a: 48 8b 7b 40 mov 0x40(%rbx),%rdi ffffffff8147844e: e8 0d 6b ff ff callq ffffffff8146ef60 <usb_free_urb> This bug seems to have been introduced by commit d178bc3a708f39cbfefc3fab37032d3f2511b4ec "user namespace: usb: make usb urbs user namespace aware (v2)" I'm not sure if this is right fix, but it does stop the oops. Unfortunately, the Point Grey software still refuses to work, but it's a closed source app, so I can't fix it. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-17 02:26:30 +07:00
if (as->cred)
put_cred(as->cred);
for (i = 0; i < as->urb->num_sgs; i++) {
if (sg_page(&as->urb->sg[i]))
kfree(sg_virt(&as->urb->sg[i]));
}
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
kfree(as->urb->sg);
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
if (as->usbm == NULL)
kfree(as->urb->transfer_buffer);
else
dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
usbfs_decrease_memory_usage(as->mem_usage);
kfree(as);
}
static void async_newpending(struct async *as)
{
struct usb_dev_state *ps = as->ps;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
list_add_tail(&as->asynclist, &ps->async_pending);
spin_unlock_irqrestore(&ps->lock, flags);
}
static void async_removepending(struct async *as)
{
struct usb_dev_state *ps = as->ps;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
list_del_init(&as->asynclist);
spin_unlock_irqrestore(&ps->lock, flags);
}
static struct async *async_getcompleted(struct usb_dev_state *ps)
{
unsigned long flags;
struct async *as = NULL;
spin_lock_irqsave(&ps->lock, flags);
if (!list_empty(&ps->async_completed)) {
as = list_entry(ps->async_completed.next, struct async,
asynclist);
list_del_init(&as->asynclist);
}
spin_unlock_irqrestore(&ps->lock, flags);
return as;
}
static struct async *async_getpending(struct usb_dev_state *ps,
void __user *userurb)
{
struct async *as;
list_for_each_entry(as, &ps->async_pending, asynclist)
if (as->userurb == userurb) {
list_del_init(&as->asynclist);
return as;
}
return NULL;
}
static void snoop_urb(struct usb_device *udev,
void __user *userurb, int pipe, unsigned length,
int timeout_or_status, enum snoop_when when,
unsigned char *data, unsigned data_len)
{
static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
static const char *dirs[] = {"out", "in"};
int ep;
const char *t, *d;
if (!usbfs_snoop)
return;
ep = usb_pipeendpoint(pipe);
t = types[usb_pipetype(pipe)];
d = dirs[!!usb_pipein(pipe)];
if (userurb) { /* Async */
if (when == SUBMIT)
dev_info(&udev->dev, "userurb %pK, ep%d %s-%s, "
"length %u\n",
userurb, ep, t, d, length);
else
dev_info(&udev->dev, "userurb %pK, ep%d %s-%s, "
"actual_length %u status %d\n",
userurb, ep, t, d, length,
timeout_or_status);
} else {
if (when == SUBMIT)
dev_info(&udev->dev, "ep%d %s-%s, length %u, "
"timeout %d\n",
ep, t, d, length, timeout_or_status);
else
dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
"status %d\n",
ep, t, d, length, timeout_or_status);
}
data_len = min(data_len, usbfs_snoop_max);
if (data && data_len > 0) {
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
data, data_len, 1);
}
}
static void snoop_urb_data(struct urb *urb, unsigned len)
{
int i, size;
len = min(len, usbfs_snoop_max);
if (!usbfs_snoop || len == 0)
return;
if (urb->num_sgs == 0) {
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
urb->transfer_buffer, len, 1);
return;
}
for (i = 0; i < urb->num_sgs && len; i++) {
size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
sg_virt(&urb->sg[i]), size, 1);
len -= size;
}
}
static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
{
unsigned i, len, size;
if (urb->number_of_packets > 0) /* Isochronous */
len = urb->transfer_buffer_length;
else /* Non-Isoc */
len = urb->actual_length;
if (urb->num_sgs == 0) {
if (copy_to_user(userbuffer, urb->transfer_buffer, len))
return -EFAULT;
return 0;
}
for (i = 0; i < urb->num_sgs && len; i++) {
size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
return -EFAULT;
userbuffer += size;
len -= size;
}
return 0;
}
#define AS_CONTINUATION 1
#define AS_UNLINK 2
static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)
__releases(ps->lock)
__acquires(ps->lock)
{
struct urb *urb;
struct async *as;
/* Mark all the pending URBs that match bulk_addr, up to but not
* including the first one without AS_CONTINUATION. If such an
* URB is encountered then a new transfer has already started so
* the endpoint doesn't need to be disabled; otherwise it does.
*/
list_for_each_entry(as, &ps->async_pending, asynclist) {
if (as->bulk_addr == bulk_addr) {
if (as->bulk_status != AS_CONTINUATION)
goto rescan;
as->bulk_status = AS_UNLINK;
as->bulk_addr = 0;
}
}
ps->disabled_bulk_eps |= (1 << bulk_addr);
/* Now carefully unlink all the marked pending URBs */
rescan:
list_for_each_entry(as, &ps->async_pending, asynclist) {
if (as->bulk_status == AS_UNLINK) {
as->bulk_status = 0; /* Only once */
urb = as->urb;
usb_get_urb(urb);
spin_unlock(&ps->lock); /* Allow completions */
usb_unlink_urb(urb);
usb_put_urb(urb);
spin_lock(&ps->lock);
goto rescan;
}
}
}
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
static void async_completed(struct urb *urb)
{
struct async *as = urb->context;
struct usb_dev_state *ps = as->ps;
struct pid *pid = NULL;
const struct cred *cred = NULL;
unsigned long flags;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
sigval_t addr;
int signr, errno;
spin_lock_irqsave(&ps->lock, flags);
list_move_tail(&as->asynclist, &ps->async_completed);
as->status = urb->status;
signr = as->signr;
if (signr) {
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
errno = as->status;
addr = as->userurb_sigval;
pid = get_pid(as->pid);
cred = get_cred(as->cred);
}
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
as->status, COMPLETE, NULL, 0);
if (usb_urb_dir_in(urb))
snoop_urb_data(urb, urb->actual_length);
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
as->status != -ENOENT)
cancel_bulk_urbs(ps, as->bulk_addr);
USB: core: Avoid race of async_completed() w/ usbdev_release() While running reboot tests w/ a specific set of USB devices (and slub_debug enabled), I found that once every few hours my device would be crashed with a stack that looked like this: [ 14.012445] BUG: spinlock bad magic on CPU#0, modprobe/2091 [ 14.012460] lock: 0xffffffc0cb055978, .magic: ffffffc0, .owner: cryption contexts: %lu/%lu [ 14.012460] /1025536097, .owner_cpu: 0 [ 14.012466] CPU: 0 PID: 2091 Comm: modprobe Not tainted 4.4.79 #352 [ 14.012468] Hardware name: Google Kevin (DT) [ 14.012471] Call trace: [ 14.012483] [<....>] dump_backtrace+0x0/0x160 [ 14.012487] [<....>] show_stack+0x20/0x28 [ 14.012494] [<....>] dump_stack+0xb4/0xf0 [ 14.012500] [<....>] spin_dump+0x8c/0x98 [ 14.012504] [<....>] spin_bug+0x30/0x3c [ 14.012508] [<....>] do_raw_spin_lock+0x40/0x164 [ 14.012515] [<....>] _raw_spin_lock_irqsave+0x64/0x74 [ 14.012521] [<....>] __wake_up+0x2c/0x60 [ 14.012528] [<....>] async_completed+0x2d0/0x300 [ 14.012534] [<....>] __usb_hcd_giveback_urb+0xc4/0x138 [ 14.012538] [<....>] usb_hcd_giveback_urb+0x54/0xf0 [ 14.012544] [<....>] xhci_irq+0x1314/0x1348 [ 14.012548] [<....>] usb_hcd_irq+0x40/0x50 [ 14.012553] [<....>] handle_irq_event_percpu+0x1b4/0x3f0 [ 14.012556] [<....>] handle_irq_event+0x4c/0x7c [ 14.012561] [<....>] handle_fasteoi_irq+0x158/0x1c8 [ 14.012564] [<....>] generic_handle_irq+0x30/0x44 [ 14.012568] [<....>] __handle_domain_irq+0x90/0xbc [ 14.012572] [<....>] gic_handle_irq+0xcc/0x18c Investigation using kgdb() found that the wait queue that was passed into wake_up() had been freed (it was filled with slub_debug poison). I analyzed and instrumented the code and reproduced. My current belief is that this is happening: 1. async_completed() is called (from IRQ). Moves "as" onto the completed list. 2. On another CPU, proc_reapurbnonblock_compat() calls async_getcompleted(). Blocks on spinlock. 3. async_completed() releases the lock; keeps running; gets blocked midway through wake_up(). 4. proc_reapurbnonblock_compat() => async_getcompleted() gets the lock; removes "as" from completed list and frees it. 5. usbdev_release() is called. Frees "ps". 6. async_completed() finally continues running wake_up(). ...but wake_up() has a pointer to the freed "ps". The instrumentation that led me to believe this was based on adding some trace_printk() calls in a select few functions and then using kdb's "ftdump" at crash time. The trace follows (NOTE: in the trace below I cheated a little bit and added a udelay(1000) in async_completed() after releasing the spinlock because I wanted it to trigger quicker): <...>-2104 0d.h2 13759034us!: async_completed at start: as=ffffffc0cc638200 mtpd-2055 3.... 13759356us : async_getcompleted before spin_lock_irqsave mtpd-2055 3d..1 13759362us : async_getcompleted after list_del_init: as=ffffffc0cc638200 mtpd-2055 3.... 13759371us+: proc_reapurbnonblock_compat: free_async(ffffffc0cc638200) mtpd-2055 3.... 13759422us+: async_getcompleted before spin_lock_irqsave mtpd-2055 3.... 13759479us : usbdev_release at start: ps=ffffffc0cc042080 mtpd-2055 3.... 13759487us : async_getcompleted before spin_lock_irqsave mtpd-2055 3.... 13759497us!: usbdev_release after kfree(ps): ps=ffffffc0cc042080 <...>-2104 0d.h2 13760294us : async_completed before wake_up(): as=ffffffc0cc638200 To fix this problem we can just move the wake_up() under the ps->lock. There should be no issues there that I'm aware of. Signed-off-by: Douglas Anderson <dianders@chromium.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-08-11 05:42:22 +07:00
wake_up(&ps->wait);
spin_unlock_irqrestore(&ps->lock, flags);
if (signr) {
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
kill_pid_usb_asyncio(signr, errno, addr, pid, cred);
put_pid(pid);
put_cred(cred);
}
}
static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
{
struct urb *urb;
struct async *as;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
list_del_init(&as->asynclist);
urb = as->urb;
usb_get_urb(urb);
/* drop the spinlock so the completion handler can run */
spin_unlock_irqrestore(&ps->lock, flags);
usb_kill_urb(urb);
usb_put_urb(urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
}
static void destroy_async_on_interface(struct usb_dev_state *ps,
unsigned int ifnum)
{
struct list_head *p, *q, hitlist;
unsigned long flags;
INIT_LIST_HEAD(&hitlist);
spin_lock_irqsave(&ps->lock, flags);
list_for_each_safe(p, q, &ps->async_pending)
if (ifnum == list_entry(p, struct async, asynclist)->ifnum)
list_move_tail(p, &hitlist);
spin_unlock_irqrestore(&ps->lock, flags);
destroy_async(ps, &hitlist);
}
static void destroy_all_async(struct usb_dev_state *ps)
{
destroy_async(ps, &ps->async_pending);
}
/*
* interface claims are made only at the request of user level code,
* which can also release them (explicitly or by closing files).
* they're also undone when devices disconnect.
*/
static int driver_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return -ENODEV;
}
static void driver_disconnect(struct usb_interface *intf)
{
struct usb_dev_state *ps = usb_get_intfdata(intf);
unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
if (!ps)
return;
/* NOTE: this relies on usbcore having canceled and completed
* all pending I/O requests; 2.6 does that.
*/
if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
clear_bit(ifnum, &ps->ifclaimed);
else
dev_warn(&intf->dev, "interface number %u out of range\n",
ifnum);
usb_set_intfdata(intf, NULL);
/* force async requests to complete */
destroy_async_on_interface(ps, ifnum);
}
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
/* We don't care about suspend/resume of claimed interfaces */
static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
{
return 0;
}
static int driver_resume(struct usb_interface *intf)
{
return 0;
}
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
/* The following routines apply to the entire device, not interfaces */
void usbfs_notify_suspend(struct usb_device *udev)
{
/* We don't need to handle this */
}
void usbfs_notify_resume(struct usb_device *udev)
{
struct usb_dev_state *ps;
/* Protect against simultaneous remove or release */
mutex_lock(&usbfs_mutex);
list_for_each_entry(ps, &udev->filelist, list) {
WRITE_ONCE(ps->not_yet_resumed, 0);
wake_up_all(&ps->wait_for_resume);
}
mutex_unlock(&usbfs_mutex);
}
struct usb_driver usbfs_driver = {
.name = "usbfs",
.probe = driver_probe,
.disconnect = driver_disconnect,
.suspend = driver_suspend,
.resume = driver_resume,
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
.supports_autosuspend = 1,
};
static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
{
struct usb_device *dev = ps->dev;
struct usb_interface *intf;
int err;
if (ifnum >= 8*sizeof(ps->ifclaimed))
return -EINVAL;
/* already claimed */
if (test_bit(ifnum, &ps->ifclaimed))
return 0;
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>
2016-02-22 04:38:01 +07:00
if (ps->privileges_dropped &&
!test_bit(ifnum, &ps->interface_allowed_mask))
return -EACCES;
intf = usb_ifnum_to_if(dev, ifnum);
if (!intf)
err = -ENOENT;
else
err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
if (err == 0)
set_bit(ifnum, &ps->ifclaimed);
return err;
}
static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
{
struct usb_device *dev;
struct usb_interface *intf;
int err;
err = -EINVAL;
if (ifnum >= 8*sizeof(ps->ifclaimed))
return err;
dev = ps->dev;
intf = usb_ifnum_to_if(dev, ifnum);
if (!intf)
err = -ENOENT;
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
usb_driver_release_interface(&usbfs_driver, intf);
err = 0;
}
return err;
}
static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)
{
if (ps->dev->state != USB_STATE_CONFIGURED)
return -EHOSTUNREACH;
if (ifnum >= 8*sizeof(ps->ifclaimed))
return -EINVAL;
if (test_bit(ifnum, &ps->ifclaimed))
return 0;
/* if not yet claimed, claim it for the driver */
dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
"interface %u before use\n", task_pid_nr(current),
current->comm, ifnum);
return claimintf(ps, ifnum);
}
static int findintfep(struct usb_device *dev, unsigned int ep)
{
unsigned int i, j, e;
struct usb_interface *intf;
struct usb_host_interface *alts;
struct usb_endpoint_descriptor *endpt;
if (ep & ~(USB_DIR_IN|0xf))
return -EINVAL;
if (!dev->actconfig)
return -ESRCH;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
intf = dev->actconfig->interface[i];
for (j = 0; j < intf->num_altsetting; j++) {
alts = &intf->altsetting[j];
for (e = 0; e < alts->desc.bNumEndpoints; e++) {
endpt = &alts->endpoint[e].desc;
if (endpt->bEndpointAddress == ep)
return alts->desc.bInterfaceNumber;
}
}
}
return -ENOENT;
}
static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,
unsigned int request, unsigned int index)
{
int ret = 0;
struct usb_host_interface *alt_setting;
if (ps->dev->state != USB_STATE_UNAUTHENTICATED
&& ps->dev->state != USB_STATE_ADDRESS
&& ps->dev->state != USB_STATE_CONFIGURED)
return -EHOSTUNREACH;
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0;
/*
* check for the special corner case 'get_device_id' in the printer
* class specification, which we always want to allow as it is used
* to query things like ink level, etc.
*/
if (requesttype == 0xa1 && request == 0) {
alt_setting = usb_find_alt_setting(ps->dev->actconfig,
index >> 8, index & 0xff);
if (alt_setting
&& alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
return 0;
}
index &= 0xff;
switch (requesttype & USB_RECIP_MASK) {
case USB_RECIP_ENDPOINT:
if ((index & ~USB_DIR_IN) == 0)
return 0;
ret = findintfep(ps->dev, index);
usb/core/devio.c: Don't reject control message to endpoint with wrong direction bit Trying to read data from the Pegasus Technologies NoteTaker (0e20:0101) [1] with the Windows App (EasyNote) works natively but fails when Windows is running under KVM (and the USB device handed to KVM). The reason is a USB control message usb 4-2.2: control urb: bRequestType=22 bRequest=09 wValue=0200 wIndex=0001 wLength=0008 This goes to endpoint address 0x01 (wIndex); however, endpoint address 0x01 does not exist. There is an endpoint 0x81 though (same number, but other direction); the app may have meant that endpoint instead. The kernel thus rejects the IO and thus we see the failure. Apparently, Linux is more strict here than Windows ... we can't change the Win app easily, so that's a problem. It seems that the Win app/driver is buggy here and the driver does not behave fully according to the USB HID class spec that it claims to belong to. The device seems to happily deal with that though (and seems to not really care about this value much). So the question is whether the Linux kernel should filter here. Rejecting has the risk that somewhat non-compliant userspace apps/ drivers (most likely in a virtual machine) are prevented from working. Not rejecting has the risk of confusing an overly sensitive device with such a transfer. Given the fact that Windows does not filter it makes this risk rather small though. The patch makes the kernel more tolerant: If the endpoint address in wIndex does not exist, but an endpoint with toggled direction bit does, it will let the transfer through. (It does NOT change the message.) With attached patch, the app in Windows in KVM works. usb 4-2.2: check_ctrlrecip: process 13073 (qemu-kvm) requesting ep 01 but needs 81 I suspect this will mostly affect apps in virtual environments; as on Linux the apps would have been adapted to the stricter handling of the kernel. I have done that for mine[2]. [1] http://www.pegatech.com/ [2] https://sourceforge.net/projects/notetakerpen/ Signed-off-by: Kurt Garloff <kurt@garloff.de> Acked-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-24 19:13:48 +07:00
if (ret < 0) {
/*
* Some not fully compliant Win apps seem to get
* index wrong and have the endpoint number here
* rather than the endpoint address (with the
* correct direction). Win does let this through,
* so we'll not reject it here but leave it to
* the device to not break KVM. But we warn.
*/
ret = findintfep(ps->dev, index ^ 0x80);
if (ret >= 0)
dev_info(&ps->dev->dev,
"%s: process %i (%s) requesting ep %02x but needs %02x\n",
__func__, task_pid_nr(current),
current->comm, index, index ^ 0x80);
}
if (ret >= 0)
ret = checkintf(ps, ret);
break;
case USB_RECIP_INTERFACE:
ret = checkintf(ps, index);
break;
}
return ret;
}
static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev,
unsigned char ep)
{
if (ep & USB_ENDPOINT_DIR_MASK)
return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK];
else
return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK];
}
USB patches for 3.15-rc1 Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlM7AbcACgkQMUfUDdst+ymbZACgncdbZyPsVZ7ZUpBFNbO/vBVT T9UAmwciojEzjh7b+x4ylsWH+O3LWVN3 =RpAF -----END PGP SIGNATURE----- Merge tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB patches from Greg KH: "Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while" * tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (249 commits) xhci: Transition maintainership to Mathias Nyman. USB: disable reset-resume when USB_QUIRK_RESET is set USB: unbind all interfaces before rebinding any usb: phy: Add ulpi IDs for SMSC USB3320 and TI TUSB1210 usb: gadget: tcm_usb_gadget: stop format strings usb: gadget: f_fs: add missing spinlock and mutex unlock usb: gadget: composite: switch over to ERR_CAST() usb: gadget: inode: switch over to memdup_user() usb: gadget: f_subset: switch over to PTR_RET usb: gadget: lpc32xx_udc: fix wrong clk_put() sequence USB: keyspan: remove dead debugging code USB: serial: add missing newlines to dev_<level> messages. USB: serial: add missing braces USB: serial: continue to write on errors USB: serial: continue to read on errors USB: serial: make bulk_out_size a lower limit USB: cypress_m8: fix potential scheduling while atomic devicetree: bindings: document lsi,zevio-usb usb: chipidea: add support for USB OTG controller on LSI Zevio SoCs usb: chipidea: imx: Use dev_name() for ci_hdrc name to distinguish USBs ...
2014-04-02 07:06:09 +07:00
static int parse_usbdevfs_streams(struct usb_dev_state *ps,
struct usbdevfs_streams __user *streams,
unsigned int *num_streams_ret,
unsigned int *num_eps_ret,
struct usb_host_endpoint ***eps_ret,
struct usb_interface **intf_ret)
{
unsigned int i, num_streams, num_eps;
struct usb_host_endpoint **eps;
struct usb_interface *intf = NULL;
unsigned char ep;
int ifnum, ret;
if (get_user(num_streams, &streams->num_streams) ||
get_user(num_eps, &streams->num_eps))
return -EFAULT;
if (num_eps < 1 || num_eps > USB_MAXENDPOINTS)
return -EINVAL;
/* The XHCI controller allows max 2 ^ 16 streams */
if (num_streams_ret && (num_streams < 2 || num_streams > 65536))
return -EINVAL;
treewide: kmalloc() -> kmalloc_array() The kmalloc() function has a 2-factor argument form, kmalloc_array(). This patch replaces cases of: kmalloc(a * b, gfp) with: kmalloc_array(a * b, gfp) as well as handling cases of: kmalloc(a * b * c, gfp) with: kmalloc(array3_size(a, b, c), gfp) as it's slightly less ugly than: kmalloc_array(array_size(a, b), c, gfp) This does, however, attempt to ignore constant size factors like: kmalloc(4 * 1024, gfp) though any constants defined via macros get caught up in the conversion. Any factors with a sizeof() of "unsigned char", "char", and "u8" were dropped, since they're redundant. The tools/ directory was manually excluded, since it has its own implementation of kmalloc(). The Coccinelle script used for this was: // Fix redundant parens around sizeof(). @@ type TYPE; expression THING, E; @@ ( kmalloc( - (sizeof(TYPE)) * E + sizeof(TYPE) * E , ...) | kmalloc( - (sizeof(THING)) * E + sizeof(THING) * E , ...) ) // Drop single-byte sizes and redundant parens. @@ expression COUNT; typedef u8; typedef __u8; @@ ( kmalloc( - sizeof(u8) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(__u8) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(char) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(unsigned char) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(u8) * COUNT + COUNT , ...) | kmalloc( - sizeof(__u8) * COUNT + COUNT , ...) | kmalloc( - sizeof(char) * COUNT + COUNT , ...) | kmalloc( - sizeof(unsigned char) * COUNT + COUNT , ...) ) // 2-factor product with sizeof(type/expression) and identifier or constant. @@ type TYPE; expression THING; identifier COUNT_ID; constant COUNT_CONST; @@ ( - kmalloc + kmalloc_array ( - sizeof(TYPE) * (COUNT_ID) + COUNT_ID, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * COUNT_ID + COUNT_ID, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * (COUNT_CONST) + COUNT_CONST, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * COUNT_CONST + COUNT_CONST, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * (COUNT_ID) + COUNT_ID, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * COUNT_ID + COUNT_ID, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * (COUNT_CONST) + COUNT_CONST, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * COUNT_CONST + COUNT_CONST, sizeof(THING) , ...) ) // 2-factor product, only identifiers. @@ identifier SIZE, COUNT; @@ - kmalloc + kmalloc_array ( - SIZE * COUNT + COUNT, SIZE , ...) // 3-factor product with 1 sizeof(type) or sizeof(expression), with // redundant parens removed. @@ expression THING; identifier STRIDE, COUNT; type TYPE; @@ ( kmalloc( - sizeof(TYPE) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(TYPE) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(TYPE) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(TYPE) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(THING) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kmalloc( - sizeof(THING) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kmalloc( - sizeof(THING) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kmalloc( - sizeof(THING) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) ) // 3-factor product with 2 sizeof(variable), with redundant parens removed. @@ expression THING1, THING2; identifier COUNT; type TYPE1, TYPE2; @@ ( kmalloc( - sizeof(TYPE1) * sizeof(TYPE2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kmalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kmalloc( - sizeof(THING1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kmalloc( - sizeof(THING1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kmalloc( - sizeof(TYPE1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) | kmalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) ) // 3-factor product, only identifiers, with redundant parens removed. @@ identifier STRIDE, SIZE, COUNT; @@ ( kmalloc( - (COUNT) * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - (COUNT) * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - (COUNT) * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - (COUNT) * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) ) // Any remaining multi-factor products, first at least 3-factor products, // when they're not all constants... @@ expression E1, E2, E3; constant C1, C2, C3; @@ ( kmalloc(C1 * C2 * C3, ...) | kmalloc( - (E1) * E2 * E3 + array3_size(E1, E2, E3) , ...) | kmalloc( - (E1) * (E2) * E3 + array3_size(E1, E2, E3) , ...) | kmalloc( - (E1) * (E2) * (E3) + array3_size(E1, E2, E3) , ...) | kmalloc( - E1 * E2 * E3 + array3_size(E1, E2, E3) , ...) ) // And then all remaining 2 factors products when they're not all constants, // keeping sizeof() as the second factor argument. @@ expression THING, E1, E2; type TYPE; constant C1, C2, C3; @@ ( kmalloc(sizeof(THING) * C2, ...) | kmalloc(sizeof(TYPE) * C2, ...) | kmalloc(C1 * C2 * C3, ...) | kmalloc(C1 * C2, ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * (E2) + E2, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * E2 + E2, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * (E2) + E2, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * E2 + E2, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - (E1) * E2 + E1, E2 , ...) | - kmalloc + kmalloc_array ( - (E1) * (E2) + E1, E2 , ...) | - kmalloc + kmalloc_array ( - E1 * E2 + E1, E2 , ...) ) Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 03:55:00 +07:00
eps = kmalloc_array(num_eps, sizeof(*eps), GFP_KERNEL);
if (!eps)
return -ENOMEM;
for (i = 0; i < num_eps; i++) {
if (get_user(ep, &streams->eps[i])) {
ret = -EFAULT;
goto error;
}
eps[i] = ep_to_host_endpoint(ps->dev, ep);
if (!eps[i]) {
ret = -EINVAL;
goto error;
}
/* usb_alloc/free_streams operate on an usb_interface */
ifnum = findintfep(ps->dev, ep);
if (ifnum < 0) {
ret = ifnum;
goto error;
}
if (i == 0) {
ret = checkintf(ps, ifnum);
if (ret < 0)
goto error;
intf = usb_ifnum_to_if(ps->dev, ifnum);
} else {
/* Verify all eps belong to the same interface */
if (ifnum != intf->altsetting->desc.bInterfaceNumber) {
ret = -EINVAL;
goto error;
}
}
}
if (num_streams_ret)
*num_streams_ret = num_streams;
*num_eps_ret = num_eps;
*eps_ret = eps;
*intf_ret = intf;
return 0;
error:
kfree(eps);
return ret;
}
static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
{
struct device *dev;
dev = bus_find_device_by_devt(&usb_bus_type, devt);
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
if (!dev)
return NULL;
return to_usb_device(dev);
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
}
/*
* file operations
*/
static int usbdev_open(struct inode *inode, struct file *file)
{
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
struct usb_device *dev = NULL;
struct usb_dev_state *ps;
int ret;
ret = -ENOMEM;
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>
2016-02-22 04:38:01 +07:00
ps = kzalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
if (!ps)
goto out_free_ps;
ret = -ENODEV;
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
/* usbdev device-node */
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
if (!dev)
goto out_free_ps;
usb_lock_device(dev);
if (dev->state == USB_STATE_NOTATTACHED)
goto out_unlock_device;
ret = usb_autoresume_device(dev);
if (ret)
goto out_unlock_device;
ps->dev = dev;
ps->file = file;
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>
2016-02-22 04:38:01 +07:00
ps->interface_allowed_mask = 0xFFFFFFFF; /* 32 bits */
spin_lock_init(&ps->lock);
INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
INIT_LIST_HEAD(&ps->memory_list);
init_waitqueue_head(&ps->wait);
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
init_waitqueue_head(&ps->wait_for_resume);
ps->disc_pid = get_pid(task_pid(current));
ps->cred = get_current_cred();
smp_wmb();
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
/* Can't race with resume; the device is already active */
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
usb_unlock_device(dev);
snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
current->comm);
return ret;
out_unlock_device:
usb_unlock_device(dev);
usb_put_dev(dev);
out_free_ps:
kfree(ps);
usbfs: private mutex for open, release, and remove The usbfs code doesn't provide sufficient mutual exclusion among open, release, and remove. Release vs. remove is okay because they both acquire the device lock, but open is not exclusive with either one. All three routines modify the udev->filelist linked list, so they must not run concurrently. Apparently someone gave this a minimum amount of thought in the past by explicitly acquiring the BKL at the start of the usbdev_open routine. Oddly enough, there's a comment pointing out that locking is unnecessary because chrdev_open already has acquired the BKL. But this ignores the point that the files in /proc/bus/usb/* are not char device files; they are regular files and so they don't get any special locking. Furthermore it's necessary to acquire the same lock in the release and remove routines, which the code does not do. Yet another problem arises because the same file_operations structure is accessible through both the /proc/bus/usb/* and /dev/usb/usbdev* file nodes. Even when one of them has been removed, it's still possible for userspace to open the other. So simple locking around the individual remove routines is insufficient; we need to lock the entire usb_notify_remove_device notifier chain. Rather than rely on the BKL, this patch (as723) introduces a new private mutex for the purpose. Holding the BKL while invoking a notifier chain doesn't seem like a good idea. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-07-02 09:05:01 +07:00
return ret;
}
static int usbdev_release(struct inode *inode, struct file *file)
{
struct usb_dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
unsigned int ifnum;
struct async *as;
usb_lock_device(dev);
usb_hub_release_all_ports(dev, ps);
usbfs: private mutex for open, release, and remove The usbfs code doesn't provide sufficient mutual exclusion among open, release, and remove. Release vs. remove is okay because they both acquire the device lock, but open is not exclusive with either one. All three routines modify the udev->filelist linked list, so they must not run concurrently. Apparently someone gave this a minimum amount of thought in the past by explicitly acquiring the BKL at the start of the usbdev_open routine. Oddly enough, there's a comment pointing out that locking is unnecessary because chrdev_open already has acquired the BKL. But this ignores the point that the files in /proc/bus/usb/* are not char device files; they are regular files and so they don't get any special locking. Furthermore it's necessary to acquire the same lock in the release and remove routines, which the code does not do. Yet another problem arises because the same file_operations structure is accessible through both the /proc/bus/usb/* and /dev/usb/usbdev* file nodes. Even when one of them has been removed, it's still possible for userspace to open the other. So simple locking around the individual remove routines is insufficient; we need to lock the entire usb_notify_remove_device notifier chain. Rather than rely on the BKL, this patch (as723) introduces a new private mutex for the purpose. Holding the BKL while invoking a notifier chain doesn't seem like a good idea. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-07-02 09:05:01 +07:00
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
/* Protect against simultaneous resume */
mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
mutex_unlock(&usbfs_mutex);
usbfs: private mutex for open, release, and remove The usbfs code doesn't provide sufficient mutual exclusion among open, release, and remove. Release vs. remove is okay because they both acquire the device lock, but open is not exclusive with either one. All three routines modify the udev->filelist linked list, so they must not run concurrently. Apparently someone gave this a minimum amount of thought in the past by explicitly acquiring the BKL at the start of the usbdev_open routine. Oddly enough, there's a comment pointing out that locking is unnecessary because chrdev_open already has acquired the BKL. But this ignores the point that the files in /proc/bus/usb/* are not char device files; they are regular files and so they don't get any special locking. Furthermore it's necessary to acquire the same lock in the release and remove routines, which the code does not do. Yet another problem arises because the same file_operations structure is accessible through both the /proc/bus/usb/* and /dev/usb/usbdev* file nodes. Even when one of them has been removed, it's still possible for userspace to open the other. So simple locking around the individual remove routines is insufficient; we need to lock the entire usb_notify_remove_device notifier chain. Rather than rely on the BKL, this patch (as723) introduces a new private mutex for the purpose. Holding the BKL while invoking a notifier chain doesn't seem like a good idea. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-07-02 09:05:01 +07:00
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
}
destroy_all_async(ps);
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
if (!ps->suspend_allowed)
usb_autosuspend_device(dev);
usb_unlock_device(dev);
usb_put_dev(dev);
put_pid(ps->disc_pid);
put_cred(ps->cred);
as = async_getcompleted(ps);
while (as) {
free_async(as);
as = async_getcompleted(ps);
}
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
kfree(ps);
usbfs: private mutex for open, release, and remove The usbfs code doesn't provide sufficient mutual exclusion among open, release, and remove. Release vs. remove is okay because they both acquire the device lock, but open is not exclusive with either one. All three routines modify the udev->filelist linked list, so they must not run concurrently. Apparently someone gave this a minimum amount of thought in the past by explicitly acquiring the BKL at the start of the usbdev_open routine. Oddly enough, there's a comment pointing out that locking is unnecessary because chrdev_open already has acquired the BKL. But this ignores the point that the files in /proc/bus/usb/* are not char device files; they are regular files and so they don't get any special locking. Furthermore it's necessary to acquire the same lock in the release and remove routines, which the code does not do. Yet another problem arises because the same file_operations structure is accessible through both the /proc/bus/usb/* and /dev/usb/usbdev* file nodes. Even when one of them has been removed, it's still possible for userspace to open the other. So simple locking around the individual remove routines is insufficient; we need to lock the entire usb_notify_remove_device notifier chain. Rather than rely on the BKL, this patch (as723) introduces a new private mutex for the purpose. Holding the BKL while invoking a notifier chain doesn't seem like a good idea. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-07-02 09:05:01 +07:00
return 0;
}
static int proc_control(struct usb_dev_state *ps, void __user *arg)
{
struct usb_device *dev = ps->dev;
struct usbdevfs_ctrltransfer ctrl;
unsigned int tmo;
unsigned char *tbuf;
unsigned wLength;
int i, pipe, ret;
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
ctrl.wIndex);
if (ret)
return ret;
wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
if (wLength > PAGE_SIZE)
return -EINVAL;
ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
sizeof(struct usb_ctrlrequest));
if (ret)
return ret;
tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!tbuf) {
ret = -ENOMEM;
goto done;
}
tmo = ctrl.timeout;
snoop(&dev->dev, "control urb: bRequestType=%02x "
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
ctrl.bRequestType, ctrl.bRequest, ctrl.wValue,
ctrl.wIndex, ctrl.wLength);
if (ctrl.bRequestType & 0x80) {
Remove 'type' argument from access_ok() function Nobody has actually used the type (VERIFY_READ vs VERIFY_WRITE) argument of the user address range verification function since we got rid of the old racy i386-only code to walk page tables by hand. It existed because the original 80386 would not honor the write protect bit when in kernel mode, so you had to do COW by hand before doing any user access. But we haven't supported that in a long time, and these days the 'type' argument is a purely historical artifact. A discussion about extending 'user_access_begin()' to do the range checking resulted this patch, because there is no way we're going to move the old VERIFY_xyz interface to that model. And it's best done at the end of the merge window when I've done most of my merges, so let's just get this done once and for all. This patch was mostly done with a sed-script, with manual fix-ups for the cases that weren't of the trivial 'access_ok(VERIFY_xyz' form. There were a couple of notable cases: - csky still had the old "verify_area()" name as an alias. - the iter_iov code had magical hardcoded knowledge of the actual values of VERIFY_{READ,WRITE} (not that they mattered, since nothing really used it) - microblaze used the type argument for a debug printout but other than those oddities this should be a total no-op patch. I tried to fix up all architectures, did fairly extensive grepping for access_ok() uses, and the changes are trivial, but I may have missed something. Any missed conversion should be trivially fixable, though. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-01-04 09:57:57 +07:00
if (ctrl.wLength && !access_ok(ctrl.data,
ctrl.wLength)) {
ret = -EINVAL;
goto done;
}
pipe = usb_rcvctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
usb_unlock_device(dev);
i = usb_control_msg(dev, pipe, ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
tbuf, max(i, 0));
if ((i > 0) && ctrl.wLength) {
if (copy_to_user(ctrl.data, tbuf, i)) {
ret = -EFAULT;
goto done;
}
}
} else {
if (ctrl.wLength) {
if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
ret = -EFAULT;
goto done;
}
}
pipe = usb_sndctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT,
tbuf, ctrl.wLength);
usb_unlock_device(dev);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
}
if (i < 0 && i != -EPIPE) {
dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
"failed cmd %s rqt %u rq %u len %u ret %d\n",
current->comm, ctrl.bRequestType, ctrl.bRequest,
ctrl.wLength, i);
}
ret = i;
done:
free_page((unsigned long) tbuf);
usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
sizeof(struct usb_ctrlrequest));
return ret;
}
static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
{
struct usb_device *dev = ps->dev;
struct usbdevfs_bulktransfer bulk;
unsigned int tmo, len1, pipe;
int len2;
unsigned char *tbuf;
int i, ret;
if (copy_from_user(&bulk, arg, sizeof(bulk)))
return -EFAULT;
ret = findintfep(ps->dev, bulk.ep);
if (ret < 0)
return ret;
ret = checkintf(ps, ret);
if (ret)
return ret;
if (bulk.ep & USB_DIR_IN)
pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
else
pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
return -EINVAL;
len1 = bulk.len;
if (len1 >= (INT_MAX - sizeof(struct urb)))
return -EINVAL;
ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
if (ret)
return ret;
tbuf = kmalloc(len1, GFP_KERNEL);
if (!tbuf) {
ret = -ENOMEM;
goto done;
}
tmo = bulk.timeout;
if (bulk.ep & 0x80) {
Remove 'type' argument from access_ok() function Nobody has actually used the type (VERIFY_READ vs VERIFY_WRITE) argument of the user address range verification function since we got rid of the old racy i386-only code to walk page tables by hand. It existed because the original 80386 would not honor the write protect bit when in kernel mode, so you had to do COW by hand before doing any user access. But we haven't supported that in a long time, and these days the 'type' argument is a purely historical artifact. A discussion about extending 'user_access_begin()' to do the range checking resulted this patch, because there is no way we're going to move the old VERIFY_xyz interface to that model. And it's best done at the end of the merge window when I've done most of my merges, so let's just get this done once and for all. This patch was mostly done with a sed-script, with manual fix-ups for the cases that weren't of the trivial 'access_ok(VERIFY_xyz' form. There were a couple of notable cases: - csky still had the old "verify_area()" name as an alias. - the iter_iov code had magical hardcoded knowledge of the actual values of VERIFY_{READ,WRITE} (not that they mattered, since nothing really used it) - microblaze used the type argument for a debug printout but other than those oddities this should be a total no-op patch. I tried to fix up all architectures, did fairly extensive grepping for access_ok() uses, and the changes are trivial, but I may have missed something. Any missed conversion should be trivially fixable, though. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-01-04 09:57:57 +07:00
if (len1 && !access_ok(bulk.data, len1)) {
ret = -EINVAL;
goto done;
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
ret = -EFAULT;
goto done;
}
}
} else {
if (len1) {
if (copy_from_user(tbuf, bulk.data, len1)) {
ret = -EFAULT;
goto done;
}
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
}
ret = (i < 0 ? i : len2);
done:
kfree(tbuf);
usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
return ret;
}
static void check_reset_of_active_ep(struct usb_device *udev,
unsigned int epnum, char *ioctl_name)
{
struct usb_host_endpoint **eps;
struct usb_host_endpoint *ep;
eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out;
ep = eps[epnum & 0x0f];
if (ep && !list_empty(&ep->urb_list))
dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n",
task_pid_nr(current), current->comm,
ioctl_name, epnum);
}
static int proc_resetep(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ep;
int ret;
if (get_user(ep, (unsigned int __user *)arg))
return -EFAULT;
ret = findintfep(ps->dev, ep);
if (ret < 0)
return ret;
ret = checkintf(ps, ret);
if (ret)
return ret;
check_reset_of_active_ep(ps->dev, ep, "RESETEP");
usb_reset_endpoint(ps->dev, ep);
return 0;
}
static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ep;
int pipe;
int ret;
if (get_user(ep, (unsigned int __user *)arg))
return -EFAULT;
ret = findintfep(ps->dev, ep);
if (ret < 0)
return ret;
ret = checkintf(ps, ret);
if (ret)
return ret;
check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");
if (ep & USB_DIR_IN)
pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
else
pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
return usb_clear_halt(ps->dev, pipe);
}
static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_getdriver gd;
struct usb_interface *intf;
int ret;
if (copy_from_user(&gd, arg, sizeof(gd)))
return -EFAULT;
intf = usb_ifnum_to_if(ps->dev, gd.interface);
if (!intf || !intf->dev.driver)
ret = -ENODATA;
else {
strlcpy(gd.driver, intf->dev.driver->name,
sizeof(gd.driver));
ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
}
return ret;
}
static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_connectinfo ci;
memset(&ci, 0, sizeof(ci));
ci.devnum = ps->dev->devnum;
ci.slow = ps->dev->speed == USB_SPEED_LOW;
if (copy_to_user(arg, &ci, sizeof(ci)))
return -EFAULT;
return 0;
}
static int proc_conninfo_ex(struct usb_dev_state *ps,
void __user *arg, size_t size)
{
struct usbdevfs_conninfo_ex ci;
struct usb_device *udev = ps->dev;
if (size < sizeof(ci.size))
return -EINVAL;
memset(&ci, 0, sizeof(ci));
ci.size = sizeof(ci);
ci.busnum = udev->bus->busnum;
ci.devnum = udev->devnum;
ci.speed = udev->speed;
while (udev && udev->portnum != 0) {
if (++ci.num_ports <= ARRAY_SIZE(ci.ports))
ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] =
udev->portnum;
udev = udev->parent;
}
if (ci.num_ports < ARRAY_SIZE(ci.ports))
memmove(&ci.ports[0],
&ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports],
ci.num_ports);
if (copy_to_user(arg, &ci, min(sizeof(ci), size)))
return -EFAULT;
return 0;
}
static int proc_resetdevice(struct usb_dev_state *ps)
{
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>
2016-02-22 04:38:01 +07:00
struct usb_host_config *actconfig = ps->dev->actconfig;
struct usb_interface *interface;
int i, number;
/* Don't allow a device reset if the process has dropped the
* privilege to do such things and any of the interfaces are
* currently claimed.
*/
if (ps->privileges_dropped && actconfig) {
for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
interface = actconfig->interface[i];
number = interface->cur_altsetting->desc.bInterfaceNumber;
if (usb_interface_claimed(interface) &&
!test_bit(number, &ps->ifclaimed)) {
dev_warn(&ps->dev->dev,
"usbfs: interface %d claimed by %s while '%s' resets device\n",
number, interface->dev.driver->name, current->comm);
return -EACCES;
}
}
}
return usb_reset_device(ps->dev);
}
static int proc_setintf(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_setinterface setintf;
int ret;
if (copy_from_user(&setintf, arg, sizeof(setintf)))
return -EFAULT;
ret = checkintf(ps, setintf.interface);
if (ret)
return ret;
destroy_async_on_interface(ps, setintf.interface);
return usb_set_interface(ps->dev, setintf.interface,
setintf.altsetting);
}
static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
{
int u;
int status = 0;
struct usb_host_config *actconfig;
if (get_user(u, (int __user *)arg))
return -EFAULT;
actconfig = ps->dev->actconfig;
/* Don't touch the device if any interfaces are claimed.
* It could interfere with other drivers' operations, and if
* an interface is claimed by usbfs it could easily deadlock.
*/
if (actconfig) {
int i;
for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
if (usb_interface_claimed(actconfig->interface[i])) {
dev_warn(&ps->dev->dev,
"usbfs: interface %d claimed by %s "
"while '%s' sets config #%d\n",
actconfig->interface[i]
->cur_altsetting
->desc.bInterfaceNumber,
actconfig->interface[i]
->dev.driver->name,
current->comm, u);
status = -EBUSY;
break;
}
}
}
/* SET_CONFIGURATION is often abused as a "cheap" driver reset,
* so avoid usb_set_configuration()'s kick to sysfs
*/
if (status == 0) {
if (actconfig && actconfig->desc.bConfigurationValue == u)
status = usb_reset_configuration(ps->dev);
else
status = usb_set_configuration(ps->dev, u);
}
return status;
}
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
static struct usb_memory *
find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
{
struct usb_memory *usbm = NULL, *iter;
unsigned long flags;
unsigned long uurb_start = (unsigned long)uurb->buffer;
spin_lock_irqsave(&ps->lock, flags);
list_for_each_entry(iter, &ps->memory_list, memlist) {
if (uurb_start >= iter->vm_start &&
uurb_start < iter->vm_start + iter->size) {
if (uurb->buffer_length > iter->vm_start + iter->size -
uurb_start) {
usbm = ERR_PTR(-EINVAL);
} else {
usbm = iter;
usbm->urb_use_count++;
}
break;
}
}
spin_unlock_irqrestore(&ps->lock, flags);
return usbm;
}
static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
void __user *arg, sigval_t userurb_sigval)
{
struct usbdevfs_iso_packet_desc *isopkt = NULL;
struct usb_host_endpoint *ep;
struct async *as = NULL;
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int i, ret, num_sgs = 0, ifnum = -1;
int number_of_packets = 0;
unsigned int stream_id = 0;
void *buf;
bool is_in;
bool allow_short = false;
bool allow_zero = false;
unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK |
USBDEVFS_URB_BULK_CONTINUATION |
USBDEVFS_URB_NO_FSBR |
USBDEVFS_URB_ZERO_PACKET |
USBDEVFS_URB_NO_INTERRUPT;
/* USBDEVFS_URB_ISO_ASAP is a special case */
if (uurb->type == USBDEVFS_URB_TYPE_ISO)
mask |= USBDEVFS_URB_ISO_ASAP;
if (uurb->flags & ~mask)
return -EINVAL;
if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX)
return -EINVAL;
if (uurb->buffer_length > 0 && !uurb->buffer)
return -EINVAL;
if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
(uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
ifnum = findintfep(ps->dev, uurb->endpoint);
if (ifnum < 0)
return ifnum;
ret = checkintf(ps, ifnum);
if (ret)
return ret;
}
ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);
if (!ep)
return -ENOENT;
is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;
u = 0;
switch (uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet */
if (uurb->buffer_length < 8)
return -EINVAL;
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!dr)
return -ENOMEM;
if (copy_from_user(dr, uurb->buffer, 8)) {
ret = -EFAULT;
goto error;
}
if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) {
ret = -EINVAL;
goto error;
}
ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
le16_to_cpu(dr->wIndex));
if (ret)
goto error;
uurb->buffer_length = le16_to_cpu(dr->wLength);
uurb->buffer += 8;
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
is_in = 1;
uurb->endpoint |= USB_DIR_IN;
} else {
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
if (is_in)
allow_short = true;
snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequestType, dr->bRequest,
__le16_to_cpu(dr->wValue),
__le16_to_cpu(dr->wIndex),
__le16_to_cpu(dr->wLength));
u = sizeof(struct usb_ctrlrequest);
break;
case USBDEVFS_URB_TYPE_BULK:
if (!is_in)
allow_zero = true;
else
allow_short = true;
switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
case USB_ENDPOINT_XFER_INT:
/* allow single-shot interrupt transfers */
uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
goto interrupt_urb;
}
num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
num_sgs = 0;
if (ep->streams)
stream_id = uurb->stream_id;
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
interrupt_urb:
if (!is_in)
allow_zero = true;
else
allow_short = true;
break;
case USBDEVFS_URB_TYPE_ISO:
/* arbitrary limit */
if (uurb->number_of_packets < 1 ||
uurb->number_of_packets > 128)
return -EINVAL;
if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
number_of_packets = uurb->number_of_packets;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
number_of_packets;
isopkt = memdup_user(iso_frame_desc, isofrmlen);
if (IS_ERR(isopkt)) {
ret = PTR_ERR(isopkt);
isopkt = NULL;
goto error;
}
for (totlen = u = 0; u < number_of_packets; u++) {
/*
* arbitrary limit need for USB 3.1 Gen2
* sizemax: 96 DPs at SSP, 96 * 1024 = 98304
*/
if (isopkt[u].length > 98304) {
ret = -EINVAL;
goto error;
}
totlen += isopkt[u].length;
}
u *= sizeof(struct usb_iso_packet_descriptor);
USB: devio: Revert "USB: devio: Don't corrupt user memory" Taking the uurb->buffer_length userspace passes in as a maximum for the actual urbs transfer_buffer_length causes 2 serious issues: 1) It breaks isochronous support for all userspace apps using libusb, as existing libusb versions pass in 0 for uurb->buffer_length, relying on the kernel using the lenghts of the usbdevfs_iso_packet_desc descriptors passed in added together as buffer length. This for example causes redirection of USB audio and Webcam's into virtual machines using qemu-kvm to no longer work. This is a userspace ABI break and as such must be reverted. Note that the original commit does not protect other users / the kernels memory, it only stops the userspace process making the call from shooting itself in the foot. 2) It may cause the kernel to program host controllers to DMA over random memory. Just as the devio code used to only look at the iso_packet_desc lenghts, the host drivers do the same, relying on the submitter of the urbs to make sure the entire buffer is large enough and not checking transfer_buffer_length. But the "USB: devio: Don't corrupt user memory" commit now takes the userspace provided uurb->buffer_length for the buffer-size while copying over the user-provided iso_packet_desc lengths 1:1, allowing the user to specify a small buffer size while programming the host controller to dma a lot more data. (Atleast the ohci, uhci, xhci and fhci drivers do not check transfer_buffer_length for isoc transfers.) This reverts commit fa1ed74eb1c2 ("USB: devio: Don't corrupt user memory") fixing both these issues. Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-10-16 21:21:19 +07:00
uurb->buffer_length = totlen;
break;
default:
return -EINVAL;
}
if (uurb->buffer_length > 0 &&
Remove 'type' argument from access_ok() function Nobody has actually used the type (VERIFY_READ vs VERIFY_WRITE) argument of the user address range verification function since we got rid of the old racy i386-only code to walk page tables by hand. It existed because the original 80386 would not honor the write protect bit when in kernel mode, so you had to do COW by hand before doing any user access. But we haven't supported that in a long time, and these days the 'type' argument is a purely historical artifact. A discussion about extending 'user_access_begin()' to do the range checking resulted this patch, because there is no way we're going to move the old VERIFY_xyz interface to that model. And it's best done at the end of the merge window when I've done most of my merges, so let's just get this done once and for all. This patch was mostly done with a sed-script, with manual fix-ups for the cases that weren't of the trivial 'access_ok(VERIFY_xyz' form. There were a couple of notable cases: - csky still had the old "verify_area()" name as an alias. - the iter_iov code had magical hardcoded knowledge of the actual values of VERIFY_{READ,WRITE} (not that they mattered, since nothing really used it) - microblaze used the type argument for a debug printout but other than those oddities this should be a total no-op patch. I tried to fix up all architectures, did fairly extensive grepping for access_ok() uses, and the changes are trivial, but I may have missed something. Any missed conversion should be trivially fixable, though. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-01-04 09:57:57 +07:00
!access_ok(uurb->buffer, uurb->buffer_length)) {
ret = -EFAULT;
goto error;
}
as = alloc_async(number_of_packets);
if (!as) {
ret = -ENOMEM;
goto error;
}
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
as->usbm = find_memory_area(ps, uurb);
if (IS_ERR(as->usbm)) {
ret = PTR_ERR(as->usbm);
as->usbm = NULL;
goto error;
}
/* do not use SG buffers when memory mapped segments
* are in use
*/
if (as->usbm)
num_sgs = 0;
u += sizeof(struct async) + sizeof(struct urb) +
(as->usbm ? 0 : uurb->buffer_length) +
num_sgs * sizeof(struct scatterlist);
ret = usbfs_increase_memory_usage(u);
if (ret)
goto error;
as->mem_usage = u;
if (num_sgs) {
treewide: kmalloc() -> kmalloc_array() The kmalloc() function has a 2-factor argument form, kmalloc_array(). This patch replaces cases of: kmalloc(a * b, gfp) with: kmalloc_array(a * b, gfp) as well as handling cases of: kmalloc(a * b * c, gfp) with: kmalloc(array3_size(a, b, c), gfp) as it's slightly less ugly than: kmalloc_array(array_size(a, b), c, gfp) This does, however, attempt to ignore constant size factors like: kmalloc(4 * 1024, gfp) though any constants defined via macros get caught up in the conversion. Any factors with a sizeof() of "unsigned char", "char", and "u8" were dropped, since they're redundant. The tools/ directory was manually excluded, since it has its own implementation of kmalloc(). The Coccinelle script used for this was: // Fix redundant parens around sizeof(). @@ type TYPE; expression THING, E; @@ ( kmalloc( - (sizeof(TYPE)) * E + sizeof(TYPE) * E , ...) | kmalloc( - (sizeof(THING)) * E + sizeof(THING) * E , ...) ) // Drop single-byte sizes and redundant parens. @@ expression COUNT; typedef u8; typedef __u8; @@ ( kmalloc( - sizeof(u8) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(__u8) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(char) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(unsigned char) * (COUNT) + COUNT , ...) | kmalloc( - sizeof(u8) * COUNT + COUNT , ...) | kmalloc( - sizeof(__u8) * COUNT + COUNT , ...) | kmalloc( - sizeof(char) * COUNT + COUNT , ...) | kmalloc( - sizeof(unsigned char) * COUNT + COUNT , ...) ) // 2-factor product with sizeof(type/expression) and identifier or constant. @@ type TYPE; expression THING; identifier COUNT_ID; constant COUNT_CONST; @@ ( - kmalloc + kmalloc_array ( - sizeof(TYPE) * (COUNT_ID) + COUNT_ID, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * COUNT_ID + COUNT_ID, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * (COUNT_CONST) + COUNT_CONST, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * COUNT_CONST + COUNT_CONST, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * (COUNT_ID) + COUNT_ID, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * COUNT_ID + COUNT_ID, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * (COUNT_CONST) + COUNT_CONST, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * COUNT_CONST + COUNT_CONST, sizeof(THING) , ...) ) // 2-factor product, only identifiers. @@ identifier SIZE, COUNT; @@ - kmalloc + kmalloc_array ( - SIZE * COUNT + COUNT, SIZE , ...) // 3-factor product with 1 sizeof(type) or sizeof(expression), with // redundant parens removed. @@ expression THING; identifier STRIDE, COUNT; type TYPE; @@ ( kmalloc( - sizeof(TYPE) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(TYPE) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(TYPE) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(TYPE) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | kmalloc( - sizeof(THING) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kmalloc( - sizeof(THING) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kmalloc( - sizeof(THING) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | kmalloc( - sizeof(THING) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) ) // 3-factor product with 2 sizeof(variable), with redundant parens removed. @@ expression THING1, THING2; identifier COUNT; type TYPE1, TYPE2; @@ ( kmalloc( - sizeof(TYPE1) * sizeof(TYPE2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kmalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | kmalloc( - sizeof(THING1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kmalloc( - sizeof(THING1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | kmalloc( - sizeof(TYPE1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) | kmalloc( - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) ) // 3-factor product, only identifiers, with redundant parens removed. @@ identifier STRIDE, SIZE, COUNT; @@ ( kmalloc( - (COUNT) * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - (COUNT) * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - (COUNT) * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - (COUNT) * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | kmalloc( - COUNT * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) ) // Any remaining multi-factor products, first at least 3-factor products, // when they're not all constants... @@ expression E1, E2, E3; constant C1, C2, C3; @@ ( kmalloc(C1 * C2 * C3, ...) | kmalloc( - (E1) * E2 * E3 + array3_size(E1, E2, E3) , ...) | kmalloc( - (E1) * (E2) * E3 + array3_size(E1, E2, E3) , ...) | kmalloc( - (E1) * (E2) * (E3) + array3_size(E1, E2, E3) , ...) | kmalloc( - E1 * E2 * E3 + array3_size(E1, E2, E3) , ...) ) // And then all remaining 2 factors products when they're not all constants, // keeping sizeof() as the second factor argument. @@ expression THING, E1, E2; type TYPE; constant C1, C2, C3; @@ ( kmalloc(sizeof(THING) * C2, ...) | kmalloc(sizeof(TYPE) * C2, ...) | kmalloc(C1 * C2 * C3, ...) | kmalloc(C1 * C2, ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * (E2) + E2, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(TYPE) * E2 + E2, sizeof(TYPE) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * (E2) + E2, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - sizeof(THING) * E2 + E2, sizeof(THING) , ...) | - kmalloc + kmalloc_array ( - (E1) * E2 + E1, E2 , ...) | - kmalloc + kmalloc_array ( - (E1) * (E2) + E1, E2 , ...) | - kmalloc + kmalloc_array ( - E1 * E2 + E1, E2 , ...) ) Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 03:55:00 +07:00
as->urb->sg = kmalloc_array(num_sgs,
sizeof(struct scatterlist),
GFP_KERNEL);
if (!as->urb->sg) {
ret = -ENOMEM;
goto error;
}
as->urb->num_sgs = num_sgs;
sg_init_table(as->urb->sg, as->urb->num_sgs);
totlen = uurb->buffer_length;
for (i = 0; i < as->urb->num_sgs; i++) {
u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
buf = kmalloc(u, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto error;
}
sg_set_buf(&as->urb->sg[i], buf, u);
if (!is_in) {
if (copy_from_user(buf, uurb->buffer, u)) {
ret = -EFAULT;
goto error;
}
uurb->buffer += u;
}
totlen -= u;
}
} else if (uurb->buffer_length > 0) {
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
if (as->usbm) {
unsigned long uurb_start = (unsigned long)uurb->buffer;
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
as->urb->transfer_buffer = as->usbm->mem +
(uurb_start - as->usbm->vm_start);
} else {
as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
GFP_KERNEL);
if (!as->urb->transfer_buffer) {
ret = -ENOMEM;
goto error;
}
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer,
uurb->buffer,
uurb->buffer_length)) {
ret = -EFAULT;
goto error;
}
} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
/*
* Isochronous input data may end up being
* discontiguous if some of the packets are
* short. Clear the buffer so that the gaps
* don't leak kernel data to userspace.
*/
memset(as->urb->transfer_buffer, 0,
uurb->buffer_length);
}
}
}
as->urb->dev = ps->dev;
as->urb->pipe = (uurb->type << 30) |
__create_pipe(ps->dev, uurb->endpoint & 0xf) |
(uurb->endpoint & USB_DIR_IN);
/* This tedious sequence is necessary because the URB_* flags
* are internal to the kernel and subject to change, whereas
* the USBDEVFS_URB_* flags are a user API and must not be changed.
*/
u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
u |= URB_ISO_ASAP;
if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
u |= URB_SHORT_NOT_OK;
if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
u |= URB_ZERO_PACKET;
if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
u |= URB_NO_INTERRUPT;
as->urb->transfer_flags = u;
if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n");
if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n");
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char *)dr;
dr = NULL;
as->urb->start_frame = uurb->start_frame;
as->urb->number_of_packets = number_of_packets;
as->urb->stream_id = stream_id;
if (ep->desc.bInterval) {
if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
ps->dev->speed == USB_SPEED_HIGH ||
ps->dev->speed >= USB_SPEED_SUPER)
as->urb->interval = 1 <<
min(15, ep->desc.bInterval - 1);
else
as->urb->interval = ep->desc.bInterval;
}
as->urb->context = as;
as->urb->complete = async_completed;
for (totlen = u = 0; u < number_of_packets; u++) {
as->urb->iso_frame_desc[u].offset = totlen;
as->urb->iso_frame_desc[u].length = isopkt[u].length;
totlen += isopkt[u].length;
}
kfree(isopkt);
isopkt = NULL;
as->ps = ps;
as->userurb = arg;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
as->userurb_sigval = userurb_sigval;
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
if (as->usbm) {
unsigned long uurb_start = (unsigned long)uurb->buffer;
as->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
as->urb->transfer_dma = as->usbm->dma_handle +
(uurb_start - as->usbm->vm_start);
} else if (is_in && uurb->buffer_length > 0)
as->userbuffer = uurb->buffer;
as->signr = uurb->signr;
as->ifnum = ifnum;
as->pid = get_pid(task_pid(current));
as->cred = get_current_cred();
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
as->urb->transfer_buffer_length, 0, SUBMIT,
NULL, 0);
if (!is_in)
snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
async_newpending(as);
if (usb_endpoint_xfer_bulk(&ep->desc)) {
spin_lock_irq(&ps->lock);
/* Not exactly the endpoint address; the direction bit is
* shifted to the 0x10 position so that the value will be
* between 0 and 31.
*/
as->bulk_addr = usb_endpoint_num(&ep->desc) |
((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
>> 3);
/* If this bulk URB is the start of a new transfer, re-enable
* the endpoint. Otherwise mark it as a continuation URB.
*/
if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
as->bulk_status = AS_CONTINUATION;
else
ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
/* Don't accept continuation URBs if the endpoint is
* disabled because of an earlier error.
*/
if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
ret = -EREMOTEIO;
else
ret = usb_submit_urb(as->urb, GFP_ATOMIC);
spin_unlock_irq(&ps->lock);
} else {
ret = usb_submit_urb(as->urb, GFP_KERNEL);
}
if (ret) {
dev_printk(KERN_DEBUG, &ps->dev->dev,
"usbfs: usb_submit_urb returned %d\n", ret);
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
0, ret, COMPLETE, NULL, 0);
async_removepending(as);
goto error;
}
return 0;
error:
kfree(isopkt);
kfree(dr);
if (as)
free_async(as);
return ret;
}
static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
sigval_t userurb_sigval;
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
memset(&userurb_sigval, 0, sizeof(userurb_sigval));
userurb_sigval.sival_ptr = arg;
return proc_do_submiturb(ps, &uurb,
(((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
arg, userurb_sigval);
}
static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)
{
struct urb *urb;
struct async *as;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
as = async_getpending(ps, arg);
if (!as) {
spin_unlock_irqrestore(&ps->lock, flags);
return -EINVAL;
}
urb = as->urb;
usb_get_urb(urb);
spin_unlock_irqrestore(&ps->lock, flags);
usb_kill_urb(urb);
usb_put_urb(urb);
return 0;
}
static void compute_isochronous_actual_length(struct urb *urb)
{
unsigned int i;
if (urb->number_of_packets > 0) {
urb->actual_length = 0;
for (i = 0; i < urb->number_of_packets; i++)
urb->actual_length +=
urb->iso_frame_desc[i].actual_length;
}
}
static int processcompl(struct async *as, void __user * __user *arg)
{
struct urb *urb = as->urb;
struct usbdevfs_urb __user *userurb = as->userurb;
void __user *addr = as->userurb;
unsigned int i;
compute_isochronous_actual_length(urb);
if (as->userbuffer && urb->actual_length) {
if (copy_urb_data_to_user(as->userbuffer, urb))
goto err_out;
}
if (put_user(as->status, &userurb->status))
goto err_out;
if (put_user(urb->actual_length, &userurb->actual_length))
goto err_out;
if (put_user(urb->error_count, &userurb->error_count))
goto err_out;
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
goto err_out;
if (put_user(urb->iso_frame_desc[i].status,
&userurb->iso_frame_desc[i].status))
goto err_out;
}
}
if (put_user(addr, (void __user * __user *)arg))
return -EFAULT;
return 0;
err_out:
return -EFAULT;
}
static struct async *reap_as(struct usb_dev_state *ps)
{
DECLARE_WAITQUEUE(wait, current);
struct async *as = NULL;
struct usb_device *dev = ps->dev;
add_wait_queue(&ps->wait, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
as = async_getcompleted(ps);
if (as || !connected(ps))
break;
if (signal_pending(current))
break;
usb_unlock_device(dev);
schedule();
usb_lock_device(dev);
}
remove_wait_queue(&ps->wait, &wait);
set_current_state(TASK_RUNNING);
return as;
}
static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
if (as) {
int retval;
snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
return retval;
}
if (signal_pending(current))
return -EINTR;
return -ENODEV;
}
static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
{
int retval;
struct async *as;
as = async_getcompleted(ps);
if (as) {
snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
} else {
retval = (connected(ps) ? -EAGAIN : -ENODEV);
}
return retval;
}
#ifdef CONFIG_COMPAT
static int proc_control_compat(struct usb_dev_state *ps,
struct usbdevfs_ctrltransfer32 __user *p32)
{
struct usbdevfs_ctrltransfer __user *p;
__u32 udata;
p = compat_alloc_user_space(sizeof(*p));
if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) ||
get_user(udata, &p32->data) ||
put_user(compat_ptr(udata), &p->data))
return -EFAULT;
return proc_control(ps, p);
}
static int proc_bulk_compat(struct usb_dev_state *ps,
struct usbdevfs_bulktransfer32 __user *p32)
{
struct usbdevfs_bulktransfer __user *p;
compat_uint_t n;
compat_caddr_t addr;
p = compat_alloc_user_space(sizeof(*p));
if (get_user(n, &p32->ep) || put_user(n, &p->ep) ||
get_user(n, &p32->len) || put_user(n, &p->len) ||
get_user(n, &p32->timeout) || put_user(n, &p->timeout) ||
get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data))
return -EFAULT;
return proc_bulk(ps, p);
}
static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnectsignal32 ds;
if (copy_from_user(&ds, arg, sizeof(ds)))
return -EFAULT;
ps->discsignr = ds.signr;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
ps->disccontext.sival_int = ds.context;
return 0;
}
static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb)
{
struct usbdevfs_urb32 urb32;
if (copy_from_user(&urb32, uurb, sizeof(*uurb)))
return -EFAULT;
kurb->type = urb32.type;
kurb->endpoint = urb32.endpoint;
kurb->status = urb32.status;
kurb->flags = urb32.flags;
kurb->buffer = compat_ptr(urb32.buffer);
kurb->buffer_length = urb32.buffer_length;
kurb->actual_length = urb32.actual_length;
kurb->start_frame = urb32.start_frame;
kurb->number_of_packets = urb32.number_of_packets;
kurb->error_count = urb32.error_count;
kurb->signr = urb32.signr;
kurb->usercontext = compat_ptr(urb32.usercontext);
return 0;
}
static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
sigval_t userurb_sigval;
if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
return -EFAULT;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
memset(&userurb_sigval, 0, sizeof(userurb_sigval));
userurb_sigval.sival_int = ptr_to_compat(arg);
return proc_do_submiturb(ps, &uurb,
((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
arg, userurb_sigval);
}
static int processcompl_compat(struct async *as, void __user * __user *arg)
{
struct urb *urb = as->urb;
struct usbdevfs_urb32 __user *userurb = as->userurb;
void __user *addr = as->userurb;
unsigned int i;
compute_isochronous_actual_length(urb);
if (as->userbuffer && urb->actual_length) {
if (copy_urb_data_to_user(as->userbuffer, urb))
return -EFAULT;
}
if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
return -EFAULT;
if (put_user(urb->iso_frame_desc[i].status,
&userurb->iso_frame_desc[i].status))
return -EFAULT;
}
}
if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
return -EFAULT;
return 0;
}
static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
if (as) {
int retval;
snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
return retval;
}
if (signal_pending(current))
return -EINTR;
return -ENODEV;
}
static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
{
int retval;
struct async *as;
as = async_getcompleted(ps);
if (as) {
snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
} else {
retval = (connected(ps) ? -EAGAIN : -ENODEV);
}
return retval;
}
#endif
static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnectsignal ds;
if (copy_from_user(&ds, arg, sizeof(ds)))
return -EFAULT;
ps->discsignr = ds.signr;
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
ps->disccontext.sival_ptr = ds.context;
return 0;
}
static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ifnum;
if (get_user(ifnum, (unsigned int __user *)arg))
return -EFAULT;
return claimintf(ps, ifnum);
}
static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ifnum;
int ret;
if (get_user(ifnum, (unsigned int __user *)arg))
return -EFAULT;
ret = releaseintf(ps, ifnum);
if (ret < 0)
return ret;
destroy_async_on_interface(ps, ifnum);
return 0;
}
static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
{
int size;
void *buf = NULL;
int retval = 0;
struct usb_interface *intf = NULL;
struct usb_driver *driver = NULL;
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>
2016-02-22 04:38:01 +07:00
if (ps->privileges_dropped)
return -EACCES;
if (!connected(ps))
return -ENODEV;
/* alloc buffer */
size = _IOC_SIZE(ctl->ioctl_code);
if (size > 0) {
buf = kmalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
if (copy_from_user(buf, ctl->data, size)) {
kfree(buf);
return -EFAULT;
}
} else {
memset(buf, 0, size);
}
}
if (ps->dev->state != USB_STATE_CONFIGURED)
retval = -EHOSTUNREACH;
else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
retval = -EINVAL;
else switch (ctl->ioctl_code) {
/* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT:
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
dev_dbg(&intf->dev, "disconnect by usbfs\n");
usb_driver_release_interface(driver, intf);
} else
retval = -ENODATA;
break;
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
if (!intf->dev.driver)
retval = device_attach(&intf->dev);
else
retval = -EBUSY;
break;
/* talk directly to the interface's driver */
default:
if (intf->dev.driver)
driver = to_usb_driver(intf->dev.driver);
if (driver == NULL || driver->unlocked_ioctl == NULL) {
retval = -ENOTTY;
} else {
retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
}
}
/* cleanup and return */
if (retval >= 0
&& (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
&& size > 0
&& copy_to_user(ctl->data, buf, size) != 0)
retval = -EFAULT;
kfree(buf);
return retval;
}
static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_ioctl ctrl;
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
return proc_ioctl(ps, &ctrl);
}
#ifdef CONFIG_COMPAT
static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
{
struct usbdevfs_ioctl32 ioc32;
struct usbdevfs_ioctl ctrl;
if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
return -EFAULT;
ctrl.ifno = ioc32.ifno;
ctrl.ioctl_code = ioc32.ioctl_code;
ctrl.data = compat_ptr(ioc32.data);
return proc_ioctl(ps, &ctrl);
}
#endif
static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)
{
unsigned portnum;
int rc;
if (get_user(portnum, (unsigned __user *) arg))
return -EFAULT;
rc = usb_hub_claim_port(ps->dev, portnum, ps);
if (rc == 0)
snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
portnum, task_pid_nr(current), current->comm);
return rc;
}
static int proc_release_port(struct usb_dev_state *ps, void __user *arg)
{
unsigned portnum;
if (get_user(portnum, (unsigned __user *) arg))
return -EFAULT;
return usb_hub_release_port(ps->dev, portnum, ps);
}
static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
usbdevfs: Add a USBDEVFS_GET_CAPABILITIES ioctl There are a few (new) usbdevfs capabilities which an application cannot discover in any other way then checking the kernel version. There are 3 problems with this: 1) It is just not very pretty. 2) Given the tendency of enterprise distros to backport stuff it is not reliable. 3) As discussed in length on the mailinglist, USBDEVFS_URB_BULK_CONTINUATION does not work as it should when combined with USBDEVFS_URB_SHORT_NOT_OK (which is its intended use) on devices attached to an XHCI controller. So the availability of these features can be host controller dependent, making depending on them based on the kernel version not a good idea. This patch besides adding the new ioctl also adds flags for the following existing capabilities: USBDEVFS_CAP_ZERO_PACKET, available since 2.6.31 USBDEVFS_CAP_BULK_CONTINUATION, available since 2.6.32, except for XHCI USBDEVFS_CAP_NO_PACKET_SIZE_LIM, available since 3.3 Note that this patch only does not advertise the USBDEVFS_URB_BULK_CONTINUATION cap for XHCI controllers, bulk transfers with this flag set will still be accepted when submitted to XHCI controllers. Returning -EINVAL for them would break existing apps, and in most cases the troublesome scenario wrt USBDEVFS_URB_SHORT_NOT_OK urbs on XHCI controllers will never get hit, so this would break working use cases. The disadvantage of not returning -EINVAL is that cases were it is causing real trouble may go undetected / the cause of the trouble may be unclear, but this is the best we can do. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-07-04 14:18:02 +07:00
{
__u32 caps;
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
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>
2016-02-22 04:38:01 +07:00
USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
USBDEVFS_CAP_DROP_PRIVILEGES |
USBDEVFS_CAP_CONNINFO_EX | MAYBE_CAP_SUSPEND;
usbdevfs: Add a USBDEVFS_GET_CAPABILITIES ioctl There are a few (new) usbdevfs capabilities which an application cannot discover in any other way then checking the kernel version. There are 3 problems with this: 1) It is just not very pretty. 2) Given the tendency of enterprise distros to backport stuff it is not reliable. 3) As discussed in length on the mailinglist, USBDEVFS_URB_BULK_CONTINUATION does not work as it should when combined with USBDEVFS_URB_SHORT_NOT_OK (which is its intended use) on devices attached to an XHCI controller. So the availability of these features can be host controller dependent, making depending on them based on the kernel version not a good idea. This patch besides adding the new ioctl also adds flags for the following existing capabilities: USBDEVFS_CAP_ZERO_PACKET, available since 2.6.31 USBDEVFS_CAP_BULK_CONTINUATION, available since 2.6.32, except for XHCI USBDEVFS_CAP_NO_PACKET_SIZE_LIM, available since 3.3 Note that this patch only does not advertise the USBDEVFS_URB_BULK_CONTINUATION cap for XHCI controllers, bulk transfers with this flag set will still be accepted when submitted to XHCI controllers. Returning -EINVAL for them would break existing apps, and in most cases the troublesome scenario wrt USBDEVFS_URB_SHORT_NOT_OK urbs on XHCI controllers will never get hit, so this would break working use cases. The disadvantage of not returning -EINVAL is that cases were it is causing real trouble may go undetected / the cause of the trouble may be unclear, but this is the best we can do. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-07-04 14:18:02 +07:00
if (!ps->dev->bus->no_stop_on_short)
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
if (ps->dev->bus->sg_tablesize)
caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
usbdevfs: Add a USBDEVFS_GET_CAPABILITIES ioctl There are a few (new) usbdevfs capabilities which an application cannot discover in any other way then checking the kernel version. There are 3 problems with this: 1) It is just not very pretty. 2) Given the tendency of enterprise distros to backport stuff it is not reliable. 3) As discussed in length on the mailinglist, USBDEVFS_URB_BULK_CONTINUATION does not work as it should when combined with USBDEVFS_URB_SHORT_NOT_OK (which is its intended use) on devices attached to an XHCI controller. So the availability of these features can be host controller dependent, making depending on them based on the kernel version not a good idea. This patch besides adding the new ioctl also adds flags for the following existing capabilities: USBDEVFS_CAP_ZERO_PACKET, available since 2.6.31 USBDEVFS_CAP_BULK_CONTINUATION, available since 2.6.32, except for XHCI USBDEVFS_CAP_NO_PACKET_SIZE_LIM, available since 3.3 Note that this patch only does not advertise the USBDEVFS_URB_BULK_CONTINUATION cap for XHCI controllers, bulk transfers with this flag set will still be accepted when submitted to XHCI controllers. Returning -EINVAL for them would break existing apps, and in most cases the troublesome scenario wrt USBDEVFS_URB_SHORT_NOT_OK urbs on XHCI controllers will never get hit, so this would break working use cases. The disadvantage of not returning -EINVAL is that cases were it is causing real trouble may go undetected / the cause of the trouble may be unclear, but this is the best we can do. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-07-04 14:18:02 +07:00
if (put_user(caps, (__u32 __user *)arg))
return -EFAULT;
return 0;
}
static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnect_claim dc;
struct usb_interface *intf;
if (copy_from_user(&dc, arg, sizeof(dc)))
return -EFAULT;
intf = usb_ifnum_to_if(ps->dev, dc.interface);
if (!intf)
return -EINVAL;
if (intf->dev.driver) {
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
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>
2016-02-22 04:38:01 +07:00
if (ps->privileges_dropped)
return -EACCES;
if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
strncmp(dc.driver, intf->dev.driver->name,
sizeof(dc.driver)) != 0)
return -EBUSY;
if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
strncmp(dc.driver, intf->dev.driver->name,
sizeof(dc.driver)) == 0)
return -EBUSY;
dev_dbg(&intf->dev, "disconnect by usbfs\n");
usb_driver_release_interface(driver, intf);
}
return claimintf(ps, dc.interface);
}
USB patches for 3.15-rc1 Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlM7AbcACgkQMUfUDdst+ymbZACgncdbZyPsVZ7ZUpBFNbO/vBVT T9UAmwciojEzjh7b+x4ylsWH+O3LWVN3 =RpAF -----END PGP SIGNATURE----- Merge tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB patches from Greg KH: "Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while" * tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (249 commits) xhci: Transition maintainership to Mathias Nyman. USB: disable reset-resume when USB_QUIRK_RESET is set USB: unbind all interfaces before rebinding any usb: phy: Add ulpi IDs for SMSC USB3320 and TI TUSB1210 usb: gadget: tcm_usb_gadget: stop format strings usb: gadget: f_fs: add missing spinlock and mutex unlock usb: gadget: composite: switch over to ERR_CAST() usb: gadget: inode: switch over to memdup_user() usb: gadget: f_subset: switch over to PTR_RET usb: gadget: lpc32xx_udc: fix wrong clk_put() sequence USB: keyspan: remove dead debugging code USB: serial: add missing newlines to dev_<level> messages. USB: serial: add missing braces USB: serial: continue to write on errors USB: serial: continue to read on errors USB: serial: make bulk_out_size a lower limit USB: cypress_m8: fix potential scheduling while atomic devicetree: bindings: document lsi,zevio-usb usb: chipidea: add support for USB OTG controller on LSI Zevio SoCs usb: chipidea: imx: Use dev_name() for ci_hdrc name to distinguish USBs ...
2014-04-02 07:06:09 +07:00
static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg)
{
unsigned num_streams, num_eps;
struct usb_host_endpoint **eps;
struct usb_interface *intf;
int r;
r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps,
&eps, &intf);
if (r)
return r;
destroy_async_on_interface(ps,
intf->altsetting[0].desc.bInterfaceNumber);
r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL);
kfree(eps);
return r;
}
USB patches for 3.15-rc1 Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlM7AbcACgkQMUfUDdst+ymbZACgncdbZyPsVZ7ZUpBFNbO/vBVT T9UAmwciojEzjh7b+x4ylsWH+O3LWVN3 =RpAF -----END PGP SIGNATURE----- Merge tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB patches from Greg KH: "Here's the big USB pull request for 3.15-rc1. The normal set of patches, lots of controller driver updates, and a smattering of individual USB driver updates as well. All have been in linux-next for a while" * tag 'usb-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (249 commits) xhci: Transition maintainership to Mathias Nyman. USB: disable reset-resume when USB_QUIRK_RESET is set USB: unbind all interfaces before rebinding any usb: phy: Add ulpi IDs for SMSC USB3320 and TI TUSB1210 usb: gadget: tcm_usb_gadget: stop format strings usb: gadget: f_fs: add missing spinlock and mutex unlock usb: gadget: composite: switch over to ERR_CAST() usb: gadget: inode: switch over to memdup_user() usb: gadget: f_subset: switch over to PTR_RET usb: gadget: lpc32xx_udc: fix wrong clk_put() sequence USB: keyspan: remove dead debugging code USB: serial: add missing newlines to dev_<level> messages. USB: serial: add missing braces USB: serial: continue to write on errors USB: serial: continue to read on errors USB: serial: make bulk_out_size a lower limit USB: cypress_m8: fix potential scheduling while atomic devicetree: bindings: document lsi,zevio-usb usb: chipidea: add support for USB OTG controller on LSI Zevio SoCs usb: chipidea: imx: Use dev_name() for ci_hdrc name to distinguish USBs ...
2014-04-02 07:06:09 +07:00
static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
{
unsigned num_eps;
struct usb_host_endpoint **eps;
struct usb_interface *intf;
int r;
r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf);
if (r)
return r;
destroy_async_on_interface(ps,
intf->altsetting[0].desc.bInterfaceNumber);
r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL);
kfree(eps);
return r;
}
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>
2016-02-22 04:38:01 +07:00
static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg)
{
u32 data;
if (copy_from_user(&data, arg, sizeof(data)))
return -EFAULT;
/* This is a one way operation. Once privileges are
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>
2016-02-22 04:38:01 +07:00
* dropped, you cannot regain them. You may however reissue
* this ioctl to shrink the allowed interfaces mask.
*/
ps->interface_allowed_mask &= data;
ps->privileges_dropped = true;
return 0;
}
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
static int proc_forbid_suspend(struct usb_dev_state *ps)
{
int ret = 0;
if (ps->suspend_allowed) {
ret = usb_autoresume_device(ps->dev);
if (ret == 0)
ps->suspend_allowed = false;
else if (ret != -ENODEV)
ret = -EIO;
}
return ret;
}
static int proc_allow_suspend(struct usb_dev_state *ps)
{
if (!connected(ps))
return -ENODEV;
WRITE_ONCE(ps->not_yet_resumed, 1);
if (!ps->suspend_allowed) {
usb_autosuspend_device(ps->dev);
ps->suspend_allowed = true;
}
return 0;
}
static int proc_wait_for_resume(struct usb_dev_state *ps)
{
int ret;
usb_unlock_device(ps->dev);
ret = wait_event_interruptible(ps->wait_for_resume,
READ_ONCE(ps->not_yet_resumed) == 0);
usb_lock_device(ps->dev);
if (ret != 0)
return -EINTR;
return proc_forbid_suspend(ps);
}
/*
* NOTE: All requests here that have interface numbers as parameters
* are assuming that somehow the configuration has been prevented from
* changing. But there's no mechanism to ensure that...
*/
static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p)
{
struct usb_dev_state *ps = file->private_data;
struct inode *inode = file_inode(file);
struct usb_device *dev = ps->dev;
int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
/* Reap operations are allowed even after disconnection */
switch (cmd) {
case USBDEVFS_REAPURB:
snoop(&dev->dev, "%s: REAPURB\n", __func__);
ret = proc_reapurb(ps, p);
goto done;
case USBDEVFS_REAPURBNDELAY:
snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
ret = proc_reapurbnonblock(ps, p);
goto done;
#ifdef CONFIG_COMPAT
case USBDEVFS_REAPURB32:
snoop(&dev->dev, "%s: REAPURB32\n", __func__);
ret = proc_reapurb_compat(ps, p);
goto done;
case USBDEVFS_REAPURBNDELAY32:
snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
ret = proc_reapurbnonblock_compat(ps, p);
goto done;
#endif
}
if (!connected(ps)) {
usb_unlock_device(dev);
return -ENODEV;
}
switch (cmd) {
case USBDEVFS_CONTROL:
snoop(&dev->dev, "%s: CONTROL\n", __func__);
ret = proc_control(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_BULK:
snoop(&dev->dev, "%s: BULK\n", __func__);
ret = proc_bulk(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_RESETEP:
snoop(&dev->dev, "%s: RESETEP\n", __func__);
ret = proc_resetep(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_RESET:
snoop(&dev->dev, "%s: RESET\n", __func__);
ret = proc_resetdevice(ps);
break;
case USBDEVFS_CLEAR_HALT:
snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
ret = proc_clearhalt(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_GETDRIVER:
snoop(&dev->dev, "%s: GETDRIVER\n", __func__);
ret = proc_getdriver(ps, p);
break;
case USBDEVFS_CONNECTINFO:
snoop(&dev->dev, "%s: CONNECTINFO\n", __func__);
ret = proc_connectinfo(ps, p);
break;
case USBDEVFS_SETINTERFACE:
snoop(&dev->dev, "%s: SETINTERFACE\n", __func__);
ret = proc_setintf(ps, p);
break;
case USBDEVFS_SETCONFIGURATION:
snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__);
ret = proc_setconfig(ps, p);
break;
case USBDEVFS_SUBMITURB:
snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
ret = proc_submiturb(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
#ifdef CONFIG_COMPAT
case USBDEVFS_CONTROL32:
snoop(&dev->dev, "%s: CONTROL32\n", __func__);
ret = proc_control_compat(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_BULK32:
snoop(&dev->dev, "%s: BULK32\n", __func__);
ret = proc_bulk_compat(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_DISCSIGNAL32:
snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__);
ret = proc_disconnectsignal_compat(ps, p);
break;
case USBDEVFS_SUBMITURB32:
snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
ret = proc_submiturb_compat(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_IOCTL32:
snoop(&dev->dev, "%s: IOCTL32\n", __func__);
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
break;
#endif
case USBDEVFS_DISCARDURB:
snoop(&dev->dev, "%s: DISCARDURB %pK\n", __func__, p);
ret = proc_unlinkurb(ps, p);
break;
case USBDEVFS_DISCSIGNAL:
snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
ret = proc_disconnectsignal(ps, p);
break;
case USBDEVFS_CLAIMINTERFACE:
snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);
ret = proc_claiminterface(ps, p);
break;
case USBDEVFS_RELEASEINTERFACE:
snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__);
ret = proc_releaseinterface(ps, p);
break;
case USBDEVFS_IOCTL:
snoop(&dev->dev, "%s: IOCTL\n", __func__);
ret = proc_ioctl_default(ps, p);
break;
case USBDEVFS_CLAIM_PORT:
snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
ret = proc_claim_port(ps, p);
break;
case USBDEVFS_RELEASE_PORT:
snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
ret = proc_release_port(ps, p);
break;
usbdevfs: Add a USBDEVFS_GET_CAPABILITIES ioctl There are a few (new) usbdevfs capabilities which an application cannot discover in any other way then checking the kernel version. There are 3 problems with this: 1) It is just not very pretty. 2) Given the tendency of enterprise distros to backport stuff it is not reliable. 3) As discussed in length on the mailinglist, USBDEVFS_URB_BULK_CONTINUATION does not work as it should when combined with USBDEVFS_URB_SHORT_NOT_OK (which is its intended use) on devices attached to an XHCI controller. So the availability of these features can be host controller dependent, making depending on them based on the kernel version not a good idea. This patch besides adding the new ioctl also adds flags for the following existing capabilities: USBDEVFS_CAP_ZERO_PACKET, available since 2.6.31 USBDEVFS_CAP_BULK_CONTINUATION, available since 2.6.32, except for XHCI USBDEVFS_CAP_NO_PACKET_SIZE_LIM, available since 3.3 Note that this patch only does not advertise the USBDEVFS_URB_BULK_CONTINUATION cap for XHCI controllers, bulk transfers with this flag set will still be accepted when submitted to XHCI controllers. Returning -EINVAL for them would break existing apps, and in most cases the troublesome scenario wrt USBDEVFS_URB_SHORT_NOT_OK urbs on XHCI controllers will never get hit, so this would break working use cases. The disadvantage of not returning -EINVAL is that cases were it is causing real trouble may go undetected / the cause of the trouble may be unclear, but this is the best we can do. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-07-04 14:18:02 +07:00
case USBDEVFS_GET_CAPABILITIES:
ret = proc_get_capabilities(ps, p);
break;
case USBDEVFS_DISCONNECT_CLAIM:
ret = proc_disconnect_claim(ps, p);
break;
case USBDEVFS_ALLOC_STREAMS:
ret = proc_alloc_streams(ps, p);
break;
case USBDEVFS_FREE_STREAMS:
ret = proc_free_streams(ps, p);
break;
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>
2016-02-22 04:38:01 +07:00
case USBDEVFS_DROP_PRIVILEGES:
ret = proc_drop_privileges(ps, p);
break;
case USBDEVFS_GET_SPEED:
ret = ps->dev->speed;
break;
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
case USBDEVFS_FORBID_SUSPEND:
ret = proc_forbid_suspend(ps);
break;
case USBDEVFS_ALLOW_SUSPEND:
ret = proc_allow_suspend(ps);
break;
case USBDEVFS_WAIT_FOR_RESUME:
ret = proc_wait_for_resume(ps);
break;
}
/* Handle variable-length commands */
switch (cmd & ~IOCSIZE_MASK) {
case USBDEVFS_CONNINFO_EX(0):
ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd));
break;
}
done:
usb_unlock_device(dev);
if (ret >= 0)
inode->i_atime = current_time(inode);
return ret;
}
static long usbdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
return ret;
}
#ifdef CONFIG_COMPAT
static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
return ret;
}
#endif
/* No kernel lock - fine */
static __poll_t usbdev_poll(struct file *file,
struct poll_table_struct *wait)
{
struct usb_dev_state *ps = file->private_data;
__poll_t mask = 0;
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= EPOLLOUT | EPOLLWRNORM;
if (!connected(ps))
mask |= EPOLLHUP;
if (list_empty(&ps->list))
mask |= EPOLLERR;
return mask;
}
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
const struct file_operations usbdev_file_operations = {
.owner = THIS_MODULE,
.llseek = no_seek_end_llseek,
.read = usbdev_read,
.poll = usbdev_poll,
.unlocked_ioctl = usbdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = usbdev_compat_ioctl,
#endif
USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson <sesse@google.com> Signed-off-by: Markus Rechberger <mrechberger@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-04 04:58:26 +07:00
.mmap = usbdev_mmap,
.open = usbdev_open,
.release = usbdev_release,
};
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
static void usbdev_remove(struct usb_device *udev)
{
struct usb_dev_state *ps;
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
/* Protect against simultaneous resume */
mutex_lock(&usbfs_mutex);
while (!list_empty(&udev->filelist)) {
ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
destroy_all_async(ps);
wake_up_all(&ps->wait);
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
WRITE_ONCE(ps->not_yet_resumed, 0);
wake_up_all(&ps->wait_for_resume);
list_del_init(&ps->list);
signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio The usb support for asyncio encoded one of it's values in the wrong field. It should have used si_value but instead used si_addr which is not present in the _rt union member of struct siginfo. The practical result of this is that on a 64bit big endian kernel when delivering a signal to a 32bit process the si_addr field is set to NULL, instead of the expected pointer value. This issue can not be fixed in copy_siginfo_to_user32 as the usb usage of the the _sigfault (aka si_addr) member of the siginfo union when SI_ASYNCIO is set is incompatible with the POSIX and glibc usage of the _rt member of the siginfo union. Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a dedicated function for this one specific case. There are no other users of kill_pid_info_as_cred so this specialization should have no impact on the amount of code in the kernel. Have kill_pid_usb_asyncio take instead of a siginfo_t which is difficult and error prone, 3 arguments, a signal number, an errno value, and an address enconded as a sigval_t. The encoding of the address as a sigval_t allows the code that reads the userspace request for a signal to handle this compat issue along with all of the other compat issues. Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place the pointer value at the in si_pid (instead of si_addr). That is the code now verifies that si_pid and si_addr always occur at the same location. Further the code veries that for native structures a value placed in si_pid and spilling into si_uid will appear in userspace in si_addr (on a byte by byte copy of siginfo or a field by field copy of siginfo). The code also verifies that for a 64bit kernel and a 32bit userspace the 32bit pointer will fit in si_pid. I have used the usbsig.c program below written by Alan Stern and slightly tweaked by me to run on a big endian machine to verify the issue exists (on sparc64) and to confirm the patch below fixes the issue. /* usbsig.c -- test USB async signal delivery */ #define _GNU_SOURCE #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <endian.h> #include <linux/usb/ch9.h> #include <linux/usbdevice_fs.h> static struct usbdevfs_urb urb; static struct usbdevfs_disconnectsignal ds; static volatile sig_atomic_t done = 0; void urb_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &urb); printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); } void ds_handler(int sig, siginfo_t *info , void *ucontext) { printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", sig, info->si_signo, info->si_errno, info->si_code, info->si_addr, &ds); printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); done = 1; } int main(int argc, char **argv) { char *devfilename; int fd; int rc; struct sigaction act; struct usb_ctrlrequest *req; void *ptr; char buf[80]; if (argc != 2) { fprintf(stderr, "Usage: usbsig device-file-name\n"); return 1; } devfilename = argv[1]; fd = open(devfilename, O_RDWR); if (fd == -1) { perror("Error opening device file"); return 1; } act.sa_sigaction = urb_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR1, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } act.sa_sigaction = ds_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; rc = sigaction(SIGUSR2, &act, NULL); if (rc == -1) { perror("Error in sigaction"); return 1; } memset(&urb, 0, sizeof(urb)); urb.type = USBDEVFS_URB_TYPE_CONTROL; urb.endpoint = USB_DIR_IN | 0; urb.buffer = buf; urb.buffer_length = sizeof(buf); urb.signr = SIGUSR1; req = (struct usb_ctrlrequest *) buf; req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_GET_DESCRIPTOR; req->wValue = htole16(USB_DT_DEVICE << 8); req->wIndex = htole16(0); req->wLength = htole16(sizeof(buf) - sizeof(*req)); rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); if (rc == -1) { perror("Error in SUBMITURB ioctl"); return 1; } rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); if (rc == -1) { perror("Error in REAPURB ioctl"); return 1; } memset(&ds, 0, sizeof(ds)); ds.signr = SIGUSR2; ds.context = &ds; rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); if (rc == -1) { perror("Error in DISCSIGNAL ioctl"); return 1; } printf("Waiting for usb disconnect\n"); while (!done) { sleep(1); } close(fd); return 0; } Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-usb@vger.kernel.org Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oneukum@suse.com> Fixes: v2.3.39 Cc: stable@vger.kernel.org Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2019-02-08 08:44:12 +07:00
if (ps->discsignr)
kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext,
ps->disc_pid, ps->cred);
}
usbfs: Add ioctls for runtime power management It has been requested that usbfs should implement runtime power management, instead of forcing the device to remain at full power as long as the device file is open. This patch introduces that new feature. It does so by adding three new usbfs ioctls: USBDEVFS_FORBID_SUSPEND: Prevents the device from going into runtime suspend (and causes a resume if the device is already suspended). USBDEVFS_ALLOW_SUSPEND: Allows the device to go into runtime suspend. Some time may elapse before the device actually is suspended, depending on things like the autosuspend delay. USBDEVFS_WAIT_FOR_RESUME: Blocks until the call is interrupted by a signal or at least one runtime resume has occurred since the most recent ALLOW_SUSPEND ioctl call (which may mean immediately, even if the device is currently suspended). In the latter case, the device is prevented from suspending again just as if FORBID_SUSPEND was called before the ioctl returns. For backward compatibility, when the device file is first opened runtime suspends are forbidden. The userspace program can then allow suspends whenever it wants, and either resume the device directly (by forbidding suspends again) or wait for a resume from some other source (such as a remote wakeup). URBs submitted to a suspended device will fail or will complete with an appropriate error code. This combination of ioctls is sufficient for user programs to have nearly the same degree of control over a device's runtime power behavior as kernel drivers do. Still lacking is documentation for the new ioctls. I intend to add it later, after the existing documentation for the usbfs userspace API is straightened out into a reasonable form. Suggested-by: Mayuresh Kulkarni <mkulkarni@opensource.cirrus.com> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908071013220.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-08-07 21:29:50 +07:00
mutex_unlock(&usbfs_mutex);
}
static int usbdev_notify(struct notifier_block *self,
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
break;
}
return NOTIFY_OK;
}
static struct notifier_block usbdev_nb = {
.notifier_call = usbdev_notify,
};
static struct cdev usb_device_cdev;
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
int __init usb_devio_init(void)
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
{
int retval;
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
"usb_device");
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
if (retval) {
printk(KERN_ERR "Unable to register minors for usb_device\n");
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
goto out;
}
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
cdev_init(&usb_device_cdev, &usbdev_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
if (retval) {
printk(KERN_ERR "Unable to get usb_device major %d\n",
USB_DEVICE_MAJOR);
goto error_cdev;
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
}
usb_register_notify(&usbdev_nb);
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
out:
return retval;
error_cdev:
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
}
USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2007-03-13 21:59:31 +07:00
void usb_devio_cleanup(void)
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
{
usb_unregister_notify(&usbdev_nb);
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
[PATCH] USB: real nodes instead of usbfs This patch introduces a /sys/class/usb_device/ class where every connected usb-device will show up: tree /sys/class/usb_device/ /sys/class/usb_device/ |-- usb1.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1 |-- usb2.1 | |-- dev | `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2 ... The presence of the "dev" file lets udev create real device nodes. kay@pim:~/src/linux-2.6> tree /dev/bus/usb/ /dev/bus/usb/ |-- 1 | `-- 1 |-- 2 | `-- 1 ... udev rule: SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c" (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/') This makes libusb pick up the real nodes instead of the mounted usbfs: export USB_DEVFS_PATH=/dev/bus/usb Background: All this makes it possible to manage usb devices with udev instead of the devfs solution. We are currently working on a pam_console/resmgr replacement driven by udev and a pam-helper. It applies ACL's to device nodes, which is required for modern desktop functionalty like "Fast User Switching" or multiple local login support. New patch with its own major. I've succesfully disabled usbfs and use real nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks up the udev managed nodes instead of reading usbfs files. This makes udev to provide symlinks for libusb to pick up: SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c" /sbin/usbdevice: #!/bin/sh echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/' Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-31 06:05:53 +07:00
}