Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm
[linux-flexiantxendom0-3.2.10.git] / ipc / util.c
index 361fd1c..75261a3 100644 (file)
@@ -47,15 +47,6 @@ struct ipc_proc_iface {
        int (*show)(struct seq_file *, void *);
 };
 
-struct ipc_namespace init_ipc_ns = {
-       .kref = {
-               .refcount       = ATOMIC_INIT(2),
-       },
-};
-
-atomic_t nr_ipc_ns = ATOMIC_INIT(1);
-
-
 #ifdef CONFIG_MEMORY_HOTPLUG
 
 static void ipc_memory_notifier(struct work_struct *work)
@@ -133,8 +124,8 @@ void ipc_init_ids(struct ipc_ids *ids)
        ids->seq = 0;
        {
                int seq_limit = INT_MAX/SEQ_MULTIPLIER;
-               if (seq_limit > USHORT_MAX)
-                       ids->seq_max = USHORT_MAX;
+               if (seq_limit > USHRT_MAX)
+                       ids->seq_max = USHRT_MAX;
                 else
                        ids->seq_max = seq_limit;
        }
@@ -258,6 +249,8 @@ int ipc_get_maxid(struct ipc_ids *ids)
  
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 {
+       uid_t euid;
+       gid_t egid;
        int id, err;
 
        if (size > IPCMNI)
@@ -280,8 +273,9 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 
        ids->in_use++;
 
-       new->cuid = new->uid = current->euid;
-       new->gid = new->cgid = current->egid;
+       current_euid_egid(&euid, &egid);
+       new->cuid = new->uid = euid;
+       new->gid = new->cgid = egid;
 
        new->seq = ids->seq++;
        if(ids->seq > ids->seq_max)
@@ -323,6 +317,7 @@ retry:
 
 /**
  *     ipc_check_perms -       check security and permissions for an IPC
+ *     @ns: IPC namespace
  *     @ipcp: ipc permission set
  *     @ops: the actual security routine to call
  *     @params: its parameters
@@ -335,12 +330,14 @@ retry:
  *
  *     It is called with ipc_ids.rw_mutex and ipcp->lock held.
  */
-static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
-                       struct ipc_params *params)
+static int ipc_check_perms(struct ipc_namespace *ns,
+                          struct kern_ipc_perm *ipcp,
+                          struct ipc_ops *ops,
+                          struct ipc_params *params)
 {
        int err;
 
-       if (ipcperms(ipcp, params->flg))
+       if (ipcperms(ns, ipcp, params->flg))
                err = -EACCES;
        else {
                err = ops->associate(ipcp, params->flg);
@@ -402,7 +399,7 @@ retry:
                                 * ipc_check_perms returns the IPC id on
                                 * success
                                 */
-                               err = ipc_check_perms(ipcp, ops, params);
+                               err = ipc_check_perms(ns, ipcp, ops, params);
                }
                ipc_unlock(ipcp);
        }
@@ -582,19 +579,6 @@ static void ipc_schedule_free(struct rcu_head *head)
        schedule_work(&sched->work);
 }
 
-/**
- * ipc_immediate_free - free ipc + rcu space
- * @head: RCU callback structure that contains pointer to be freed
- *
- * Free from the RCU callback context.
- */
-static void ipc_immediate_free(struct rcu_head *head)
-{
-       struct ipc_rcu_grace *free =
-               container_of(head, struct ipc_rcu_grace, rcu);
-       kfree(free);
-}
-
 void ipc_rcu_putref(void *ptr)
 {
        if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0)
@@ -604,35 +588,38 @@ void ipc_rcu_putref(void *ptr)
                call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
                                ipc_schedule_free);
        } else {
-               call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
-                               ipc_immediate_free);
+               kfree_rcu(container_of(ptr, struct ipc_rcu_grace, data), rcu);
        }
 }
 
 /**
  *     ipcperms        -       check IPC permissions
+ *     @ns: IPC namespace
  *     @ipcp: IPC permission set
  *     @flag: desired permission set.
  *
  *     Check user, group, other permissions for access
  *     to ipc resources. return 0 if allowed
+ *
+ *     @flag will most probably be 0 or S_...UGO from <linux/stat.h>
  */
  
-int ipcperms (struct kern_ipc_perm *ipcp, short flag)
-{      /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
-       int requested_mode, granted_mode, err;
+int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
+{
+       uid_t euid = current_euid();
+       int requested_mode, granted_mode;
 
-       if (unlikely((err = audit_ipc_obj(ipcp))))
-               return err;
+       audit_ipc_obj(ipcp);
        requested_mode = (flag >> 6) | (flag >> 3) | flag;
        granted_mode = ipcp->mode;
-       if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
+       if (euid == ipcp->cuid ||
+           euid == ipcp->uid)
                granted_mode >>= 6;
        else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
                granted_mode >>= 3;
        /* is there some bit set in requested_mode but not in granted_mode? */
        if ((requested_mode & ~granted_mode & 0007) && 
-           !capable(CAP_IPC_OWNER))
+           !ns_capable(ns->user_ns, CAP_IPC_OWNER))
                return -1;
 
        return security_ipc_permission(ipcp, flag);
@@ -770,6 +757,7 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
 
 /**
  * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
+ * @ns:  the ipc namespace
  * @ids:  the table of ids where to look for the ipc
  * @id:   the id of the ipc to retrieve
  * @cmd:  the cmd to check
@@ -784,10 +772,12 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
  *  - returns the ipc with both ipc and rw_mutex locks held in case of success
  *    or an err-code without any lock held otherwise.
  */
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
+struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
+                                     struct ipc_ids *ids, int id, int cmd,
                                      struct ipc64_perm *perm, int extra_perm)
 {
        struct kern_ipc_perm *ipcp;
+       uid_t euid;
        int err;
 
        down_write(&ids->rw_mutex);
@@ -797,22 +787,17 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
                goto out_up;
        }
 
-       err = audit_ipc_obj(ipcp);
-       if (err)
-               goto out_unlock;
-
-       if (cmd == IPC_SET) {
-               err = audit_ipc_set_perm(extra_perm, perm->uid,
+       audit_ipc_obj(ipcp);
+       if (cmd == IPC_SET)
+               audit_ipc_set_perm(extra_perm, perm->uid,
                                         perm->gid, perm->mode);
-               if (err)
-                       goto out_unlock;
-       }
-       if (current->euid == ipcp->cuid ||
-           current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
+
+       euid = current_euid();
+       if (euid == ipcp->cuid || euid == ipcp->uid  ||
+           ns_capable(ns->user_ns, CAP_SYS_ADMIN))
                return ipcp;
 
        err = -EPERM;
-out_unlock:
        ipc_unlock(ipcp);
 out_up:
        up_write(&ids->rw_mutex);
@@ -951,7 +936,7 @@ static int sysvipc_proc_show(struct seq_file *s, void *it)
        return iface->show(s, it);
 }
 
-static struct seq_operations sysvipc_proc_seqops = {
+static const struct seq_operations sysvipc_proc_seqops = {
        .start = sysvipc_proc_start,
        .stop  = sysvipc_proc_stop,
        .next  = sysvipc_proc_next,