V4L/DVB (13590): cpia: convert it to use proc_fops
[safe/jmp/linux-2.6] / net / core / scm.c
index 271cf06..b7ba91b 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/security.h>
+#include <linux/pid.h>
+#include <linux/nsproxy.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
 
 /*
- *     Only allow a user to send credentials, that they could set with 
+ *     Only allow a user to send credentials, that they could set with
  *     setu(g)id.
  */
 
 static __inline__ int scm_check_creds(struct ucred *creds)
 {
-       if ((creds->pid == current->tgid || capable(CAP_SYS_ADMIN)) &&
-           ((creds->uid == current->uid || creds->uid == current->euid ||
-             creds->uid == current->suid) || capable(CAP_SETUID)) &&
-           ((creds->gid == current->gid || creds->gid == current->egid ||
-             creds->gid == current->sgid) || capable(CAP_SETGID))) {
+       const struct cred *cred = current_cred();
+
+       if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
+           ((creds->uid == cred->uid   || creds->uid == cred->euid ||
+             creds->uid == cred->suid) || capable(CAP_SETUID)) &&
+           ((creds->gid == cred->gid   || creds->gid == cred->egid ||
+             creds->gid == cred->sgid) || capable(CAP_SETGID))) {
               return 0;
        }
        return -EPERM;
@@ -79,11 +83,11 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 
        if (fpl->count + num > SCM_MAX_FD)
                return -EINVAL;
-       
+
        /*
         *      Verify the descriptors and increment the usage count.
         */
-        
+
        for (i=0; i< num; i++)
        {
                int fd = fdp[i];
@@ -104,9 +108,25 @@ void __scm_destroy(struct scm_cookie *scm)
 
        if (fpl) {
                scm->fp = NULL;
-               for (i=fpl->count-1; i>=0; i--)
-                       fput(fpl->fp[i]);
-               kfree(fpl);
+               if (current->scm_work_list) {
+                       list_add_tail(&fpl->list, current->scm_work_list);
+               } else {
+                       LIST_HEAD(work_list);
+
+                       current->scm_work_list = &work_list;
+
+                       list_add(&fpl->list, &work_list);
+                       while (!list_empty(&work_list)) {
+                               fpl = list_first_entry(&work_list, struct scm_fp_list, list);
+
+                               list_del(&fpl->list);
+                               for (i=fpl->count-1; i>=0; i--)
+                                       fput(fpl->fp[i]);
+                               kfree(fpl);
+                       }
+
+                       current->scm_work_list = NULL;
+               }
        }
 }
 
@@ -123,7 +143,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                /* The first check was omitted in <= 2.2.5. The reasoning was
                   that parser checks cmsg_len in any case, so that
                   additional check would be work duplication.
-                  But if cmsg_level is not SOL_SOCKET, we do not check 
+                  But if cmsg_level is not SOL_SOCKET, we do not check
                   for too short ancillary data object at all! Oops.
                   OK, let's add it...
                 */
@@ -159,7 +179,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                p->fp = NULL;
        }
        return 0;
-       
+
 error:
        scm_destroy(p);
        return err;
@@ -167,7 +187,8 @@ error:
 
 int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
 {
-       struct cmsghdr __user *cm = (struct cmsghdr __user *)msg->msg_control;
+       struct cmsghdr __user *cm
+               = (__force struct cmsghdr __user *)msg->msg_control;
        struct cmsghdr cmhdr;
        int cmlen = CMSG_LEN(len);
        int err;
@@ -189,10 +210,12 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
 
        err = -EFAULT;
        if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
-               goto out; 
+               goto out;
        if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
                goto out;
        cmlen = CMSG_SPACE(len);
+       if (msg->msg_controllen < cmlen)
+               cmlen = msg->msg_controllen;
        msg->msg_control += cmlen;
        msg->msg_controllen -= cmlen;
        err = 0;
@@ -202,7 +225,8 @@ out:
 
 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
 {
-       struct cmsghdr __user *cm = (struct cmsghdr __user*)msg->msg_control;
+       struct cmsghdr __user *cm
+               = (__force struct cmsghdr __user*)msg->msg_control;
 
        int fdmax = 0;
        int fdnum = scm->fp->count;
@@ -222,13 +246,15 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
        if (fdnum < fdmax)
                fdmax = fdnum;
 
-       for (i=0, cmfptr=(int __user *)CMSG_DATA(cm); i<fdmax; i++, cmfptr++)
+       for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax;
+            i++, cmfptr++)
        {
                int new_fd;
                err = security_file_receive(fp[i]);
                if (err)
                        break;
-               err = get_unused_fd();
+               err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & msg->msg_flags
+                                         ? O_CLOEXEC : 0);
                if (err < 0)
                        break;
                new_fd = err;