diff options
Diffstat (limited to 'ipc/msg.c')
-rw-r--r-- | ipc/msg.c | 32 |
1 files changed, 26 insertions, 6 deletions
@@ -165,6 +165,15 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s) | |||
165 | ipc_rmid(&msg_ids(ns), &s->q_perm); | 165 | ipc_rmid(&msg_ids(ns), &s->q_perm); |
166 | } | 166 | } |
167 | 167 | ||
168 | static void msg_rcu_free(struct rcu_head *head) | ||
169 | { | ||
170 | struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu); | ||
171 | struct msg_queue *msq = ipc_rcu_to_struct(p); | ||
172 | |||
173 | security_msg_queue_free(msq); | ||
174 | ipc_rcu_free(head); | ||
175 | } | ||
176 | |||
168 | /** | 177 | /** |
169 | * newque - Create a new msg queue | 178 | * newque - Create a new msg queue |
170 | * @ns: namespace | 179 | * @ns: namespace |
@@ -189,15 +198,14 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) | |||
189 | msq->q_perm.security = NULL; | 198 | msq->q_perm.security = NULL; |
190 | retval = security_msg_queue_alloc(msq); | 199 | retval = security_msg_queue_alloc(msq); |
191 | if (retval) { | 200 | if (retval) { |
192 | ipc_rcu_putref(msq); | 201 | ipc_rcu_putref(msq, ipc_rcu_free); |
193 | return retval; | 202 | return retval; |
194 | } | 203 | } |
195 | 204 | ||
196 | /* ipc_addid() locks msq upon success. */ | 205 | /* ipc_addid() locks msq upon success. */ |
197 | id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); | 206 | id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); |
198 | if (id < 0) { | 207 | if (id < 0) { |
199 | security_msg_queue_free(msq); | 208 | ipc_rcu_putref(msq, msg_rcu_free); |
200 | ipc_rcu_putref(msq); | ||
201 | return id; | 209 | return id; |
202 | } | 210 | } |
203 | 211 | ||
@@ -276,8 +284,7 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
276 | free_msg(msg); | 284 | free_msg(msg); |
277 | } | 285 | } |
278 | atomic_sub(msq->q_cbytes, &ns->msg_bytes); | 286 | atomic_sub(msq->q_cbytes, &ns->msg_bytes); |
279 | security_msg_queue_free(msq); | 287 | ipc_rcu_putref(msq, msg_rcu_free); |
280 | ipc_rcu_putref(msq); | ||
281 | } | 288 | } |
282 | 289 | ||
283 | /* | 290 | /* |
@@ -688,6 +695,12 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
688 | if (ipcperms(ns, &msq->q_perm, S_IWUGO)) | 695 | if (ipcperms(ns, &msq->q_perm, S_IWUGO)) |
689 | goto out_unlock0; | 696 | goto out_unlock0; |
690 | 697 | ||
698 | /* raced with RMID? */ | ||
699 | if (msq->q_perm.deleted) { | ||
700 | err = -EIDRM; | ||
701 | goto out_unlock0; | ||
702 | } | ||
703 | |||
691 | err = security_msg_queue_msgsnd(msq, msg, msgflg); | 704 | err = security_msg_queue_msgsnd(msq, msg, msgflg); |
692 | if (err) | 705 | if (err) |
693 | goto out_unlock0; | 706 | goto out_unlock0; |
@@ -717,7 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
717 | rcu_read_lock(); | 730 | rcu_read_lock(); |
718 | ipc_lock_object(&msq->q_perm); | 731 | ipc_lock_object(&msq->q_perm); |
719 | 732 | ||
720 | ipc_rcu_putref(msq); | 733 | ipc_rcu_putref(msq, ipc_rcu_free); |
721 | if (msq->q_perm.deleted) { | 734 | if (msq->q_perm.deleted) { |
722 | err = -EIDRM; | 735 | err = -EIDRM; |
723 | goto out_unlock0; | 736 | goto out_unlock0; |
@@ -894,6 +907,13 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
894 | goto out_unlock1; | 907 | goto out_unlock1; |
895 | 908 | ||
896 | ipc_lock_object(&msq->q_perm); | 909 | ipc_lock_object(&msq->q_perm); |
910 | |||
911 | /* raced with RMID? */ | ||
912 | if (msq->q_perm.deleted) { | ||
913 | msg = ERR_PTR(-EIDRM); | ||
914 | goto out_unlock0; | ||
915 | } | ||
916 | |||
897 | msg = find_msg(msq, &msgtyp, mode); | 917 | msg = find_msg(msq, &msgtyp, mode); |
898 | if (!IS_ERR(msg)) { | 918 | if (!IS_ERR(msg)) { |
899 | /* | 919 | /* |