git://git.onelab.eu
/
linux-2.6.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git]
/
drivers
/
usb
/
core
/
devio.c
diff --git
a/drivers/usb/core/devio.c
b/drivers/usb/core/devio.c
index
2b68998
..
4b3a6ab
100644
(file)
--- a/
drivers/usb/core/devio.c
+++ b/
drivers/usb/core/devio.c
@@
-47,6
+47,7
@@
#include <linux/usbdevice_fs.h>
#include <linux/cdev.h>
#include <linux/notifier.h>
#include <linux/usbdevice_fs.h>
#include <linux/cdev.h>
#include <linux/notifier.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
@@
-58,16
+59,20
@@
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
+/* Mutual exclusion for removal, open, and release */
+DEFINE_MUTEX(usbfs_mutex);
+
struct async {
struct list_head asynclist;
struct dev_state *ps;
struct async {
struct list_head asynclist;
struct dev_state *ps;
-
pid_t
pid;
+
struct pid *
pid;
uid_t uid, euid;
unsigned int signr;
unsigned int ifnum;
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
uid_t uid, euid;
unsigned int signr;
unsigned int ifnum;
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
+ u32 secid;
};
static int usbfs_snoop = 0;
};
static int usbfs_snoop = 0;
@@
-85,9
+90,10
@@
MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
#define MAX_USBFS_BUFFER_SIZE 16384
#define MAX_USBFS_BUFFER_SIZE 16384
-static inline int connected (struct
usb_device *dev
)
+static inline int connected (struct
dev_state *ps
)
{
{
- return dev->state != USB_STATE_NOTATTACHED;
+ return (!list_empty(&ps->list) &&
+ ps->dev->state != USB_STATE_NOTATTACHED);
}
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
}
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@
-116,7
+122,7
@@
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct dev_state *ps =
(struct dev_state *)
file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
@@
-125,7
+131,7
@@
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
pos = *ppos;
usb_lock_device(dev);
pos = *ppos;
usb_lock_device(dev);
- if (!connected(
dev
)) {
+ if (!connected(
ps
)) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
@@
-134,26
+140,21
@@
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
}
if (pos < sizeof(struct usb_device_descriptor)) {
}
if (pos < sizeof(struct usb_device_descriptor)) {
- struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL);
- if (!desc) {
- ret = -ENOMEM;
- goto err;
- }
- memcpy(desc, &dev->descriptor, sizeof(dev->descriptor));
- le16_to_cpus(&desc->bcdUSB);
- le16_to_cpus(&desc->idVendor);
- le16_to_cpus(&desc->idProduct);
- le16_to_cpus(&desc->bcdDevice);
+ struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
+
+ 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;
len = sizeof(struct usb_device_descriptor) - pos;
if (len > nbytes)
len = nbytes;
- if (copy_to_user(buf, ((char *)desc) + pos, len)) {
- kfree(desc);
+ if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
ret = -EFAULT;
goto err;
}
ret = -EFAULT;
goto err;
}
- kfree(desc);
*ppos += len;
buf += len;
*ppos += len;
buf += len;
@@
-224,6
+225,7
@@
static struct async *alloc_async(unsigned int numisoframes)
static void free_async(struct async *as)
{
static void free_async(struct async *as)
{
+ put_pid(as->pid);
kfree(as->urb->transfer_buffer);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
kfree(as->urb->transfer_buffer);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
@@
-302,9
+304,9
@@
static void snoop_urb(struct urb *urb, void __user *userurb)
printk("\n");
}
printk("\n");
}
-static void async_completed(struct urb *urb
, struct pt_regs *regs
)
+static void async_completed(struct urb *urb)
{
{
- struct async *as =
(struct async *)
urb->context;
+ struct async *as = urb->context;
struct dev_state *ps = as->ps;
struct siginfo sinfo;
struct dev_state *ps = as->ps;
struct siginfo sinfo;
@@
-316,8
+318,8
@@
static void async_completed(struct urb *urb, struct pt_regs *regs)
sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
- kill_p
roc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
- as->euid);
+ kill_p
id_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
+ as->euid
, as->secid
);
}
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb, as->userurb);
}
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb, as->userurb);
@@
-498,7
+500,8
@@
static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
{
int ret = 0;
{
int ret = 0;
- if (ps->dev->state != USB_STATE_CONFIGURED)
+ if (ps->dev->state != USB_STATE_ADDRESS
+ && ps->dev->state != USB_STATE_CONFIGURED)
return -EHOSTUNREACH;
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0;
return -EHOSTUNREACH;
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0;
@@
-543,25
+546,25
@@
static int usbdev_open(struct inode *inode, struct file *file)
struct dev_state *ps;
int ret;
struct dev_state *ps;
int ret;
- /*
- * no locking necessary here, as chrdev_open has the kernel lock
- * (still acquire the kernel lock for safety)
- */
+ /* Protect against simultaneous removal or release */
+ mutex_lock(&usbfs_mutex);
+
ret = -ENOMEM;
if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
ret = -ENOMEM;
if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
- goto out
_nolock
;
+ goto out;
- lock_kernel();
ret = -ENOENT;
/* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
ret = -ENOENT;
/* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
- dev = inode->u.generic_ip;
- if (!dev) {
- kfree(ps);
+ dev = inode->i_private;
+ if (!dev)
goto out;
goto out;
- }
+ ret = usb_autoresume_device(dev);
+ if (ret)
+ goto out;
+
usb_get_dev(dev);
ret = 0;
ps->dev = dev;
usb_get_dev(dev);
ret = 0;
ps->dev = dev;
@@
-571,39
+574,47
@@
static int usbdev_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
- ps->disc_pid =
current->pid
;
+ ps->disc_pid =
get_pid(task_pid(current))
;
ps->disc_uid = current->uid;
ps->disc_euid = current->euid;
ps->disccontext = NULL;
ps->ifclaimed = 0;
ps->disc_uid = current->uid;
ps->disc_euid = current->euid;
ps->disccontext = NULL;
ps->ifclaimed = 0;
+ security_task_getsecid(current, &ps->secid);
wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
- unlock_kernel();
- out_nolock:
- return ret;
+ if (ret)
+ kfree(ps);
+ mutex_unlock(&usbfs_mutex);
+ return ret;
}
static int usbdev_release(struct inode *inode, struct file *file)
{
}
static int usbdev_release(struct inode *inode, struct file *file)
{
- struct dev_state *ps =
(struct dev_state *)
file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
unsigned int ifnum;
usb_lock_device(dev);
struct usb_device *dev = ps->dev;
unsigned int ifnum;
usb_lock_device(dev);
+
+ /* Protect against simultaneous open */
+ mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
list_del_init(&ps->list);
+ mutex_unlock(&usbfs_mutex);
+
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
}
destroy_all_async(ps);
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
}
destroy_all_async(ps);
+ usb_autosuspend_device(dev);
usb_unlock_device(dev);
usb_put_dev(dev);
usb_unlock_device(dev);
usb_put_dev(dev);
- p
s->dev = NULL
;
+ p
ut_pid(ps->disc_pid)
;
kfree(ps);
kfree(ps);
-
return 0;
+ return 0;
}
static int proc_control(struct dev_state *ps, void __user *arg)
}
static int proc_control(struct dev_state *ps, void __user *arg)
@@
-827,8
+838,7
@@
static int proc_connectinfo(struct dev_state *ps, void __user *arg)
static int proc_resetdevice(struct dev_state *ps)
{
static int proc_resetdevice(struct dev_state *ps)
{
- return usb_reset_device(ps->dev);
-
+ return usb_reset_composite_device(ps->dev, NULL);
}
static int proc_setintf(struct dev_state *ps, void __user *arg)
}
static int proc_setintf(struct dev_state *ps, void __user *arg)
@@
-927,8
+937,8
@@
static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_CONTROL)
return -EINVAL;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_CONTROL)
return -EINVAL;
- /* min 8 byte setup packet, max
arbitrary
*/
- if (uurb->buffer_length < 8 || uurb->buffer_length >
PAGE_SIZE
)
+ /* min 8 byte setup packet, max
8 byte setup plus an arbitrary data stage
*/
+ if (uurb->buffer_length < 8 || uurb->buffer_length >
(8 + MAX_USBFS_BUFFER_SIZE)
)
return -EINVAL;
if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -ENOMEM;
return -EINVAL;
if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -ENOMEM;
@@
-952,7
+962,11
@@
static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return -EFAULT;
}
kfree(dr);
return -EFAULT;
}
- snoop(&ps->dev->dev, "control urb\n");
+ snoop(&ps->dev->dev, "control urb: bRequest=%02x "
+ "bRrequestType=%02x wValue=%04x "
+ "wIndex=%04x wLength=%04x\n",
+ dr->bRequest, dr->bRequestType, dr->wValue,
+ dr->wIndex, dr->wLength);
break;
case USBDEVFS_URB_TYPE_BULK:
break;
case USBDEVFS_URB_TYPE_BULK:
@@
-986,7
+1000,8
@@
static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EFAULT;
}
for (totlen = u = 0; u < uurb->number_of_packets; u++) {
return -EFAULT;
}
for (totlen = u = 0; u < uurb->number_of_packets; u++) {
- if (isopkt[u].length > 1023) {
+ /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */
+ if (isopkt[u].length > 8192) {
kfree(isopkt);
return -EINVAL;
}
kfree(isopkt);
return -EINVAL;
}
@@
-1054,9
+1069,10
@@
static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->userbuffer = NULL;
as->signr = uurb->signr;
as->ifnum = ifnum;
as->userbuffer = NULL;
as->signr = uurb->signr;
as->ifnum = ifnum;
- as->pid =
current->pid
;
+ as->pid =
get_pid(task_pid(current))
;
as->uid = current->uid;
as->euid = current->euid;
as->uid = current->uid;
as->euid = current->euid;
+ security_task_getsecid(current, &as->secid);
if (!(uurb->endpoint & USB_DIR_IN)) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
free_async(as);
if (!(uurb->endpoint & USB_DIR_IN)) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
free_async(as);
@@
-1204,7
+1220,7
@@
static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
{
struct usbdevfs_urb uurb;
- if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
+ if (get_urb32(&uurb,(struct usbdevfs_urb32
__user
*)arg))
return -EFAULT;
return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
return -EFAULT;
return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
@@
-1239,7
+1255,7
@@
static int processcompl_compat(struct async *as, void __user * __user *arg)
}
free_async(as);
}
free_async(as);
- if (put_user(
(u32)(u64)addr
, (u32 __user *)arg))
+ if (put_user(
ptr_to_compat(addr)
, (u32 __user *)arg))
return -EFAULT;
return 0;
}
return -EFAULT;
return 0;
}
@@
-1322,7
+1338,7
@@
static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
}
}
- if (!connected(ps
->dev
)) {
+ if (!connected(ps)) {
kfree(buf);
return -ENODEV;
}
kfree(buf);
return -ENODEV;
}
@@
-1349,7
+1365,7
@@
static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
usb_unlock_device(ps->dev);
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
usb_unlock_device(ps->dev);
- bus_rescan_devices(intf->dev.bus);
+
retval =
bus_rescan_devices(intf->dev.bus);
usb_lock_device(ps->dev);
break;
usb_lock_device(ps->dev);
break;
@@
-1413,7
+1429,7
@@
static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
*/
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
*/
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct dev_state *ps =
(struct dev_state *)
file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
void __user *p = (void __user *)arg;
int ret = -ENOTTY;
struct usb_device *dev = ps->dev;
void __user *p = (void __user *)arg;
int ret = -ENOTTY;
@@
-1421,7
+1437,7
@@
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
- if (!connected(
dev
)) {
+ if (!connected(
ps
)) {
usb_unlock_device(dev);
return -ENODEV;
}
usb_unlock_device(dev);
return -ENODEV;
}
@@
-1508,7
+1524,7
@@
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case USBDEVFS_IOCTL32:
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
case USBDEVFS_IOCTL32:
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
- ret = proc_ioctl_compat(ps,
(compat_uptr_t)(long)p
);
+ ret = proc_ioctl_compat(ps,
ptr_to_compat(p)
);
break;
#endif
break;
#endif
@@
-1556,18
+1572,18
@@
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
- struct dev_state *ps =
(struct dev_state *)
file->private_data;
-
unsigned int mask = 0;
+ struct dev_state *ps = file->private_data;
+ unsigned int mask = 0;
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= POLLOUT | POLLWRNORM;
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= POLLOUT | POLLWRNORM;
- if (!connected(ps
->dev
))
+ if (!connected(ps))
mask |= POLLERR | POLLHUP;
return mask;
}
mask |= POLLERR | POLLHUP;
return mask;
}
-struct file_operations usbfs_device_file_operations = {
+
const
struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@
-1576,15
+1592,18
@@
struct file_operations usbfs_device_file_operations = {
.release = usbdev_release,
};
.release = usbdev_release,
};
-static
void
usbdev_add(struct usb_device *dev)
+static
int
usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->class_dev = class_device_create(usb_device_class, NULL,
MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->class_dev = class_device_create(usb_device_class, NULL,
MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
+ if (IS_ERR(dev->class_dev))
+ return PTR_ERR(dev->class_dev);
dev->class_dev->class_data = dev;
dev->class_dev->class_data = dev;
+ return 0;
}
static void usbdev_remove(struct usb_device *dev)
}
static void usbdev_remove(struct usb_device *dev)
@@
-1597,7
+1616,8
@@
static int usbdev_notify(struct notifier_block *self, unsigned long action,
{
switch (action) {
case USB_DEVICE_ADD:
{
switch (action) {
case USB_DEVICE_ADD:
- usbdev_add(dev);
+ if (usbdev_add(dev))
+ return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);