2933 lines · 71.4 KB · C
RawDownload
// 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 */#include <linux/usb/quirks.h>#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>#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 #define USB_MAXBUS			64#define USB_DEVICE_MAX			(USB_MAXBUS * 128)#define USB_SG_SIZE			16384 /* split-size for large txs */ /* 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;	struct list_head memory_list;	wait_queue_head_t wait;     /* wake up if a request completed */	wait_queue_head_t wait_for_resume;   /* wake up upon runtime resume */	unsigned int discsignr;	struct pid *disc_pid;	const struct cred *cred;	sigval_t disccontext;	unsigned long ifclaimed;	u32 disabled_bulk_eps;	unsigned long interface_allowed_mask;	int not_yet_resumed;	bool suspend_allowed;	bool privileges_dropped;}; 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;	sigval_t userurb_sigval;	struct urb *urb;	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 DEFINE_SPINLOCK(usbfs_memory_usage_lock);static u64 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, total_mem;	unsigned long flags;	int ret; 	lim = READ_ONCE(usbfs_memory_mb);	lim <<= 20; 	ret = 0;	spin_lock_irqsave(&usbfs_memory_usage_lock, flags);	total_mem = usbfs_memory_usage + amount;	if (lim > 0 && total_mem > lim)		ret = -ENOMEM;	else		usbfs_memory_usage = total_mem;	spin_unlock_irqrestore(&usbfs_memory_usage_lock, flags); 	return ret;} /* Memory for a transfer is being deallocated */static void usbfs_decrease_memory_usage(u64 amount){	unsigned long flags; 	spin_lock_irqsave(&usbfs_memory_usage_lock, flags);	if (amount > usbfs_memory_usage)		usbfs_memory_usage = 0;	else		usbfs_memory_usage -= amount;	spin_unlock_irqrestore(&usbfs_memory_usage_lock, flags);} static int connected(struct usb_dev_state *ps){	return (!list_empty(&ps->list) &&			ps->dev->state != USB_STATE_NOTATTACHED);} static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count){	struct usb_dev_state *ps = usbm->ps;	struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus);	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); 		hcd_buffer_free_pages(hcd, 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 = {	.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;	struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus);	size_t size = vma->vm_end - vma->vm_start;	void *mem;	unsigned long flags;	dma_addr_t dma_handle = DMA_MAPPING_ERROR;	int ret; 	if (!(file->f_mode & FMODE_WRITE))		return -EPERM; 	ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));	if (ret)		goto error; 	usbm = kzalloc_obj(struct usb_memory);	if (!usbm) {		ret = -ENOMEM;		goto error_decrease_mem;	} 	mem = hcd_buffer_alloc_pages(hcd,			size, GFP_USER | __GFP_NOWARN, &dma_handle);	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); 	/*	 * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates	 * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check	 * whether we are in such cases, and then use remap_pfn_range (or	 * dma_mmap_coherent) to map normal (or DMA) pages into the user	 * space, respectively.	 */	if (dma_handle == DMA_MAPPING_ERROR) {		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;		}	} else {		if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle,				      size)) {			dec_usb_memory_use_count(usbm, &usbm->vma_use_count);			return -EAGAIN;		}	} 	vm_flags_set(vma, VM_IO | 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_obj(struct async);	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);	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]));	} 	kfree(as->urb->sg);	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;

Lines 1–500 of 2933.