aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-04-30 22:15:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-01 11:12:58 -0400
commit444d0f621b64716f7868dcbde448e0c66ece4e61 (patch)
tree3947e0fe791c53c81d87a929af6d1b8e18a5c6aa /ipc
parent4d2bff5eb86e8d7b4a20934cccb93bdeebed3558 (diff)
ipc: introduce lockless pre_down ipcctl
Various forms of ipc use ipcctl_pre_down() to retrieve an ipc object and check permissions, mostly for IPC_RMID and IPC_SET commands. Introduce ipcctl_pre_down_nolock(), a lockless version of this function. The locking version is retained, yet modified to call the nolock version without affecting its semantics, thus transparent to all ipc callers. Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Signed-off-by: Rik van Riel <riel@redhat.com> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Cc: Chegu Vinod <chegu_vinod@hp.com> Cc: Emmanuel Benisty <benisty.e@gmail.com> Cc: Jason Low <jason.low2@hp.com> Cc: Michel Lespinasse <walken@google.com> Cc: Peter Hurley <peter@hurleysoftware.com> Cc: Stanislav Kinsbursky <skinsbursky@parallels.com> Tested-by: Sedat Dilek <sedat.dilek@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/util.c31
-rw-r--r--ipc/util.h3
2 files changed, 29 insertions, 5 deletions
diff --git a/ipc/util.c b/ipc/util.c
index 813804ebdeba..3df0af3158a5 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -824,11 +824,28 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
824 struct ipc64_perm *perm, int extra_perm) 824 struct ipc64_perm *perm, int extra_perm)
825{ 825{
826 struct kern_ipc_perm *ipcp; 826 struct kern_ipc_perm *ipcp;
827
828 ipcp = ipcctl_pre_down_nolock(ns, ids, id, cmd, perm, extra_perm);
829 if (IS_ERR(ipcp))
830 goto out;
831
832 spin_lock(&ipcp->lock);
833out:
834 return ipcp;
835}
836
837struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
838 struct ipc_ids *ids, int id, int cmd,
839 struct ipc64_perm *perm, int extra_perm)
840{
827 kuid_t euid; 841 kuid_t euid;
828 int err; 842 int err = -EPERM;
843 struct kern_ipc_perm *ipcp;
829 844
830 down_write(&ids->rw_mutex); 845 down_write(&ids->rw_mutex);
831 ipcp = ipc_lock_check(ids, id); 846 rcu_read_lock();
847
848 ipcp = ipc_obtain_object_check(ids, id);
832 if (IS_ERR(ipcp)) { 849 if (IS_ERR(ipcp)) {
833 err = PTR_ERR(ipcp); 850 err = PTR_ERR(ipcp);
834 goto out_up; 851 goto out_up;
@@ -837,17 +854,21 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
837 audit_ipc_obj(ipcp); 854 audit_ipc_obj(ipcp);
838 if (cmd == IPC_SET) 855 if (cmd == IPC_SET)
839 audit_ipc_set_perm(extra_perm, perm->uid, 856 audit_ipc_set_perm(extra_perm, perm->uid,
840 perm->gid, perm->mode); 857 perm->gid, perm->mode);
841 858
842 euid = current_euid(); 859 euid = current_euid();
843 if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) || 860 if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||
844 ns_capable(ns->user_ns, CAP_SYS_ADMIN)) 861 ns_capable(ns->user_ns, CAP_SYS_ADMIN))
845 return ipcp; 862 return ipcp;
846 863
847 err = -EPERM;
848 ipc_unlock(ipcp);
849out_up: 864out_up:
865 /*
866 * Unsuccessful lookup, unlock and return
867 * the corresponding error.
868 */
869 rcu_read_unlock();
850 up_write(&ids->rw_mutex); 870 up_write(&ids->rw_mutex);
871
851 return ERR_PTR(err); 872 return ERR_PTR(err);
852} 873}
853 874
diff --git a/ipc/util.h b/ipc/util.h
index bfc8d4ea6e46..13d92fea15a3 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -128,6 +128,9 @@ struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id);
128void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); 128void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
129void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); 129void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
130int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); 130int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
131struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
132 struct ipc_ids *ids, int id, int cmd,
133 struct ipc64_perm *perm, int extra_perm);
131struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns, 134struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
132 struct ipc_ids *ids, int id, int cmd, 135 struct ipc_ids *ids, int id, int cmd,
133 struct ipc64_perm *perm, int extra_perm); 136 struct ipc64_perm *perm, int extra_perm);