diff options
| author | Serge Hallyn <serge.hallyn@canonical.com> | 2011-09-26 10:45:18 -0500 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-09-29 13:13:08 -0700 | 
| commit | d178bc3a708f39cbfefc3fab37032d3f2511b4ec (patch) | |
| tree | af492e92e140f1f6abad5a377a269ef7335824de /drivers/usb/core/devio.c | |
| parent | edb2b255a0bebac5aeb17c7613aeb76ba4e6c63c (diff) | |
user namespace: usb: make usb urbs user namespace aware (v2)
Add to the dev_state and alloc_async structures the user namespace
corresponding to the uid and euid.  Pass these to kill_pid_info_as_uid(),
which can then implement a proper, user-namespace-aware uid check.
Changelog:
Sep 20: Per Oleg's suggestion: Instead of caching and passing user namespace,
	uid, and euid each separately, pass a struct cred.
Sep 26: Address Alan Stern's comments: don't define a struct cred at
	usbdev_open(), and take and put a cred at async_completed() to
	ensure it lasts for the duration of kill_pid_info_as_cred().
Signed-off-by: Serge Hallyn <serge.hallyn@canonical.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/devio.c')
| -rw-r--r-- | drivers/usb/core/devio.c | 30 | 
1 files changed, 13 insertions, 17 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 0ca54e22d31..e3beaf229ee 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -46,6 +46,7 @@  #include <linux/cdev.h>  #include <linux/notifier.h>  #include <linux/security.h> +#include <linux/user_namespace.h>  #include <asm/uaccess.h>  #include <asm/byteorder.h>  #include <linux/moduleparam.h> @@ -68,7 +69,7 @@ struct dev_state {  	wait_queue_head_t wait;     /* wake up if a request completed */  	unsigned int discsignr;  	struct pid *disc_pid; -	uid_t disc_uid, disc_euid; +	const struct cred *cred;  	void __user *disccontext;  	unsigned long ifclaimed;  	u32 secid; @@ -79,7 +80,7 @@ struct async {  	struct list_head asynclist;  	struct dev_state *ps;  	struct pid *pid; -	uid_t uid, euid; +	const struct cred *cred;  	unsigned int signr;  	unsigned int ifnum;  	void __user *userbuffer; @@ -248,6 +249,7 @@ static struct async *alloc_async(unsigned int numisoframes)  static void free_async(struct async *as)  {  	put_pid(as->pid); +	put_cred(as->cred);  	kfree(as->urb->transfer_buffer);  	kfree(as->urb->setup_packet);  	usb_free_urb(as->urb); @@ -393,9 +395,8 @@ static void async_completed(struct urb *urb)  	struct dev_state *ps = as->ps;  	struct siginfo sinfo;  	struct pid *pid = NULL; -	uid_t uid = 0; -	uid_t euid = 0;  	u32 secid = 0; +	const struct cred *cred = NULL;  	int signr;  	spin_lock(&ps->lock); @@ -408,8 +409,7 @@ static void async_completed(struct urb *urb)  		sinfo.si_code = SI_ASYNCIO;  		sinfo.si_addr = as->userurb;  		pid = get_pid(as->pid); -		uid = as->uid; -		euid = as->euid; +		cred = get_cred(as->cred);  		secid = as->secid;  	}  	snoop(&urb->dev->dev, "urb complete\n"); @@ -423,9 +423,9 @@ static void async_completed(struct urb *urb)  	spin_unlock(&ps->lock);  	if (signr) { -		kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, -				      euid, secid); +		kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid);  		put_pid(pid); +		put_cred(cred);  	}  	wake_up(&ps->wait); @@ -672,7 +672,6 @@ static int usbdev_open(struct inode *inode, struct file *file)  {  	struct usb_device *dev = NULL;  	struct dev_state *ps; -	const struct cred *cred = current_cred();  	int ret;  	ret = -ENOMEM; @@ -722,8 +721,7 @@ static int usbdev_open(struct inode *inode, struct file *file)  	init_waitqueue_head(&ps->wait);  	ps->discsignr = 0;  	ps->disc_pid = get_pid(task_pid(current)); -	ps->disc_uid = cred->uid; -	ps->disc_euid = cred->euid; +	ps->cred = get_current_cred();  	ps->disccontext = NULL;  	ps->ifclaimed = 0;  	security_task_getsecid(current, &ps->secid); @@ -765,6 +763,7 @@ static int usbdev_release(struct inode *inode, struct file *file)  	usb_unlock_device(dev);  	usb_put_dev(dev);  	put_pid(ps->disc_pid); +	put_cred(ps->cred);  	as = async_getcompleted(ps);  	while (as) { @@ -1065,7 +1064,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	struct usb_host_endpoint *ep;  	struct async *as;  	struct usb_ctrlrequest *dr = NULL; -	const struct cred *cred = current_cred();  	unsigned int u, totlen, isofrmlen;  	int ret, ifnum = -1;  	int is_in; @@ -1279,8 +1277,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	as->signr = uurb->signr;  	as->ifnum = ifnum;  	as->pid = get_pid(task_pid(current)); -	as->uid = cred->uid; -	as->euid = cred->euid; +	as->cred = get_current_cred();  	security_task_getsecid(current, &as->secid);  	if (!is_in && uurb->buffer_length > 0) {  		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, @@ -1998,9 +1995,8 @@ static void usbdev_remove(struct usb_device *udev)  			sinfo.si_errno = EPIPE;  			sinfo.si_code = SI_ASYNCIO;  			sinfo.si_addr = ps->disccontext; -			kill_pid_info_as_uid(ps->discsignr, &sinfo, -					ps->disc_pid, ps->disc_uid, -					ps->disc_euid, ps->secid); +			kill_pid_info_as_cred(ps->discsignr, &sinfo, +					ps->disc_pid, ps->cred, ps->secid);  		}  	}  }  | 
