aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/util.c71
-rw-r--r--ipc/util.h2
2 files changed, 59 insertions, 14 deletions
diff --git a/ipc/util.c b/ipc/util.c
index 03eadd8fb0fd..813804ebdeba 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -669,38 +669,81 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
669} 669}
670 670
671/** 671/**
672 * ipc_obtain_object
673 * @ids: ipc identifier set
674 * @id: ipc id to look for
675 *
676 * Look for an id in the ipc ids idr and return associated ipc object.
677 *
678 * Call inside the RCU critical section.
679 * The ipc object is *not* locked on exit.
680 */
681struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id)
682{
683 struct kern_ipc_perm *out;
684 int lid = ipcid_to_idx(id);
685
686 out = idr_find(&ids->ipcs_idr, lid);
687 if (!out)
688 return ERR_PTR(-EINVAL);
689
690 return out;
691}
692
693/**
672 * ipc_lock - Lock an ipc structure without rw_mutex held 694 * ipc_lock - Lock an ipc structure without rw_mutex held
673 * @ids: IPC identifier set 695 * @ids: IPC identifier set
674 * @id: ipc id to look for 696 * @id: ipc id to look for
675 * 697 *
676 * Look for an id in the ipc ids idr and lock the associated ipc object. 698 * Look for an id in the ipc ids idr and lock the associated ipc object.
677 * 699 *
678 * The ipc object is locked on exit. 700 * The ipc object is locked on successful exit.
679 */ 701 */
680
681struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) 702struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
682{ 703{
683 struct kern_ipc_perm *out; 704 struct kern_ipc_perm *out;
684 int lid = ipcid_to_idx(id);
685 705
686 rcu_read_lock(); 706 rcu_read_lock();
687 out = idr_find(&ids->ipcs_idr, lid); 707 out = ipc_obtain_object(ids, id);
688 if (out == NULL) { 708 if (IS_ERR(out))
689 rcu_read_unlock(); 709 goto err1;
690 return ERR_PTR(-EINVAL);
691 }
692 710
693 spin_lock(&out->lock); 711 spin_lock(&out->lock);
694 712
695 /* ipc_rmid() may have already freed the ID while ipc_lock 713 /* ipc_rmid() may have already freed the ID while ipc_lock
696 * was spinning: here verify that the structure is still valid 714 * was spinning: here verify that the structure is still valid
697 */ 715 */
698 if (out->deleted) { 716 if (!out->deleted)
699 spin_unlock(&out->lock); 717 return out;
700 rcu_read_unlock();
701 return ERR_PTR(-EINVAL);
702 }
703 718
719 spin_unlock(&out->lock);
720 out = ERR_PTR(-EINVAL);
721err1:
722 rcu_read_unlock();
723 return out;
724}
725
726/**
727 * ipc_obtain_object_check
728 * @ids: ipc identifier set
729 * @id: ipc id to look for
730 *
731 * Similar to ipc_obtain_object() but also checks
732 * the ipc object reference counter.
733 *
734 * Call inside the RCU critical section.
735 * The ipc object is *not* locked on exit.
736 */
737struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id)
738{
739 struct kern_ipc_perm *out = ipc_obtain_object(ids, id);
740
741 if (IS_ERR(out))
742 goto out;
743
744 if (ipc_checkid(out, id))
745 return ERR_PTR(-EIDRM);
746out:
704 return out; 747 return out;
705} 748}
706 749
diff --git a/ipc/util.h b/ipc/util.h
index ac1480a4efd1..bfc8d4ea6e46 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -123,6 +123,7 @@ void ipc_rcu_getref(void *ptr);
123void ipc_rcu_putref(void *ptr); 123void ipc_rcu_putref(void *ptr);
124 124
125struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); 125struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
126struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id);
126 127
127void 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);
128void 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);
@@ -168,6 +169,7 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm)
168} 169}
169 170
170struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id); 171struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
172struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
171int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, 173int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
172 struct ipc_ops *ops, struct ipc_params *params); 174 struct ipc_ops *ops, struct ipc_params *params);
173void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, 175void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,