diff options
Diffstat (limited to 'ipc/msg.c')
| -rw-r--r-- | ipc/msg.c | 115 |
1 files changed, 70 insertions, 45 deletions
| @@ -75,13 +75,12 @@ static struct ipc_ids init_msg_ids; | |||
| 75 | 75 | ||
| 76 | #define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id)) | 76 | #define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id)) |
| 77 | #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) | 77 | #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) |
| 78 | #define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id)) | ||
| 79 | #define msg_checkid(ns, msq, msgid) \ | 78 | #define msg_checkid(ns, msq, msgid) \ |
| 80 | ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid) | 79 | ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid) |
| 81 | #define msg_buildid(ns, id, seq) \ | 80 | #define msg_buildid(ns, id, seq) \ |
| 82 | ipc_buildid(&msg_ids(ns), id, seq) | 81 | ipc_buildid(&msg_ids(ns), id, seq) |
| 83 | 82 | ||
| 84 | static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id); | 83 | static void freeque(struct ipc_namespace *, struct msg_queue *); |
| 85 | static int newque (struct ipc_namespace *ns, key_t key, int msgflg); | 84 | static int newque (struct ipc_namespace *ns, key_t key, int msgflg); |
| 86 | #ifdef CONFIG_PROC_FS | 85 | #ifdef CONFIG_PROC_FS |
| 87 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it); | 86 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it); |
| @@ -93,7 +92,7 @@ static void __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) | |||
| 93 | ns->msg_ctlmax = MSGMAX; | 92 | ns->msg_ctlmax = MSGMAX; |
| 94 | ns->msg_ctlmnb = MSGMNB; | 93 | ns->msg_ctlmnb = MSGMNB; |
| 95 | ns->msg_ctlmni = MSGMNI; | 94 | ns->msg_ctlmni = MSGMNI; |
| 96 | ipc_init_ids(ids, ns->msg_ctlmni); | 95 | ipc_init_ids(ids); |
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | int msg_init_ns(struct ipc_namespace *ns) | 98 | int msg_init_ns(struct ipc_namespace *ns) |
| @@ -110,20 +109,24 @@ int msg_init_ns(struct ipc_namespace *ns) | |||
| 110 | 109 | ||
| 111 | void msg_exit_ns(struct ipc_namespace *ns) | 110 | void msg_exit_ns(struct ipc_namespace *ns) |
| 112 | { | 111 | { |
| 113 | int i; | ||
| 114 | struct msg_queue *msq; | 112 | struct msg_queue *msq; |
| 113 | int next_id; | ||
| 114 | int total, in_use; | ||
| 115 | 115 | ||
| 116 | mutex_lock(&msg_ids(ns).mutex); | 116 | mutex_lock(&msg_ids(ns).mutex); |
| 117 | for (i = 0; i <= msg_ids(ns).max_id; i++) { | 117 | |
| 118 | msq = msg_lock(ns, i); | 118 | in_use = msg_ids(ns).in_use; |
| 119 | |||
| 120 | for (total = 0, next_id = 0; total < in_use; next_id++) { | ||
| 121 | msq = idr_find(&msg_ids(ns).ipcs_idr, next_id); | ||
| 119 | if (msq == NULL) | 122 | if (msq == NULL) |
| 120 | continue; | 123 | continue; |
| 121 | 124 | ipc_lock_by_ptr(&msq->q_perm); | |
| 122 | freeque(ns, msq, i); | 125 | freeque(ns, msq); |
| 126 | total++; | ||
| 123 | } | 127 | } |
| 124 | mutex_unlock(&msg_ids(ns).mutex); | 128 | mutex_unlock(&msg_ids(ns).mutex); |
| 125 | 129 | ||
| 126 | ipc_fini_ids(ns->ids[IPC_MSG_IDS]); | ||
| 127 | kfree(ns->ids[IPC_MSG_IDS]); | 130 | kfree(ns->ids[IPC_MSG_IDS]); |
| 128 | ns->ids[IPC_MSG_IDS] = NULL; | 131 | ns->ids[IPC_MSG_IDS] = NULL; |
| 129 | } | 132 | } |
| @@ -136,6 +139,11 @@ void __init msg_init(void) | |||
| 136 | IPC_MSG_IDS, sysvipc_msg_proc_show); | 139 | IPC_MSG_IDS, sysvipc_msg_proc_show); |
| 137 | } | 140 | } |
| 138 | 141 | ||
| 142 | static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s) | ||
| 143 | { | ||
| 144 | ipc_rmid(&msg_ids(ns), &s->q_perm); | ||
| 145 | } | ||
| 146 | |||
| 139 | static int newque (struct ipc_namespace *ns, key_t key, int msgflg) | 147 | static int newque (struct ipc_namespace *ns, key_t key, int msgflg) |
| 140 | { | 148 | { |
| 141 | struct msg_queue *msq; | 149 | struct msg_queue *msq; |
| @@ -155,6 +163,9 @@ static int newque (struct ipc_namespace *ns, key_t key, int msgflg) | |||
| 155 | return retval; | 163 | return retval; |
| 156 | } | 164 | } |
| 157 | 165 | ||
| 166 | /* | ||
| 167 | * ipc_addid() locks msq | ||
| 168 | */ | ||
| 158 | id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); | 169 | id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); |
| 159 | if (id == -1) { | 170 | if (id == -1) { |
| 160 | security_msg_queue_free(msq); | 171 | security_msg_queue_free(msq); |
| @@ -162,7 +173,7 @@ static int newque (struct ipc_namespace *ns, key_t key, int msgflg) | |||
| 162 | return -ENOSPC; | 173 | return -ENOSPC; |
| 163 | } | 174 | } |
| 164 | 175 | ||
| 165 | msq->q_id = msg_buildid(ns, id, msq->q_perm.seq); | 176 | msq->q_perm.id = msg_buildid(ns, id, msq->q_perm.seq); |
| 166 | msq->q_stime = msq->q_rtime = 0; | 177 | msq->q_stime = msq->q_rtime = 0; |
| 167 | msq->q_ctime = get_seconds(); | 178 | msq->q_ctime = get_seconds(); |
| 168 | msq->q_cbytes = msq->q_qnum = 0; | 179 | msq->q_cbytes = msq->q_qnum = 0; |
| @@ -171,9 +182,10 @@ static int newque (struct ipc_namespace *ns, key_t key, int msgflg) | |||
| 171 | INIT_LIST_HEAD(&msq->q_messages); | 182 | INIT_LIST_HEAD(&msq->q_messages); |
| 172 | INIT_LIST_HEAD(&msq->q_receivers); | 183 | INIT_LIST_HEAD(&msq->q_receivers); |
| 173 | INIT_LIST_HEAD(&msq->q_senders); | 184 | INIT_LIST_HEAD(&msq->q_senders); |
| 185 | |||
| 174 | msg_unlock(msq); | 186 | msg_unlock(msq); |
| 175 | 187 | ||
| 176 | return msq->q_id; | 188 | return msq->q_perm.id; |
| 177 | } | 189 | } |
| 178 | 190 | ||
| 179 | static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss) | 191 | static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss) |
| @@ -225,18 +237,18 @@ static void expunge_all(struct msg_queue *msq, int res) | |||
| 225 | /* | 237 | /* |
| 226 | * freeque() wakes up waiters on the sender and receiver waiting queue, | 238 | * freeque() wakes up waiters on the sender and receiver waiting queue, |
| 227 | * removes the message queue from message queue ID | 239 | * removes the message queue from message queue ID |
| 228 | * array, and cleans up all the messages associated with this queue. | 240 | * IDR, and cleans up all the messages associated with this queue. |
| 229 | * | 241 | * |
| 230 | * msg_ids.mutex and the spinlock for this message queue is hold | 242 | * msg_ids.mutex and the spinlock for this message queue are held |
| 231 | * before freeque() is called. msg_ids.mutex remains locked on exit. | 243 | * before freeque() is called. msg_ids.mutex remains locked on exit. |
| 232 | */ | 244 | */ |
| 233 | static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id) | 245 | static void freeque(struct ipc_namespace *ns, struct msg_queue *msq) |
| 234 | { | 246 | { |
| 235 | struct list_head *tmp; | 247 | struct list_head *tmp; |
| 236 | 248 | ||
| 237 | expunge_all(msq, -EIDRM); | 249 | expunge_all(msq, -EIDRM); |
| 238 | ss_wakeup(&msq->q_senders, 1); | 250 | ss_wakeup(&msq->q_senders, 1); |
| 239 | msq = msg_rmid(ns, id); | 251 | msg_rmid(ns, msq); |
| 240 | msg_unlock(msq); | 252 | msg_unlock(msq); |
| 241 | 253 | ||
| 242 | tmp = msq->q_messages.next; | 254 | tmp = msq->q_messages.next; |
| @@ -255,36 +267,51 @@ static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id) | |||
| 255 | asmlinkage long sys_msgget(key_t key, int msgflg) | 267 | asmlinkage long sys_msgget(key_t key, int msgflg) |
| 256 | { | 268 | { |
| 257 | struct msg_queue *msq; | 269 | struct msg_queue *msq; |
| 258 | int id, ret = -EPERM; | 270 | int ret; |
| 259 | struct ipc_namespace *ns; | 271 | struct ipc_namespace *ns; |
| 260 | 272 | ||
| 261 | ns = current->nsproxy->ipc_ns; | 273 | ns = current->nsproxy->ipc_ns; |
| 262 | 274 | ||
| 263 | mutex_lock(&msg_ids(ns).mutex); | 275 | ret = idr_pre_get(&msg_ids(ns).ipcs_idr, GFP_KERNEL); |
| 264 | if (key == IPC_PRIVATE) | 276 | |
| 265 | ret = newque(ns, key, msgflg); | 277 | if (key == IPC_PRIVATE) { |
| 266 | else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */ | 278 | if (!ret) |
| 267 | if (!(msgflg & IPC_CREAT)) | 279 | ret = -ENOMEM; |
| 268 | ret = -ENOENT; | 280 | else { |
| 269 | else | 281 | mutex_lock(&msg_ids(ns).mutex); |
| 270 | ret = newque(ns, key, msgflg); | 282 | ret = newque(ns, key, msgflg); |
| 271 | } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { | 283 | mutex_unlock(&msg_ids(ns).mutex); |
| 272 | ret = -EEXIST; | 284 | } |
| 273 | } else { | 285 | } else { |
| 274 | msq = msg_lock(ns, id); | 286 | mutex_lock(&msg_ids(ns).mutex); |
| 275 | BUG_ON(msq == NULL); | 287 | msq = (struct msg_queue *) ipc_findkey(&msg_ids(ns), key); |
| 276 | if (ipcperms(&msq->q_perm, msgflg)) | 288 | if (msq == NULL) { |
| 277 | ret = -EACCES; | 289 | /* key not used */ |
| 278 | else { | 290 | if (!(msgflg & IPC_CREAT)) |
| 279 | int qid = msg_buildid(ns, id, msq->q_perm.seq); | 291 | ret = -ENOENT; |
| 280 | 292 | else if (!ret) | |
| 281 | ret = security_msg_queue_associate(msq, msgflg); | 293 | ret = -ENOMEM; |
| 282 | if (!ret) | 294 | else |
| 283 | ret = qid; | 295 | ret = newque(ns, key, msgflg); |
| 296 | } else { | ||
| 297 | /* msq has been locked by ipc_findkey() */ | ||
| 298 | |||
| 299 | if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) | ||
| 300 | ret = -EEXIST; | ||
| 301 | else { | ||
| 302 | if (ipcperms(&msq->q_perm, msgflg)) | ||
| 303 | ret = -EACCES; | ||
| 304 | else { | ||
| 305 | ret = security_msg_queue_associate( | ||
| 306 | msq, msgflg); | ||
| 307 | if (!ret) | ||
| 308 | ret = msq->q_perm.id; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | msg_unlock(msq); | ||
| 284 | } | 312 | } |
| 285 | msg_unlock(msq); | 313 | mutex_unlock(&msg_ids(ns).mutex); |
| 286 | } | 314 | } |
| 287 | mutex_unlock(&msg_ids(ns).mutex); | ||
| 288 | 315 | ||
| 289 | return ret; | 316 | return ret; |
| 290 | } | 317 | } |
| @@ -430,13 +457,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 430 | msginfo.msgpool = MSGPOOL; | 457 | msginfo.msgpool = MSGPOOL; |
| 431 | msginfo.msgtql = MSGTQL; | 458 | msginfo.msgtql = MSGTQL; |
| 432 | } | 459 | } |
| 433 | max_id = msg_ids(ns).max_id; | 460 | max_id = ipc_get_maxid(&msg_ids(ns)); |
| 434 | mutex_unlock(&msg_ids(ns).mutex); | 461 | mutex_unlock(&msg_ids(ns).mutex); |
| 435 | if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) | 462 | if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) |
| 436 | return -EFAULT; | 463 | return -EFAULT; |
| 437 | return (max_id < 0) ? 0 : max_id; | 464 | return (max_id < 0) ? 0 : max_id; |
| 438 | } | 465 | } |
| 439 | case MSG_STAT: | 466 | case MSG_STAT: /* msqid is an index rather than a msg queue id */ |
| 440 | case IPC_STAT: | 467 | case IPC_STAT: |
| 441 | { | 468 | { |
| 442 | struct msqid64_ds tbuf; | 469 | struct msqid64_ds tbuf; |
| @@ -444,8 +471,6 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 444 | 471 | ||
| 445 | if (!buf) | 472 | if (!buf) |
| 446 | return -EFAULT; | 473 | return -EFAULT; |
| 447 | if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size) | ||
| 448 | return -EINVAL; | ||
| 449 | 474 | ||
| 450 | memset(&tbuf, 0, sizeof(tbuf)); | 475 | memset(&tbuf, 0, sizeof(tbuf)); |
| 451 | 476 | ||
| @@ -454,7 +479,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 454 | return -EINVAL; | 479 | return -EINVAL; |
| 455 | 480 | ||
| 456 | if (cmd == MSG_STAT) { | 481 | if (cmd == MSG_STAT) { |
| 457 | success_return = msg_buildid(ns, msqid, msq->q_perm.seq); | 482 | success_return = msq->q_perm.id; |
| 458 | } else { | 483 | } else { |
| 459 | err = -EIDRM; | 484 | err = -EIDRM; |
| 460 | if (msg_checkid(ns, msq, msqid)) | 485 | if (msg_checkid(ns, msq, msqid)) |
| @@ -552,7 +577,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 552 | break; | 577 | break; |
| 553 | } | 578 | } |
| 554 | case IPC_RMID: | 579 | case IPC_RMID: |
| 555 | freeque(ns, msq, msqid); | 580 | freeque(ns, msq); |
| 556 | break; | 581 | break; |
| 557 | } | 582 | } |
| 558 | err = 0; | 583 | err = 0; |
| @@ -926,7 +951,7 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it) | |||
| 926 | return seq_printf(s, | 951 | return seq_printf(s, |
| 927 | "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", | 952 | "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", |
| 928 | msq->q_perm.key, | 953 | msq->q_perm.key, |
| 929 | msq->q_id, | 954 | msq->q_perm.id, |
| 930 | msq->q_perm.mode, | 955 | msq->q_perm.mode, |
| 931 | msq->q_cbytes, | 956 | msq->q_cbytes, |
| 932 | msq->q_qnum, | 957 | msq->q_qnum, |
