diff options
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/compat.c | 30 | ||||
| -rw-r--r-- | ipc/compat_mq.c | 2 | ||||
| -rw-r--r-- | ipc/ipc_sysctl.c | 14 | ||||
| -rw-r--r-- | ipc/mq_sysctl.c | 18 | ||||
| -rw-r--r-- | ipc/mqueue.c | 28 | ||||
| -rw-r--r-- | ipc/msg.c | 44 | ||||
| -rw-r--r-- | ipc/sem.c | 178 | ||||
| -rw-r--r-- | ipc/shm.c | 49 | ||||
| -rw-r--r-- | ipc/util.c | 290 | ||||
| -rw-r--r-- | ipc/util.h | 28 |
10 files changed, 348 insertions, 333 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index 892f6585dd60..f486b0096a67 100644 --- a/ipc/compat.c +++ b/ipc/compat.c | |||
| @@ -197,7 +197,7 @@ static inline int __put_compat_ipc_perm(struct ipc64_perm *p, | |||
| 197 | static inline int get_compat_semid64_ds(struct semid64_ds *s64, | 197 | static inline int get_compat_semid64_ds(struct semid64_ds *s64, |
| 198 | struct compat_semid64_ds __user *up64) | 198 | struct compat_semid64_ds __user *up64) |
| 199 | { | 199 | { |
| 200 | if (!access_ok (VERIFY_READ, up64, sizeof(*up64))) | 200 | if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) |
| 201 | return -EFAULT; | 201 | return -EFAULT; |
| 202 | return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); | 202 | return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); |
| 203 | } | 203 | } |
| @@ -205,7 +205,7 @@ static inline int get_compat_semid64_ds(struct semid64_ds *s64, | |||
| 205 | static inline int get_compat_semid_ds(struct semid64_ds *s, | 205 | static inline int get_compat_semid_ds(struct semid64_ds *s, |
| 206 | struct compat_semid_ds __user *up) | 206 | struct compat_semid_ds __user *up) |
| 207 | { | 207 | { |
| 208 | if (!access_ok (VERIFY_READ, up, sizeof(*up))) | 208 | if (!access_ok(VERIFY_READ, up, sizeof(*up))) |
| 209 | return -EFAULT; | 209 | return -EFAULT; |
| 210 | return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); | 210 | return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); |
| 211 | } | 211 | } |
| @@ -215,7 +215,7 @@ static inline int put_compat_semid64_ds(struct semid64_ds *s64, | |||
| 215 | { | 215 | { |
| 216 | int err; | 216 | int err; |
| 217 | 217 | ||
| 218 | if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64))) | 218 | if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) |
| 219 | return -EFAULT; | 219 | return -EFAULT; |
| 220 | err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); | 220 | err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); |
| 221 | err |= __put_user(s64->sem_otime, &up64->sem_otime); | 221 | err |= __put_user(s64->sem_otime, &up64->sem_otime); |
| @@ -229,7 +229,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s, | |||
| 229 | { | 229 | { |
| 230 | int err; | 230 | int err; |
| 231 | 231 | ||
| 232 | if (!access_ok (VERIFY_WRITE, up, sizeof(*up))) | 232 | if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) |
| 233 | return -EFAULT; | 233 | return -EFAULT; |
| 234 | err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); | 234 | err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); |
| 235 | err |= __put_user(s->sem_otime, &up->sem_otime); | 235 | err |= __put_user(s->sem_otime, &up->sem_otime); |
| @@ -288,11 +288,11 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) | |||
| 288 | break; | 288 | break; |
| 289 | 289 | ||
| 290 | case IPC_SET: | 290 | case IPC_SET: |
| 291 | if (version == IPC_64) { | 291 | if (version == IPC_64) |
| 292 | err = get_compat_semid64_ds(&s64, compat_ptr(pad)); | 292 | err = get_compat_semid64_ds(&s64, compat_ptr(pad)); |
| 293 | } else { | 293 | else |
| 294 | err = get_compat_semid_ds(&s64, compat_ptr(pad)); | 294 | err = get_compat_semid_ds(&s64, compat_ptr(pad)); |
| 295 | } | 295 | |
| 296 | up64 = compat_alloc_user_space(sizeof(s64)); | 296 | up64 = compat_alloc_user_space(sizeof(s64)); |
| 297 | if (copy_to_user(up64, &s64, sizeof(s64))) | 297 | if (copy_to_user(up64, &s64, sizeof(s64))) |
| 298 | err = -EFAULT; | 298 | err = -EFAULT; |
| @@ -376,12 +376,12 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, | |||
| 376 | struct compat_ipc_kludge ipck; | 376 | struct compat_ipc_kludge ipck; |
| 377 | if (!uptr) | 377 | if (!uptr) |
| 378 | return -EINVAL; | 378 | return -EINVAL; |
| 379 | if (copy_from_user (&ipck, uptr, sizeof(ipck))) | 379 | if (copy_from_user(&ipck, uptr, sizeof(ipck))) |
| 380 | return -EFAULT; | 380 | return -EFAULT; |
| 381 | uptr = compat_ptr(ipck.msgp); | 381 | uptr = compat_ptr(ipck.msgp); |
| 382 | fifth = ipck.msgtyp; | 382 | fifth = ipck.msgtyp; |
| 383 | } | 383 | } |
| 384 | return do_msgrcv(first, uptr, second, fifth, third, | 384 | return do_msgrcv(first, uptr, second, (s32)fifth, third, |
| 385 | compat_do_msg_fill); | 385 | compat_do_msg_fill); |
| 386 | } | 386 | } |
| 387 | case MSGGET: | 387 | case MSGGET: |
| @@ -515,11 +515,11 @@ long compat_sys_msgctl(int first, int second, void __user *uptr) | |||
| 515 | break; | 515 | break; |
| 516 | 516 | ||
| 517 | case IPC_SET: | 517 | case IPC_SET: |
| 518 | if (version == IPC_64) { | 518 | if (version == IPC_64) |
| 519 | err = get_compat_msqid64(&m64, uptr); | 519 | err = get_compat_msqid64(&m64, uptr); |
| 520 | } else { | 520 | else |
| 521 | err = get_compat_msqid(&m64, uptr); | 521 | err = get_compat_msqid(&m64, uptr); |
| 522 | } | 522 | |
| 523 | if (err) | 523 | if (err) |
| 524 | break; | 524 | break; |
| 525 | p = compat_alloc_user_space(sizeof(m64)); | 525 | p = compat_alloc_user_space(sizeof(m64)); |
| @@ -702,11 +702,11 @@ long compat_sys_shmctl(int first, int second, void __user *uptr) | |||
| 702 | 702 | ||
| 703 | 703 | ||
| 704 | case IPC_SET: | 704 | case IPC_SET: |
| 705 | if (version == IPC_64) { | 705 | if (version == IPC_64) |
| 706 | err = get_compat_shmid64_ds(&s64, uptr); | 706 | err = get_compat_shmid64_ds(&s64, uptr); |
| 707 | } else { | 707 | else |
| 708 | err = get_compat_shmid_ds(&s64, uptr); | 708 | err = get_compat_shmid_ds(&s64, uptr); |
| 709 | } | 709 | |
| 710 | if (err) | 710 | if (err) |
| 711 | break; | 711 | break; |
| 712 | p = compat_alloc_user_space(sizeof(s64)); | 712 | p = compat_alloc_user_space(sizeof(s64)); |
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c index 380ea4fe08e7..63d7c6de335b 100644 --- a/ipc/compat_mq.c +++ b/ipc/compat_mq.c | |||
| @@ -64,7 +64,7 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name, | |||
| 64 | return sys_mq_open(u_name, oflag, mode, p); | 64 | return sys_mq_open(u_name, oflag, mode, p); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static int compat_prepare_timeout(struct timespec __user * *p, | 67 | static int compat_prepare_timeout(struct timespec __user **p, |
| 68 | const struct compat_timespec __user *u) | 68 | const struct compat_timespec __user *u) |
| 69 | { | 69 | { |
| 70 | struct timespec ts; | 70 | struct timespec ts; |
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index b0e99deb6d05..17028648cfeb 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c | |||
| @@ -164,21 +164,21 @@ static struct ctl_table ipc_kern_table[] = { | |||
| 164 | { | 164 | { |
| 165 | .procname = "shmmax", | 165 | .procname = "shmmax", |
| 166 | .data = &init_ipc_ns.shm_ctlmax, | 166 | .data = &init_ipc_ns.shm_ctlmax, |
| 167 | .maxlen = sizeof (init_ipc_ns.shm_ctlmax), | 167 | .maxlen = sizeof(init_ipc_ns.shm_ctlmax), |
| 168 | .mode = 0644, | 168 | .mode = 0644, |
| 169 | .proc_handler = proc_ipc_doulongvec_minmax, | 169 | .proc_handler = proc_ipc_doulongvec_minmax, |
| 170 | }, | 170 | }, |
| 171 | { | 171 | { |
| 172 | .procname = "shmall", | 172 | .procname = "shmall", |
| 173 | .data = &init_ipc_ns.shm_ctlall, | 173 | .data = &init_ipc_ns.shm_ctlall, |
| 174 | .maxlen = sizeof (init_ipc_ns.shm_ctlall), | 174 | .maxlen = sizeof(init_ipc_ns.shm_ctlall), |
| 175 | .mode = 0644, | 175 | .mode = 0644, |
| 176 | .proc_handler = proc_ipc_doulongvec_minmax, | 176 | .proc_handler = proc_ipc_doulongvec_minmax, |
| 177 | }, | 177 | }, |
| 178 | { | 178 | { |
| 179 | .procname = "shmmni", | 179 | .procname = "shmmni", |
| 180 | .data = &init_ipc_ns.shm_ctlmni, | 180 | .data = &init_ipc_ns.shm_ctlmni, |
| 181 | .maxlen = sizeof (init_ipc_ns.shm_ctlmni), | 181 | .maxlen = sizeof(init_ipc_ns.shm_ctlmni), |
| 182 | .mode = 0644, | 182 | .mode = 0644, |
| 183 | .proc_handler = proc_ipc_dointvec, | 183 | .proc_handler = proc_ipc_dointvec, |
| 184 | }, | 184 | }, |
| @@ -194,7 +194,7 @@ static struct ctl_table ipc_kern_table[] = { | |||
| 194 | { | 194 | { |
| 195 | .procname = "msgmax", | 195 | .procname = "msgmax", |
| 196 | .data = &init_ipc_ns.msg_ctlmax, | 196 | .data = &init_ipc_ns.msg_ctlmax, |
| 197 | .maxlen = sizeof (init_ipc_ns.msg_ctlmax), | 197 | .maxlen = sizeof(init_ipc_ns.msg_ctlmax), |
| 198 | .mode = 0644, | 198 | .mode = 0644, |
| 199 | .proc_handler = proc_ipc_dointvec_minmax, | 199 | .proc_handler = proc_ipc_dointvec_minmax, |
| 200 | .extra1 = &zero, | 200 | .extra1 = &zero, |
| @@ -203,7 +203,7 @@ static struct ctl_table ipc_kern_table[] = { | |||
| 203 | { | 203 | { |
| 204 | .procname = "msgmni", | 204 | .procname = "msgmni", |
| 205 | .data = &init_ipc_ns.msg_ctlmni, | 205 | .data = &init_ipc_ns.msg_ctlmni, |
| 206 | .maxlen = sizeof (init_ipc_ns.msg_ctlmni), | 206 | .maxlen = sizeof(init_ipc_ns.msg_ctlmni), |
| 207 | .mode = 0644, | 207 | .mode = 0644, |
| 208 | .proc_handler = proc_ipc_callback_dointvec_minmax, | 208 | .proc_handler = proc_ipc_callback_dointvec_minmax, |
| 209 | .extra1 = &zero, | 209 | .extra1 = &zero, |
| @@ -212,7 +212,7 @@ static struct ctl_table ipc_kern_table[] = { | |||
| 212 | { | 212 | { |
| 213 | .procname = "msgmnb", | 213 | .procname = "msgmnb", |
| 214 | .data = &init_ipc_ns.msg_ctlmnb, | 214 | .data = &init_ipc_ns.msg_ctlmnb, |
| 215 | .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), | 215 | .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), |
| 216 | .mode = 0644, | 216 | .mode = 0644, |
| 217 | .proc_handler = proc_ipc_dointvec_minmax, | 217 | .proc_handler = proc_ipc_dointvec_minmax, |
| 218 | .extra1 = &zero, | 218 | .extra1 = &zero, |
| @@ -221,7 +221,7 @@ static struct ctl_table ipc_kern_table[] = { | |||
| 221 | { | 221 | { |
| 222 | .procname = "sem", | 222 | .procname = "sem", |
| 223 | .data = &init_ipc_ns.sem_ctls, | 223 | .data = &init_ipc_ns.sem_ctls, |
| 224 | .maxlen = 4*sizeof (int), | 224 | .maxlen = 4*sizeof(int), |
| 225 | .mode = 0644, | 225 | .mode = 0644, |
| 226 | .proc_handler = proc_ipc_dointvec, | 226 | .proc_handler = proc_ipc_dointvec, |
| 227 | }, | 227 | }, |
diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c index 383d638340b8..5bb8bfe67149 100644 --- a/ipc/mq_sysctl.c +++ b/ipc/mq_sysctl.c | |||
| @@ -22,6 +22,16 @@ static void *get_mq(ctl_table *table) | |||
| 22 | return which; | 22 | return which; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | static int proc_mq_dointvec(ctl_table *table, int write, | ||
| 26 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 27 | { | ||
| 28 | struct ctl_table mq_table; | ||
| 29 | memcpy(&mq_table, table, sizeof(mq_table)); | ||
| 30 | mq_table.data = get_mq(table); | ||
| 31 | |||
| 32 | return proc_dointvec(&mq_table, write, buffer, lenp, ppos); | ||
| 33 | } | ||
| 34 | |||
| 25 | static int proc_mq_dointvec_minmax(ctl_table *table, int write, | 35 | static int proc_mq_dointvec_minmax(ctl_table *table, int write, |
| 26 | void __user *buffer, size_t *lenp, loff_t *ppos) | 36 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 27 | { | 37 | { |
| @@ -33,12 +43,10 @@ static int proc_mq_dointvec_minmax(ctl_table *table, int write, | |||
| 33 | lenp, ppos); | 43 | lenp, ppos); |
| 34 | } | 44 | } |
| 35 | #else | 45 | #else |
| 46 | #define proc_mq_dointvec NULL | ||
| 36 | #define proc_mq_dointvec_minmax NULL | 47 | #define proc_mq_dointvec_minmax NULL |
| 37 | #endif | 48 | #endif |
| 38 | 49 | ||
| 39 | static int msg_queues_limit_min = MIN_QUEUESMAX; | ||
| 40 | static int msg_queues_limit_max = HARD_QUEUESMAX; | ||
| 41 | |||
| 42 | static int msg_max_limit_min = MIN_MSGMAX; | 50 | static int msg_max_limit_min = MIN_MSGMAX; |
| 43 | static int msg_max_limit_max = HARD_MSGMAX; | 51 | static int msg_max_limit_max = HARD_MSGMAX; |
| 44 | 52 | ||
| @@ -51,9 +59,7 @@ static ctl_table mq_sysctls[] = { | |||
| 51 | .data = &init_ipc_ns.mq_queues_max, | 59 | .data = &init_ipc_ns.mq_queues_max, |
| 52 | .maxlen = sizeof(int), | 60 | .maxlen = sizeof(int), |
| 53 | .mode = 0644, | 61 | .mode = 0644, |
| 54 | .proc_handler = proc_mq_dointvec_minmax, | 62 | .proc_handler = proc_mq_dointvec, |
| 55 | .extra1 = &msg_queues_limit_min, | ||
| 56 | .extra2 = &msg_queues_limit_max, | ||
| 57 | }, | 63 | }, |
| 58 | { | 64 | { |
| 59 | .procname = "msg_max", | 65 | .procname = "msg_max", |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 95827ce2f3c7..c3b31179122c 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * | 6 | * |
| 7 | * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com) | 7 | * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com) |
| 8 | * Lockless receive & send, fd based notify: | 8 | * Lockless receive & send, fd based notify: |
| 9 | * Manfred Spraul (manfred@colorfullife.com) | 9 | * Manfred Spraul (manfred@colorfullife.com) |
| 10 | * | 10 | * |
| 11 | * Audit: George Wilson (ltcgcw@us.ibm.com) | 11 | * Audit: George Wilson (ltcgcw@us.ibm.com) |
| 12 | * | 12 | * |
| @@ -73,7 +73,7 @@ struct mqueue_inode_info { | |||
| 73 | struct mq_attr attr; | 73 | struct mq_attr attr; |
| 74 | 74 | ||
| 75 | struct sigevent notify; | 75 | struct sigevent notify; |
| 76 | struct pid* notify_owner; | 76 | struct pid *notify_owner; |
| 77 | struct user_namespace *notify_user_ns; | 77 | struct user_namespace *notify_user_ns; |
| 78 | struct user_struct *user; /* user who created, for accounting */ | 78 | struct user_struct *user; /* user who created, for accounting */ |
| 79 | struct sock *notify_sock; | 79 | struct sock *notify_sock; |
| @@ -92,7 +92,7 @@ static void remove_notification(struct mqueue_inode_info *info); | |||
| 92 | 92 | ||
| 93 | static struct kmem_cache *mqueue_inode_cachep; | 93 | static struct kmem_cache *mqueue_inode_cachep; |
| 94 | 94 | ||
| 95 | static struct ctl_table_header * mq_sysctl_table; | 95 | static struct ctl_table_header *mq_sysctl_table; |
| 96 | 96 | ||
| 97 | static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode) | 97 | static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode) |
| 98 | { | 98 | { |
| @@ -433,9 +433,9 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry, | |||
| 433 | error = -EACCES; | 433 | error = -EACCES; |
| 434 | goto out_unlock; | 434 | goto out_unlock; |
| 435 | } | 435 | } |
| 436 | if (ipc_ns->mq_queues_count >= HARD_QUEUESMAX || | 436 | |
| 437 | (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && | 437 | if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && |
| 438 | !capable(CAP_SYS_RESOURCE))) { | 438 | !capable(CAP_SYS_RESOURCE)) { |
| 439 | error = -ENOSPC; | 439 | error = -ENOSPC; |
| 440 | goto out_unlock; | 440 | goto out_unlock; |
| 441 | } | 441 | } |
| @@ -466,13 +466,13 @@ out_unlock: | |||
| 466 | 466 | ||
| 467 | static int mqueue_unlink(struct inode *dir, struct dentry *dentry) | 467 | static int mqueue_unlink(struct inode *dir, struct dentry *dentry) |
| 468 | { | 468 | { |
| 469 | struct inode *inode = dentry->d_inode; | 469 | struct inode *inode = dentry->d_inode; |
| 470 | 470 | ||
| 471 | dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; | 471 | dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; |
| 472 | dir->i_size -= DIRENT_SIZE; | 472 | dir->i_size -= DIRENT_SIZE; |
| 473 | drop_nlink(inode); | 473 | drop_nlink(inode); |
| 474 | dput(dentry); | 474 | dput(dentry); |
| 475 | return 0; | 475 | return 0; |
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | /* | 478 | /* |
| @@ -622,7 +622,7 @@ static struct ext_wait_queue *wq_get_first_waiter( | |||
| 622 | 622 | ||
| 623 | static inline void set_cookie(struct sk_buff *skb, char code) | 623 | static inline void set_cookie(struct sk_buff *skb, char code) |
| 624 | { | 624 | { |
| 625 | ((char*)skb->data)[NOTIFY_COOKIE_LEN-1] = code; | 625 | ((char *)skb->data)[NOTIFY_COOKIE_LEN-1] = code; |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | /* | 628 | /* |
| @@ -1303,11 +1303,11 @@ retry: | |||
| 1303 | out_fput: | 1303 | out_fput: |
| 1304 | fdput(f); | 1304 | fdput(f); |
| 1305 | out: | 1305 | out: |
| 1306 | if (sock) { | 1306 | if (sock) |
| 1307 | netlink_detachskb(sock, nc); | 1307 | netlink_detachskb(sock, nc); |
| 1308 | } else if (nc) { | 1308 | else if (nc) |
| 1309 | dev_kfree_skb(nc); | 1309 | dev_kfree_skb(nc); |
| 1310 | } | 1310 | |
| 1311 | return ret; | 1311 | return ret; |
| 1312 | } | 1312 | } |
| 1313 | 1313 | ||
| @@ -253,8 +253,14 @@ static void expunge_all(struct msg_queue *msq, int res) | |||
| 253 | struct msg_receiver *msr, *t; | 253 | struct msg_receiver *msr, *t; |
| 254 | 254 | ||
| 255 | list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { | 255 | list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { |
| 256 | msr->r_msg = NULL; | 256 | msr->r_msg = NULL; /* initialize expunge ordering */ |
| 257 | wake_up_process(msr->r_tsk); | 257 | wake_up_process(msr->r_tsk); |
| 258 | /* | ||
| 259 | * Ensure that the wakeup is visible before setting r_msg as | ||
| 260 | * the receiving end depends on it: either spinning on a nil, | ||
| 261 | * or dealing with -EAGAIN cases. See lockless receive part 1 | ||
| 262 | * and 2 in do_msgrcv(). | ||
| 263 | */ | ||
| 258 | smp_mb(); | 264 | smp_mb(); |
| 259 | msr->r_msg = ERR_PTR(res); | 265 | msr->r_msg = ERR_PTR(res); |
| 260 | } | 266 | } |
| @@ -318,7 +324,7 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) | |||
| 318 | static inline unsigned long | 324 | static inline unsigned long |
| 319 | copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) | 325 | copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) |
| 320 | { | 326 | { |
| 321 | switch(version) { | 327 | switch (version) { |
| 322 | case IPC_64: | 328 | case IPC_64: |
| 323 | return copy_to_user(buf, in, sizeof(*in)); | 329 | return copy_to_user(buf, in, sizeof(*in)); |
| 324 | case IPC_OLD: | 330 | case IPC_OLD: |
| @@ -363,7 +369,7 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) | |||
| 363 | static inline unsigned long | 369 | static inline unsigned long |
| 364 | copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) | 370 | copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) |
| 365 | { | 371 | { |
| 366 | switch(version) { | 372 | switch (version) { |
| 367 | case IPC_64: | 373 | case IPC_64: |
| 368 | if (copy_from_user(out, buf, sizeof(*out))) | 374 | if (copy_from_user(out, buf, sizeof(*out))) |
| 369 | return -EFAULT; | 375 | return -EFAULT; |
| @@ -375,9 +381,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) | |||
| 375 | if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) | 381 | if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) |
| 376 | return -EFAULT; | 382 | return -EFAULT; |
| 377 | 383 | ||
| 378 | out->msg_perm.uid = tbuf_old.msg_perm.uid; | 384 | out->msg_perm.uid = tbuf_old.msg_perm.uid; |
| 379 | out->msg_perm.gid = tbuf_old.msg_perm.gid; | 385 | out->msg_perm.gid = tbuf_old.msg_perm.gid; |
| 380 | out->msg_perm.mode = tbuf_old.msg_perm.mode; | 386 | out->msg_perm.mode = tbuf_old.msg_perm.mode; |
| 381 | 387 | ||
| 382 | if (tbuf_old.msg_qbytes == 0) | 388 | if (tbuf_old.msg_qbytes == 0) |
| 383 | out->msg_qbytes = tbuf_old.msg_lqbytes; | 389 | out->msg_qbytes = tbuf_old.msg_lqbytes; |
| @@ -606,13 +612,13 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) | |||
| 606 | 612 | ||
| 607 | static int testmsg(struct msg_msg *msg, long type, int mode) | 613 | static int testmsg(struct msg_msg *msg, long type, int mode) |
| 608 | { | 614 | { |
| 609 | switch(mode) | 615 | switch (mode) |
| 610 | { | 616 | { |
| 611 | case SEARCH_ANY: | 617 | case SEARCH_ANY: |
| 612 | case SEARCH_NUMBER: | 618 | case SEARCH_NUMBER: |
| 613 | return 1; | 619 | return 1; |
| 614 | case SEARCH_LESSEQUAL: | 620 | case SEARCH_LESSEQUAL: |
| 615 | if (msg->m_type <=type) | 621 | if (msg->m_type <= type) |
| 616 | return 1; | 622 | return 1; |
| 617 | break; | 623 | break; |
| 618 | case SEARCH_EQUAL: | 624 | case SEARCH_EQUAL: |
| @@ -638,15 +644,22 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) | |||
| 638 | 644 | ||
| 639 | list_del(&msr->r_list); | 645 | list_del(&msr->r_list); |
| 640 | if (msr->r_maxsize < msg->m_ts) { | 646 | if (msr->r_maxsize < msg->m_ts) { |
| 647 | /* initialize pipelined send ordering */ | ||
| 641 | msr->r_msg = NULL; | 648 | msr->r_msg = NULL; |
| 642 | wake_up_process(msr->r_tsk); | 649 | wake_up_process(msr->r_tsk); |
| 643 | smp_mb(); | 650 | smp_mb(); /* see barrier comment below */ |
| 644 | msr->r_msg = ERR_PTR(-E2BIG); | 651 | msr->r_msg = ERR_PTR(-E2BIG); |
| 645 | } else { | 652 | } else { |
| 646 | msr->r_msg = NULL; | 653 | msr->r_msg = NULL; |
| 647 | msq->q_lrpid = task_pid_vnr(msr->r_tsk); | 654 | msq->q_lrpid = task_pid_vnr(msr->r_tsk); |
| 648 | msq->q_rtime = get_seconds(); | 655 | msq->q_rtime = get_seconds(); |
| 649 | wake_up_process(msr->r_tsk); | 656 | wake_up_process(msr->r_tsk); |
| 657 | /* | ||
| 658 | * Ensure that the wakeup is visible before | ||
| 659 | * setting r_msg, as the receiving end depends | ||
| 660 | * on it. See lockless receive part 1 and 2 in | ||
| 661 | * do_msgrcv(). | ||
| 662 | */ | ||
| 650 | smp_mb(); | 663 | smp_mb(); |
| 651 | msr->r_msg = msg; | 664 | msr->r_msg = msg; |
| 652 | 665 | ||
| @@ -654,6 +667,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) | |||
| 654 | } | 667 | } |
| 655 | } | 668 | } |
| 656 | } | 669 | } |
| 670 | |||
| 657 | return 0; | 671 | return 0; |
| 658 | } | 672 | } |
| 659 | 673 | ||
| @@ -696,7 +710,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 696 | goto out_unlock0; | 710 | goto out_unlock0; |
| 697 | 711 | ||
| 698 | /* raced with RMID? */ | 712 | /* raced with RMID? */ |
| 699 | if (msq->q_perm.deleted) { | 713 | if (!ipc_valid_object(&msq->q_perm)) { |
| 700 | err = -EIDRM; | 714 | err = -EIDRM; |
| 701 | goto out_unlock0; | 715 | goto out_unlock0; |
| 702 | } | 716 | } |
| @@ -716,6 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 716 | goto out_unlock0; | 730 | goto out_unlock0; |
| 717 | } | 731 | } |
| 718 | 732 | ||
| 733 | /* enqueue the sender and prepare to block */ | ||
| 719 | ss_add(msq, &s); | 734 | ss_add(msq, &s); |
| 720 | 735 | ||
| 721 | if (!ipc_rcu_getref(msq)) { | 736 | if (!ipc_rcu_getref(msq)) { |
| @@ -731,7 +746,8 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 731 | ipc_lock_object(&msq->q_perm); | 746 | ipc_lock_object(&msq->q_perm); |
| 732 | 747 | ||
| 733 | ipc_rcu_putref(msq, ipc_rcu_free); | 748 | ipc_rcu_putref(msq, ipc_rcu_free); |
| 734 | if (msq->q_perm.deleted) { | 749 | /* raced with RMID? */ |
| 750 | if (!ipc_valid_object(&msq->q_perm)) { | ||
| 735 | err = -EIDRM; | 751 | err = -EIDRM; |
| 736 | goto out_unlock0; | 752 | goto out_unlock0; |
| 737 | } | 753 | } |
| @@ -909,7 +925,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
| 909 | ipc_lock_object(&msq->q_perm); | 925 | ipc_lock_object(&msq->q_perm); |
| 910 | 926 | ||
| 911 | /* raced with RMID? */ | 927 | /* raced with RMID? */ |
| 912 | if (msq->q_perm.deleted) { | 928 | if (!ipc_valid_object(&msq->q_perm)) { |
| 913 | msg = ERR_PTR(-EIDRM); | 929 | msg = ERR_PTR(-EIDRM); |
| 914 | goto out_unlock0; | 930 | goto out_unlock0; |
| 915 | } | 931 | } |
| @@ -983,7 +999,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
| 983 | * wake_up_process(). There is a race with exit(), see | 999 | * wake_up_process(). There is a race with exit(), see |
| 984 | * ipc/mqueue.c for the details. | 1000 | * ipc/mqueue.c for the details. |
| 985 | */ | 1001 | */ |
| 986 | msg = (struct msg_msg*)msr_d.r_msg; | 1002 | msg = (struct msg_msg *)msr_d.r_msg; |
| 987 | while (msg == NULL) { | 1003 | while (msg == NULL) { |
| 988 | cpu_relax(); | 1004 | cpu_relax(); |
| 989 | msg = (struct msg_msg *)msr_d.r_msg; | 1005 | msg = (struct msg_msg *)msr_d.r_msg; |
| @@ -1004,7 +1020,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
| 1004 | /* Lockless receive, part 4: | 1020 | /* Lockless receive, part 4: |
| 1005 | * Repeat test after acquiring the spinlock. | 1021 | * Repeat test after acquiring the spinlock. |
| 1006 | */ | 1022 | */ |
| 1007 | msg = (struct msg_msg*)msr_d.r_msg; | 1023 | msg = (struct msg_msg *)msr_d.r_msg; |
| 1008 | if (msg != ERR_PTR(-EAGAIN)) | 1024 | if (msg != ERR_PTR(-EAGAIN)) |
| 1009 | goto out_unlock0; | 1025 | goto out_unlock0; |
| 1010 | 1026 | ||
| @@ -188,7 +188,7 @@ void sem_exit_ns(struct ipc_namespace *ns) | |||
| 188 | } | 188 | } |
| 189 | #endif | 189 | #endif |
| 190 | 190 | ||
| 191 | void __init sem_init (void) | 191 | void __init sem_init(void) |
| 192 | { | 192 | { |
| 193 | sem_init_ns(&init_ipc_ns); | 193 | sem_init_ns(&init_ipc_ns); |
| 194 | ipc_init_proc_interface("sysvipc/sem", | 194 | ipc_init_proc_interface("sysvipc/sem", |
| @@ -225,7 +225,7 @@ static void unmerge_queues(struct sem_array *sma) | |||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | /** | 227 | /** |
| 228 | * merge_queues - Merge single semop queues into global queue | 228 | * merge_queues - merge single semop queues into global queue |
| 229 | * @sma: semaphore array | 229 | * @sma: semaphore array |
| 230 | * | 230 | * |
| 231 | * This function merges all per-semaphore queues into the global queue. | 231 | * This function merges all per-semaphore queues into the global queue. |
| @@ -394,7 +394,7 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns, | |||
| 394 | /* ipc_rmid() may have already freed the ID while sem_lock | 394 | /* ipc_rmid() may have already freed the ID while sem_lock |
| 395 | * was spinning: verify that the structure is still valid | 395 | * was spinning: verify that the structure is still valid |
| 396 | */ | 396 | */ |
| 397 | if (!ipcp->deleted) | 397 | if (ipc_valid_object(ipcp)) |
| 398 | return container_of(ipcp, struct sem_array, sem_perm); | 398 | return container_of(ipcp, struct sem_array, sem_perm); |
| 399 | 399 | ||
| 400 | sem_unlock(sma, *locknum); | 400 | sem_unlock(sma, *locknum); |
| @@ -445,11 +445,11 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) | |||
| 445 | * * call wake_up_process | 445 | * * call wake_up_process |
| 446 | * * set queue.status to the final value. | 446 | * * set queue.status to the final value. |
| 447 | * - the previously blocked thread checks queue.status: | 447 | * - the previously blocked thread checks queue.status: |
| 448 | * * if it's IN_WAKEUP, then it must wait until the value changes | 448 | * * if it's IN_WAKEUP, then it must wait until the value changes |
| 449 | * * if it's not -EINTR, then the operation was completed by | 449 | * * if it's not -EINTR, then the operation was completed by |
| 450 | * update_queue. semtimedop can return queue.status without | 450 | * update_queue. semtimedop can return queue.status without |
| 451 | * performing any operation on the sem array. | 451 | * performing any operation on the sem array. |
| 452 | * * otherwise it must acquire the spinlock and check what's up. | 452 | * * otherwise it must acquire the spinlock and check what's up. |
| 453 | * | 453 | * |
| 454 | * The two-stage algorithm is necessary to protect against the following | 454 | * The two-stage algorithm is necessary to protect against the following |
| 455 | * races: | 455 | * races: |
| @@ -474,7 +474,6 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) | |||
| 474 | * | 474 | * |
| 475 | * Called with sem_ids.rwsem held (as a writer) | 475 | * Called with sem_ids.rwsem held (as a writer) |
| 476 | */ | 476 | */ |
| 477 | |||
| 478 | static int newary(struct ipc_namespace *ns, struct ipc_params *params) | 477 | static int newary(struct ipc_namespace *ns, struct ipc_params *params) |
| 479 | { | 478 | { |
| 480 | int id; | 479 | int id; |
| @@ -491,12 +490,12 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 491 | if (ns->used_sems + nsems > ns->sc_semmns) | 490 | if (ns->used_sems + nsems > ns->sc_semmns) |
| 492 | return -ENOSPC; | 491 | return -ENOSPC; |
| 493 | 492 | ||
| 494 | size = sizeof (*sma) + nsems * sizeof (struct sem); | 493 | size = sizeof(*sma) + nsems * sizeof(struct sem); |
| 495 | sma = ipc_rcu_alloc(size); | 494 | sma = ipc_rcu_alloc(size); |
| 496 | if (!sma) { | 495 | if (!sma) |
| 497 | return -ENOMEM; | 496 | return -ENOMEM; |
| 498 | } | 497 | |
| 499 | memset (sma, 0, size); | 498 | memset(sma, 0, size); |
| 500 | 499 | ||
| 501 | sma->sem_perm.mode = (semflg & S_IRWXUGO); | 500 | sma->sem_perm.mode = (semflg & S_IRWXUGO); |
| 502 | sma->sem_perm.key = key; | 501 | sma->sem_perm.key = key; |
| @@ -584,10 +583,11 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) | |||
| 584 | return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); | 583 | return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); |
| 585 | } | 584 | } |
| 586 | 585 | ||
| 587 | /** perform_atomic_semop - Perform (if possible) a semaphore operation | 586 | /** |
| 587 | * perform_atomic_semop - Perform (if possible) a semaphore operation | ||
| 588 | * @sma: semaphore array | 588 | * @sma: semaphore array |
| 589 | * @sops: array with operations that should be checked | 589 | * @sops: array with operations that should be checked |
| 590 | * @nsems: number of sops | 590 | * @nsops: number of operations |
| 591 | * @un: undo array | 591 | * @un: undo array |
| 592 | * @pid: pid that did the change | 592 | * @pid: pid that did the change |
| 593 | * | 593 | * |
| @@ -595,19 +595,18 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) | |||
| 595 | * Returns 1 if the operation is impossible, the caller must sleep. | 595 | * Returns 1 if the operation is impossible, the caller must sleep. |
| 596 | * Negative values are error codes. | 596 | * Negative values are error codes. |
| 597 | */ | 597 | */ |
| 598 | |||
| 599 | static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops, | 598 | static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops, |
| 600 | int nsops, struct sem_undo *un, int pid) | 599 | int nsops, struct sem_undo *un, int pid) |
| 601 | { | 600 | { |
| 602 | int result, sem_op; | 601 | int result, sem_op; |
| 603 | struct sembuf *sop; | 602 | struct sembuf *sop; |
| 604 | struct sem * curr; | 603 | struct sem *curr; |
| 605 | 604 | ||
| 606 | for (sop = sops; sop < sops + nsops; sop++) { | 605 | for (sop = sops; sop < sops + nsops; sop++) { |
| 607 | curr = sma->sem_base + sop->sem_num; | 606 | curr = sma->sem_base + sop->sem_num; |
| 608 | sem_op = sop->sem_op; | 607 | sem_op = sop->sem_op; |
| 609 | result = curr->semval; | 608 | result = curr->semval; |
| 610 | 609 | ||
| 611 | if (!sem_op && result) | 610 | if (!sem_op && result) |
| 612 | goto would_block; | 611 | goto would_block; |
| 613 | 612 | ||
| @@ -616,25 +615,24 @@ static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops, | |||
| 616 | goto would_block; | 615 | goto would_block; |
| 617 | if (result > SEMVMX) | 616 | if (result > SEMVMX) |
| 618 | goto out_of_range; | 617 | goto out_of_range; |
| 618 | |||
| 619 | if (sop->sem_flg & SEM_UNDO) { | 619 | if (sop->sem_flg & SEM_UNDO) { |
| 620 | int undo = un->semadj[sop->sem_num] - sem_op; | 620 | int undo = un->semadj[sop->sem_num] - sem_op; |
| 621 | /* | 621 | /* Exceeding the undo range is an error. */ |
| 622 | * Exceeding the undo range is an error. | ||
| 623 | */ | ||
| 624 | if (undo < (-SEMAEM - 1) || undo > SEMAEM) | 622 | if (undo < (-SEMAEM - 1) || undo > SEMAEM) |
| 625 | goto out_of_range; | 623 | goto out_of_range; |
| 624 | un->semadj[sop->sem_num] = undo; | ||
| 626 | } | 625 | } |
| 626 | |||
| 627 | curr->semval = result; | 627 | curr->semval = result; |
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | sop--; | 630 | sop--; |
| 631 | while (sop >= sops) { | 631 | while (sop >= sops) { |
| 632 | sma->sem_base[sop->sem_num].sempid = pid; | 632 | sma->sem_base[sop->sem_num].sempid = pid; |
| 633 | if (sop->sem_flg & SEM_UNDO) | ||
| 634 | un->semadj[sop->sem_num] -= sop->sem_op; | ||
| 635 | sop--; | 633 | sop--; |
| 636 | } | 634 | } |
| 637 | 635 | ||
| 638 | return 0; | 636 | return 0; |
| 639 | 637 | ||
| 640 | out_of_range: | 638 | out_of_range: |
| @@ -650,7 +648,10 @@ would_block: | |||
| 650 | undo: | 648 | undo: |
| 651 | sop--; | 649 | sop--; |
| 652 | while (sop >= sops) { | 650 | while (sop >= sops) { |
| 653 | sma->sem_base[sop->sem_num].semval -= sop->sem_op; | 651 | sem_op = sop->sem_op; |
| 652 | sma->sem_base[sop->sem_num].semval -= sem_op; | ||
| 653 | if (sop->sem_flg & SEM_UNDO) | ||
| 654 | un->semadj[sop->sem_num] += sem_op; | ||
| 654 | sop--; | 655 | sop--; |
| 655 | } | 656 | } |
| 656 | 657 | ||
| @@ -680,7 +681,7 @@ static void wake_up_sem_queue_prepare(struct list_head *pt, | |||
| 680 | } | 681 | } |
| 681 | 682 | ||
| 682 | /** | 683 | /** |
| 683 | * wake_up_sem_queue_do(pt) - do the actual wake-up | 684 | * wake_up_sem_queue_do - do the actual wake-up |
| 684 | * @pt: list of tasks to be woken up | 685 | * @pt: list of tasks to be woken up |
| 685 | * | 686 | * |
| 686 | * Do the actual wake-up. | 687 | * Do the actual wake-up. |
| @@ -746,7 +747,7 @@ static int check_restart(struct sem_array *sma, struct sem_queue *q) | |||
| 746 | } | 747 | } |
| 747 | 748 | ||
| 748 | /** | 749 | /** |
| 749 | * wake_const_ops(sma, semnum, pt) - Wake up non-alter tasks | 750 | * wake_const_ops - wake up non-alter tasks |
| 750 | * @sma: semaphore array. | 751 | * @sma: semaphore array. |
| 751 | * @semnum: semaphore that was modified. | 752 | * @semnum: semaphore that was modified. |
| 752 | * @pt: list head for the tasks that must be woken up. | 753 | * @pt: list head for the tasks that must be woken up. |
| @@ -796,15 +797,14 @@ static int wake_const_ops(struct sem_array *sma, int semnum, | |||
| 796 | } | 797 | } |
| 797 | 798 | ||
| 798 | /** | 799 | /** |
| 799 | * do_smart_wakeup_zero(sma, sops, nsops, pt) - wakeup all wait for zero tasks | 800 | * do_smart_wakeup_zero - wakeup all wait for zero tasks |
| 800 | * @sma: semaphore array | 801 | * @sma: semaphore array |
| 801 | * @sops: operations that were performed | 802 | * @sops: operations that were performed |
| 802 | * @nsops: number of operations | 803 | * @nsops: number of operations |
| 803 | * @pt: list head of the tasks that must be woken up. | 804 | * @pt: list head of the tasks that must be woken up. |
| 804 | * | 805 | * |
| 805 | * do_smart_wakeup_zero() checks all required queue for wait-for-zero | 806 | * Checks all required queue for wait-for-zero operations, based |
| 806 | * operations, based on the actual changes that were performed on the | 807 | * on the actual changes that were performed on the semaphore array. |
| 807 | * semaphore array. | ||
| 808 | * The function returns 1 if at least one operation was completed successfully. | 808 | * The function returns 1 if at least one operation was completed successfully. |
| 809 | */ | 809 | */ |
| 810 | static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops, | 810 | static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops, |
| @@ -848,7 +848,7 @@ static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops, | |||
| 848 | 848 | ||
| 849 | 849 | ||
| 850 | /** | 850 | /** |
| 851 | * update_queue(sma, semnum): Look for tasks that can be completed. | 851 | * update_queue - look for tasks that can be completed. |
| 852 | * @sma: semaphore array. | 852 | * @sma: semaphore array. |
| 853 | * @semnum: semaphore that was modified. | 853 | * @semnum: semaphore that was modified. |
| 854 | * @pt: list head for the tasks that must be woken up. | 854 | * @pt: list head for the tasks that must be woken up. |
| @@ -918,7 +918,7 @@ again: | |||
| 918 | } | 918 | } |
| 919 | 919 | ||
| 920 | /** | 920 | /** |
| 921 | * set_semotime(sma, sops) - set sem_otime | 921 | * set_semotime - set sem_otime |
| 922 | * @sma: semaphore array | 922 | * @sma: semaphore array |
| 923 | * @sops: operations that modified the array, may be NULL | 923 | * @sops: operations that modified the array, may be NULL |
| 924 | * | 924 | * |
| @@ -936,7 +936,7 @@ static void set_semotime(struct sem_array *sma, struct sembuf *sops) | |||
| 936 | } | 936 | } |
| 937 | 937 | ||
| 938 | /** | 938 | /** |
| 939 | * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue | 939 | * do_smart_update - optimized update_queue |
| 940 | * @sma: semaphore array | 940 | * @sma: semaphore array |
| 941 | * @sops: operations that were performed | 941 | * @sops: operations that were performed |
| 942 | * @nsops: number of operations | 942 | * @nsops: number of operations |
| @@ -998,21 +998,21 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop | |||
| 998 | * The counts we return here are a rough approximation, but still | 998 | * The counts we return here are a rough approximation, but still |
| 999 | * warrant that semncnt+semzcnt>0 if the task is on the pending queue. | 999 | * warrant that semncnt+semzcnt>0 if the task is on the pending queue. |
| 1000 | */ | 1000 | */ |
| 1001 | static int count_semncnt (struct sem_array * sma, ushort semnum) | 1001 | static int count_semncnt(struct sem_array *sma, ushort semnum) |
| 1002 | { | 1002 | { |
| 1003 | int semncnt; | 1003 | int semncnt; |
| 1004 | struct sem_queue * q; | 1004 | struct sem_queue *q; |
| 1005 | 1005 | ||
| 1006 | semncnt = 0; | 1006 | semncnt = 0; |
| 1007 | list_for_each_entry(q, &sma->sem_base[semnum].pending_alter, list) { | 1007 | list_for_each_entry(q, &sma->sem_base[semnum].pending_alter, list) { |
| 1008 | struct sembuf * sops = q->sops; | 1008 | struct sembuf *sops = q->sops; |
| 1009 | BUG_ON(sops->sem_num != semnum); | 1009 | BUG_ON(sops->sem_num != semnum); |
| 1010 | if ((sops->sem_op < 0) && !(sops->sem_flg & IPC_NOWAIT)) | 1010 | if ((sops->sem_op < 0) && !(sops->sem_flg & IPC_NOWAIT)) |
| 1011 | semncnt++; | 1011 | semncnt++; |
| 1012 | } | 1012 | } |
| 1013 | 1013 | ||
| 1014 | list_for_each_entry(q, &sma->pending_alter, list) { | 1014 | list_for_each_entry(q, &sma->pending_alter, list) { |
| 1015 | struct sembuf * sops = q->sops; | 1015 | struct sembuf *sops = q->sops; |
| 1016 | int nsops = q->nsops; | 1016 | int nsops = q->nsops; |
| 1017 | int i; | 1017 | int i; |
| 1018 | for (i = 0; i < nsops; i++) | 1018 | for (i = 0; i < nsops; i++) |
| @@ -1024,21 +1024,21 @@ static int count_semncnt (struct sem_array * sma, ushort semnum) | |||
| 1024 | return semncnt; | 1024 | return semncnt; |
| 1025 | } | 1025 | } |
| 1026 | 1026 | ||
| 1027 | static int count_semzcnt (struct sem_array * sma, ushort semnum) | 1027 | static int count_semzcnt(struct sem_array *sma, ushort semnum) |
| 1028 | { | 1028 | { |
| 1029 | int semzcnt; | 1029 | int semzcnt; |
| 1030 | struct sem_queue * q; | 1030 | struct sem_queue *q; |
| 1031 | 1031 | ||
| 1032 | semzcnt = 0; | 1032 | semzcnt = 0; |
| 1033 | list_for_each_entry(q, &sma->sem_base[semnum].pending_const, list) { | 1033 | list_for_each_entry(q, &sma->sem_base[semnum].pending_const, list) { |
| 1034 | struct sembuf * sops = q->sops; | 1034 | struct sembuf *sops = q->sops; |
| 1035 | BUG_ON(sops->sem_num != semnum); | 1035 | BUG_ON(sops->sem_num != semnum); |
| 1036 | if ((sops->sem_op == 0) && !(sops->sem_flg & IPC_NOWAIT)) | 1036 | if ((sops->sem_op == 0) && !(sops->sem_flg & IPC_NOWAIT)) |
| 1037 | semzcnt++; | 1037 | semzcnt++; |
| 1038 | } | 1038 | } |
| 1039 | 1039 | ||
| 1040 | list_for_each_entry(q, &sma->pending_const, list) { | 1040 | list_for_each_entry(q, &sma->pending_const, list) { |
| 1041 | struct sembuf * sops = q->sops; | 1041 | struct sembuf *sops = q->sops; |
| 1042 | int nsops = q->nsops; | 1042 | int nsops = q->nsops; |
| 1043 | int i; | 1043 | int i; |
| 1044 | for (i = 0; i < nsops; i++) | 1044 | for (i = 0; i < nsops; i++) |
| @@ -1108,7 +1108,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
| 1108 | 1108 | ||
| 1109 | static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version) | 1109 | static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version) |
| 1110 | { | 1110 | { |
| 1111 | switch(version) { | 1111 | switch (version) { |
| 1112 | case IPC_64: | 1112 | case IPC_64: |
| 1113 | return copy_to_user(buf, in, sizeof(*in)); | 1113 | return copy_to_user(buf, in, sizeof(*in)); |
| 1114 | case IPC_OLD: | 1114 | case IPC_OLD: |
| @@ -1151,7 +1151,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
| 1151 | int err; | 1151 | int err; |
| 1152 | struct sem_array *sma; | 1152 | struct sem_array *sma; |
| 1153 | 1153 | ||
| 1154 | switch(cmd) { | 1154 | switch (cmd) { |
| 1155 | case IPC_INFO: | 1155 | case IPC_INFO: |
| 1156 | case SEM_INFO: | 1156 | case SEM_INFO: |
| 1157 | { | 1157 | { |
| @@ -1162,7 +1162,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
| 1162 | if (err) | 1162 | if (err) |
| 1163 | return err; | 1163 | return err; |
| 1164 | 1164 | ||
| 1165 | memset(&seminfo,0,sizeof(seminfo)); | 1165 | memset(&seminfo, 0, sizeof(seminfo)); |
| 1166 | seminfo.semmni = ns->sc_semmni; | 1166 | seminfo.semmni = ns->sc_semmni; |
| 1167 | seminfo.semmns = ns->sc_semmns; | 1167 | seminfo.semmns = ns->sc_semmns; |
| 1168 | seminfo.semmsl = ns->sc_semmsl; | 1168 | seminfo.semmsl = ns->sc_semmsl; |
| @@ -1183,7 +1183,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
| 1183 | up_read(&sem_ids(ns).rwsem); | 1183 | up_read(&sem_ids(ns).rwsem); |
| 1184 | if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) | 1184 | if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) |
| 1185 | return -EFAULT; | 1185 | return -EFAULT; |
| 1186 | return (max_id < 0) ? 0: max_id; | 1186 | return (max_id < 0) ? 0 : max_id; |
| 1187 | } | 1187 | } |
| 1188 | case IPC_STAT: | 1188 | case IPC_STAT: |
| 1189 | case SEM_STAT: | 1189 | case SEM_STAT: |
| @@ -1239,7 +1239,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1239 | { | 1239 | { |
| 1240 | struct sem_undo *un; | 1240 | struct sem_undo *un; |
| 1241 | struct sem_array *sma; | 1241 | struct sem_array *sma; |
| 1242 | struct sem* curr; | 1242 | struct sem *curr; |
| 1243 | int err; | 1243 | int err; |
| 1244 | struct list_head tasks; | 1244 | struct list_head tasks; |
| 1245 | int val; | 1245 | int val; |
| @@ -1282,7 +1282,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1282 | 1282 | ||
| 1283 | sem_lock(sma, NULL, -1); | 1283 | sem_lock(sma, NULL, -1); |
| 1284 | 1284 | ||
| 1285 | if (sma->sem_perm.deleted) { | 1285 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 1286 | sem_unlock(sma, -1); | 1286 | sem_unlock(sma, -1); |
| 1287 | rcu_read_unlock(); | 1287 | rcu_read_unlock(); |
| 1288 | return -EIDRM; | 1288 | return -EIDRM; |
| @@ -1309,10 +1309,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1309 | int cmd, void __user *p) | 1309 | int cmd, void __user *p) |
| 1310 | { | 1310 | { |
| 1311 | struct sem_array *sma; | 1311 | struct sem_array *sma; |
| 1312 | struct sem* curr; | 1312 | struct sem *curr; |
| 1313 | int err, nsems; | 1313 | int err, nsems; |
| 1314 | ushort fast_sem_io[SEMMSL_FAST]; | 1314 | ushort fast_sem_io[SEMMSL_FAST]; |
| 1315 | ushort* sem_io = fast_sem_io; | 1315 | ushort *sem_io = fast_sem_io; |
| 1316 | struct list_head tasks; | 1316 | struct list_head tasks; |
| 1317 | 1317 | ||
| 1318 | INIT_LIST_HEAD(&tasks); | 1318 | INIT_LIST_HEAD(&tasks); |
| @@ -1342,11 +1342,11 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1342 | int i; | 1342 | int i; |
| 1343 | 1343 | ||
| 1344 | sem_lock(sma, NULL, -1); | 1344 | sem_lock(sma, NULL, -1); |
| 1345 | if (sma->sem_perm.deleted) { | 1345 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 1346 | err = -EIDRM; | 1346 | err = -EIDRM; |
| 1347 | goto out_unlock; | 1347 | goto out_unlock; |
| 1348 | } | 1348 | } |
| 1349 | if(nsems > SEMMSL_FAST) { | 1349 | if (nsems > SEMMSL_FAST) { |
| 1350 | if (!ipc_rcu_getref(sma)) { | 1350 | if (!ipc_rcu_getref(sma)) { |
| 1351 | err = -EIDRM; | 1351 | err = -EIDRM; |
| 1352 | goto out_unlock; | 1352 | goto out_unlock; |
| @@ -1354,14 +1354,14 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1354 | sem_unlock(sma, -1); | 1354 | sem_unlock(sma, -1); |
| 1355 | rcu_read_unlock(); | 1355 | rcu_read_unlock(); |
| 1356 | sem_io = ipc_alloc(sizeof(ushort)*nsems); | 1356 | sem_io = ipc_alloc(sizeof(ushort)*nsems); |
| 1357 | if(sem_io == NULL) { | 1357 | if (sem_io == NULL) { |
| 1358 | ipc_rcu_putref(sma, ipc_rcu_free); | 1358 | ipc_rcu_putref(sma, ipc_rcu_free); |
| 1359 | return -ENOMEM; | 1359 | return -ENOMEM; |
| 1360 | } | 1360 | } |
| 1361 | 1361 | ||
| 1362 | rcu_read_lock(); | 1362 | rcu_read_lock(); |
| 1363 | sem_lock_and_putref(sma); | 1363 | sem_lock_and_putref(sma); |
| 1364 | if (sma->sem_perm.deleted) { | 1364 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 1365 | err = -EIDRM; | 1365 | err = -EIDRM; |
| 1366 | goto out_unlock; | 1366 | goto out_unlock; |
| 1367 | } | 1367 | } |
| @@ -1371,7 +1371,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1371 | sem_unlock(sma, -1); | 1371 | sem_unlock(sma, -1); |
| 1372 | rcu_read_unlock(); | 1372 | rcu_read_unlock(); |
| 1373 | err = 0; | 1373 | err = 0; |
| 1374 | if(copy_to_user(array, sem_io, nsems*sizeof(ushort))) | 1374 | if (copy_to_user(array, sem_io, nsems*sizeof(ushort))) |
| 1375 | err = -EFAULT; | 1375 | err = -EFAULT; |
| 1376 | goto out_free; | 1376 | goto out_free; |
| 1377 | } | 1377 | } |
| @@ -1386,15 +1386,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1386 | } | 1386 | } |
| 1387 | rcu_read_unlock(); | 1387 | rcu_read_unlock(); |
| 1388 | 1388 | ||
| 1389 | if(nsems > SEMMSL_FAST) { | 1389 | if (nsems > SEMMSL_FAST) { |
| 1390 | sem_io = ipc_alloc(sizeof(ushort)*nsems); | 1390 | sem_io = ipc_alloc(sizeof(ushort)*nsems); |
| 1391 | if(sem_io == NULL) { | 1391 | if (sem_io == NULL) { |
| 1392 | ipc_rcu_putref(sma, ipc_rcu_free); | 1392 | ipc_rcu_putref(sma, ipc_rcu_free); |
| 1393 | return -ENOMEM; | 1393 | return -ENOMEM; |
| 1394 | } | 1394 | } |
| 1395 | } | 1395 | } |
| 1396 | 1396 | ||
| 1397 | if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) { | 1397 | if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) { |
| 1398 | ipc_rcu_putref(sma, ipc_rcu_free); | 1398 | ipc_rcu_putref(sma, ipc_rcu_free); |
| 1399 | err = -EFAULT; | 1399 | err = -EFAULT; |
| 1400 | goto out_free; | 1400 | goto out_free; |
| @@ -1409,7 +1409,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1409 | } | 1409 | } |
| 1410 | rcu_read_lock(); | 1410 | rcu_read_lock(); |
| 1411 | sem_lock_and_putref(sma); | 1411 | sem_lock_and_putref(sma); |
| 1412 | if (sma->sem_perm.deleted) { | 1412 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 1413 | err = -EIDRM; | 1413 | err = -EIDRM; |
| 1414 | goto out_unlock; | 1414 | goto out_unlock; |
| 1415 | } | 1415 | } |
| @@ -1435,7 +1435,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1435 | goto out_rcu_wakeup; | 1435 | goto out_rcu_wakeup; |
| 1436 | 1436 | ||
| 1437 | sem_lock(sma, NULL, -1); | 1437 | sem_lock(sma, NULL, -1); |
| 1438 | if (sma->sem_perm.deleted) { | 1438 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 1439 | err = -EIDRM; | 1439 | err = -EIDRM; |
| 1440 | goto out_unlock; | 1440 | goto out_unlock; |
| 1441 | } | 1441 | } |
| @@ -1449,10 +1449,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
| 1449 | err = curr->sempid; | 1449 | err = curr->sempid; |
| 1450 | goto out_unlock; | 1450 | goto out_unlock; |
| 1451 | case GETNCNT: | 1451 | case GETNCNT: |
| 1452 | err = count_semncnt(sma,semnum); | 1452 | err = count_semncnt(sma, semnum); |
| 1453 | goto out_unlock; | 1453 | goto out_unlock; |
| 1454 | case GETZCNT: | 1454 | case GETZCNT: |
| 1455 | err = count_semzcnt(sma,semnum); | 1455 | err = count_semzcnt(sma, semnum); |
| 1456 | goto out_unlock; | 1456 | goto out_unlock; |
| 1457 | } | 1457 | } |
| 1458 | 1458 | ||
| @@ -1462,7 +1462,7 @@ out_rcu_wakeup: | |||
| 1462 | rcu_read_unlock(); | 1462 | rcu_read_unlock(); |
| 1463 | wake_up_sem_queue_do(&tasks); | 1463 | wake_up_sem_queue_do(&tasks); |
| 1464 | out_free: | 1464 | out_free: |
| 1465 | if(sem_io != fast_sem_io) | 1465 | if (sem_io != fast_sem_io) |
| 1466 | ipc_free(sem_io, sizeof(ushort)*nsems); | 1466 | ipc_free(sem_io, sizeof(ushort)*nsems); |
| 1467 | return err; | 1467 | return err; |
| 1468 | } | 1468 | } |
| @@ -1470,7 +1470,7 @@ out_free: | |||
| 1470 | static inline unsigned long | 1470 | static inline unsigned long |
| 1471 | copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) | 1471 | copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) |
| 1472 | { | 1472 | { |
| 1473 | switch(version) { | 1473 | switch (version) { |
| 1474 | case IPC_64: | 1474 | case IPC_64: |
| 1475 | if (copy_from_user(out, buf, sizeof(*out))) | 1475 | if (copy_from_user(out, buf, sizeof(*out))) |
| 1476 | return -EFAULT; | 1476 | return -EFAULT; |
| @@ -1479,7 +1479,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version) | |||
| 1479 | { | 1479 | { |
| 1480 | struct semid_ds tbuf_old; | 1480 | struct semid_ds tbuf_old; |
| 1481 | 1481 | ||
| 1482 | if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) | 1482 | if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) |
| 1483 | return -EFAULT; | 1483 | return -EFAULT; |
| 1484 | 1484 | ||
| 1485 | out->sem_perm.uid = tbuf_old.sem_perm.uid; | 1485 | out->sem_perm.uid = tbuf_old.sem_perm.uid; |
| @@ -1506,7 +1506,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, | |||
| 1506 | struct semid64_ds semid64; | 1506 | struct semid64_ds semid64; |
| 1507 | struct kern_ipc_perm *ipcp; | 1507 | struct kern_ipc_perm *ipcp; |
| 1508 | 1508 | ||
| 1509 | if(cmd == IPC_SET) { | 1509 | if (cmd == IPC_SET) { |
| 1510 | if (copy_semid_from_user(&semid64, p, version)) | 1510 | if (copy_semid_from_user(&semid64, p, version)) |
| 1511 | return -EFAULT; | 1511 | return -EFAULT; |
| 1512 | } | 1512 | } |
| @@ -1566,7 +1566,7 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) | |||
| 1566 | version = ipc_parse_version(&cmd); | 1566 | version = ipc_parse_version(&cmd); |
| 1567 | ns = current->nsproxy->ipc_ns; | 1567 | ns = current->nsproxy->ipc_ns; |
| 1568 | 1568 | ||
| 1569 | switch(cmd) { | 1569 | switch (cmd) { |
| 1570 | case IPC_INFO: | 1570 | case IPC_INFO: |
| 1571 | case SEM_INFO: | 1571 | case SEM_INFO: |
| 1572 | case IPC_STAT: | 1572 | case IPC_STAT: |
| @@ -1634,7 +1634,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | |||
| 1634 | { | 1634 | { |
| 1635 | struct sem_undo *un; | 1635 | struct sem_undo *un; |
| 1636 | 1636 | ||
| 1637 | assert_spin_locked(&ulp->lock); | 1637 | assert_spin_locked(&ulp->lock); |
| 1638 | 1638 | ||
| 1639 | un = __lookup_undo(ulp, semid); | 1639 | un = __lookup_undo(ulp, semid); |
| 1640 | if (un) { | 1640 | if (un) { |
| @@ -1645,7 +1645,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | |||
| 1645 | } | 1645 | } |
| 1646 | 1646 | ||
| 1647 | /** | 1647 | /** |
| 1648 | * find_alloc_undo - Lookup (and if not present create) undo array | 1648 | * find_alloc_undo - lookup (and if not present create) undo array |
| 1649 | * @ns: namespace | 1649 | * @ns: namespace |
| 1650 | * @semid: semaphore array id | 1650 | * @semid: semaphore array id |
| 1651 | * | 1651 | * |
| @@ -1670,7 +1670,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) | |||
| 1670 | spin_lock(&ulp->lock); | 1670 | spin_lock(&ulp->lock); |
| 1671 | un = lookup_undo(ulp, semid); | 1671 | un = lookup_undo(ulp, semid); |
| 1672 | spin_unlock(&ulp->lock); | 1672 | spin_unlock(&ulp->lock); |
| 1673 | if (likely(un!=NULL)) | 1673 | if (likely(un != NULL)) |
| 1674 | goto out; | 1674 | goto out; |
| 1675 | 1675 | ||
| 1676 | /* no undo structure around - allocate one. */ | 1676 | /* no undo structure around - allocate one. */ |
| @@ -1699,7 +1699,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) | |||
| 1699 | /* step 3: Acquire the lock on semaphore array */ | 1699 | /* step 3: Acquire the lock on semaphore array */ |
| 1700 | rcu_read_lock(); | 1700 | rcu_read_lock(); |
| 1701 | sem_lock_and_putref(sma); | 1701 | sem_lock_and_putref(sma); |
| 1702 | if (sma->sem_perm.deleted) { | 1702 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 1703 | sem_unlock(sma, -1); | 1703 | sem_unlock(sma, -1); |
| 1704 | rcu_read_unlock(); | 1704 | rcu_read_unlock(); |
| 1705 | kfree(new); | 1705 | kfree(new); |
| @@ -1735,7 +1735,7 @@ out: | |||
| 1735 | 1735 | ||
| 1736 | 1736 | ||
| 1737 | /** | 1737 | /** |
| 1738 | * get_queue_result - Retrieve the result code from sem_queue | 1738 | * get_queue_result - retrieve the result code from sem_queue |
| 1739 | * @q: Pointer to queue structure | 1739 | * @q: Pointer to queue structure |
| 1740 | * | 1740 | * |
| 1741 | * Retrieve the return code from the pending queue. If IN_WAKEUP is found in | 1741 | * Retrieve the return code from the pending queue. If IN_WAKEUP is found in |
| @@ -1765,7 +1765,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
| 1765 | int error = -EINVAL; | 1765 | int error = -EINVAL; |
| 1766 | struct sem_array *sma; | 1766 | struct sem_array *sma; |
| 1767 | struct sembuf fast_sops[SEMOPM_FAST]; | 1767 | struct sembuf fast_sops[SEMOPM_FAST]; |
| 1768 | struct sembuf* sops = fast_sops, *sop; | 1768 | struct sembuf *sops = fast_sops, *sop; |
| 1769 | struct sem_undo *un; | 1769 | struct sem_undo *un; |
| 1770 | int undos = 0, alter = 0, max, locknum; | 1770 | int undos = 0, alter = 0, max, locknum; |
| 1771 | struct sem_queue queue; | 1771 | struct sem_queue queue; |
| @@ -1779,13 +1779,13 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
| 1779 | return -EINVAL; | 1779 | return -EINVAL; |
| 1780 | if (nsops > ns->sc_semopm) | 1780 | if (nsops > ns->sc_semopm) |
| 1781 | return -E2BIG; | 1781 | return -E2BIG; |
| 1782 | if(nsops > SEMOPM_FAST) { | 1782 | if (nsops > SEMOPM_FAST) { |
| 1783 | sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); | 1783 | sops = kmalloc(sizeof(*sops)*nsops, GFP_KERNEL); |
| 1784 | if(sops==NULL) | 1784 | if (sops == NULL) |
| 1785 | return -ENOMEM; | 1785 | return -ENOMEM; |
| 1786 | } | 1786 | } |
| 1787 | if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) { | 1787 | if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) { |
| 1788 | error=-EFAULT; | 1788 | error = -EFAULT; |
| 1789 | goto out_free; | 1789 | goto out_free; |
| 1790 | } | 1790 | } |
| 1791 | if (timeout) { | 1791 | if (timeout) { |
| @@ -1846,7 +1846,15 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
| 1846 | 1846 | ||
| 1847 | error = -EIDRM; | 1847 | error = -EIDRM; |
| 1848 | locknum = sem_lock(sma, sops, nsops); | 1848 | locknum = sem_lock(sma, sops, nsops); |
| 1849 | if (sma->sem_perm.deleted) | 1849 | /* |
| 1850 | * We eventually might perform the following check in a lockless | ||
| 1851 | * fashion, considering ipc_valid_object() locking constraints. | ||
| 1852 | * If nsops == 1 and there is no contention for sem_perm.lock, then | ||
| 1853 | * only a per-semaphore lock is held and it's OK to proceed with the | ||
| 1854 | * check below. More details on the fine grained locking scheme | ||
| 1855 | * entangled here and why it's RMID race safe on comments at sem_lock() | ||
| 1856 | */ | ||
| 1857 | if (!ipc_valid_object(&sma->sem_perm)) | ||
| 1850 | goto out_unlock_free; | 1858 | goto out_unlock_free; |
| 1851 | /* | 1859 | /* |
| 1852 | * semid identifiers are not unique - find_alloc_undo may have | 1860 | * semid identifiers are not unique - find_alloc_undo may have |
| @@ -1959,10 +1967,8 @@ sleep_again: | |||
| 1959 | * If queue.status != -EINTR we are woken up by another process. | 1967 | * If queue.status != -EINTR we are woken up by another process. |
| 1960 | * Leave without unlink_queue(), but with sem_unlock(). | 1968 | * Leave without unlink_queue(), but with sem_unlock(). |
| 1961 | */ | 1969 | */ |
| 1962 | 1970 | if (error != -EINTR) | |
| 1963 | if (error != -EINTR) { | ||
| 1964 | goto out_unlock_free; | 1971 | goto out_unlock_free; |
| 1965 | } | ||
| 1966 | 1972 | ||
| 1967 | /* | 1973 | /* |
| 1968 | * If an interrupt occurred we have to clean up the queue | 1974 | * If an interrupt occurred we have to clean up the queue |
| @@ -1984,7 +1990,7 @@ out_rcu_wakeup: | |||
| 1984 | rcu_read_unlock(); | 1990 | rcu_read_unlock(); |
| 1985 | wake_up_sem_queue_do(&tasks); | 1991 | wake_up_sem_queue_do(&tasks); |
| 1986 | out_free: | 1992 | out_free: |
| 1987 | if(sops != fast_sops) | 1993 | if (sops != fast_sops) |
| 1988 | kfree(sops); | 1994 | kfree(sops); |
| 1989 | return error; | 1995 | return error; |
| 1990 | } | 1996 | } |
| @@ -2068,7 +2074,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 2068 | 2074 | ||
| 2069 | sem_lock(sma, NULL, -1); | 2075 | sem_lock(sma, NULL, -1); |
| 2070 | /* exit_sem raced with IPC_RMID, nothing to do */ | 2076 | /* exit_sem raced with IPC_RMID, nothing to do */ |
| 2071 | if (sma->sem_perm.deleted) { | 2077 | if (!ipc_valid_object(&sma->sem_perm)) { |
| 2072 | sem_unlock(sma, -1); | 2078 | sem_unlock(sma, -1); |
| 2073 | rcu_read_unlock(); | 2079 | rcu_read_unlock(); |
| 2074 | continue; | 2080 | continue; |
| @@ -2093,7 +2099,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 2093 | 2099 | ||
| 2094 | /* perform adjustments registered in un */ | 2100 | /* perform adjustments registered in un */ |
| 2095 | for (i = 0; i < sma->sem_nsems; i++) { | 2101 | for (i = 0; i < sma->sem_nsems; i++) { |
| 2096 | struct sem * semaphore = &sma->sem_base[i]; | 2102 | struct sem *semaphore = &sma->sem_base[i]; |
| 2097 | if (un->semadj[i]) { | 2103 | if (un->semadj[i]) { |
| 2098 | semaphore->semval += un->semadj[i]; | 2104 | semaphore->semval += un->semadj[i]; |
| 2099 | /* | 2105 | /* |
| @@ -2107,7 +2113,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 2107 | * Linux caps the semaphore value, both at 0 | 2113 | * Linux caps the semaphore value, both at 0 |
| 2108 | * and at SEMVMX. | 2114 | * and at SEMVMX. |
| 2109 | * | 2115 | * |
| 2110 | * Manfred <manfred@colorfullife.com> | 2116 | * Manfred <manfred@colorfullife.com> |
| 2111 | */ | 2117 | */ |
| 2112 | if (semaphore->semval < 0) | 2118 | if (semaphore->semval < 0) |
| 2113 | semaphore->semval = 0; | 2119 | semaphore->semval = 0; |
| @@ -67,7 +67,7 @@ static const struct vm_operations_struct shm_vm_ops; | |||
| 67 | static int newseg(struct ipc_namespace *, struct ipc_params *); | 67 | static int newseg(struct ipc_namespace *, struct ipc_params *); |
| 68 | static void shm_open(struct vm_area_struct *vma); | 68 | static void shm_open(struct vm_area_struct *vma); |
| 69 | static void shm_close(struct vm_area_struct *vma); | 69 | static void shm_close(struct vm_area_struct *vma); |
| 70 | static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); | 70 | static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp); |
| 71 | #ifdef CONFIG_PROC_FS | 71 | #ifdef CONFIG_PROC_FS |
| 72 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); | 72 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); |
| 73 | #endif | 73 | #endif |
| @@ -91,7 +91,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
| 91 | struct shmid_kernel *shp; | 91 | struct shmid_kernel *shp; |
| 92 | shp = container_of(ipcp, struct shmid_kernel, shm_perm); | 92 | shp = container_of(ipcp, struct shmid_kernel, shm_perm); |
| 93 | 93 | ||
| 94 | if (shp->shm_nattch){ | 94 | if (shp->shm_nattch) { |
| 95 | shp->shm_perm.mode |= SHM_DEST; | 95 | shp->shm_perm.mode |= SHM_DEST; |
| 96 | /* Do not find it any more */ | 96 | /* Do not find it any more */ |
| 97 | shp->shm_perm.key = IPC_PRIVATE; | 97 | shp->shm_perm.key = IPC_PRIVATE; |
| @@ -116,7 +116,7 @@ static int __init ipc_ns_init(void) | |||
| 116 | 116 | ||
| 117 | pure_initcall(ipc_ns_init); | 117 | pure_initcall(ipc_ns_init); |
| 118 | 118 | ||
| 119 | void __init shm_init (void) | 119 | void __init shm_init(void) |
| 120 | { | 120 | { |
| 121 | ipc_init_proc_interface("sysvipc/shm", | 121 | ipc_init_proc_interface("sysvipc/shm", |
| 122 | #if BITS_PER_LONG <= 32 | 122 | #if BITS_PER_LONG <= 32 |
| @@ -248,7 +248,7 @@ static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) | |||
| 248 | */ | 248 | */ |
| 249 | static void shm_close(struct vm_area_struct *vma) | 249 | static void shm_close(struct vm_area_struct *vma) |
| 250 | { | 250 | { |
| 251 | struct file * file = vma->vm_file; | 251 | struct file *file = vma->vm_file; |
| 252 | struct shm_file_data *sfd = shm_file_data(file); | 252 | struct shm_file_data *sfd = shm_file_data(file); |
| 253 | struct shmid_kernel *shp; | 253 | struct shmid_kernel *shp; |
| 254 | struct ipc_namespace *ns = sfd->ns; | 254 | struct ipc_namespace *ns = sfd->ns; |
| @@ -379,7 +379,7 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma, | |||
| 379 | } | 379 | } |
| 380 | #endif | 380 | #endif |
| 381 | 381 | ||
| 382 | static int shm_mmap(struct file * file, struct vm_area_struct * vma) | 382 | static int shm_mmap(struct file *file, struct vm_area_struct *vma) |
| 383 | { | 383 | { |
| 384 | struct shm_file_data *sfd = shm_file_data(file); | 384 | struct shm_file_data *sfd = shm_file_data(file); |
| 385 | int ret; | 385 | int ret; |
| @@ -477,7 +477,6 @@ static const struct vm_operations_struct shm_vm_ops = { | |||
| 477 | * | 477 | * |
| 478 | * Called with shm_ids.rwsem held as a writer. | 478 | * Called with shm_ids.rwsem held as a writer. |
| 479 | */ | 479 | */ |
| 480 | |||
| 481 | static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | 480 | static int newseg(struct ipc_namespace *ns, struct ipc_params *params) |
| 482 | { | 481 | { |
| 483 | key_t key = params->key; | 482 | key_t key = params->key; |
| @@ -486,7 +485,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 486 | int error; | 485 | int error; |
| 487 | struct shmid_kernel *shp; | 486 | struct shmid_kernel *shp; |
| 488 | size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 487 | size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 489 | struct file * file; | 488 | struct file *file; |
| 490 | char name[13]; | 489 | char name[13]; |
| 491 | int id; | 490 | int id; |
| 492 | vm_flags_t acctflag = 0; | 491 | vm_flags_t acctflag = 0; |
| @@ -512,7 +511,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 512 | return error; | 511 | return error; |
| 513 | } | 512 | } |
| 514 | 513 | ||
| 515 | sprintf (name, "SYSV%08x", key); | 514 | sprintf(name, "SYSV%08x", key); |
| 516 | if (shmflg & SHM_HUGETLB) { | 515 | if (shmflg & SHM_HUGETLB) { |
| 517 | struct hstate *hs; | 516 | struct hstate *hs; |
| 518 | size_t hugesize; | 517 | size_t hugesize; |
| @@ -533,7 +532,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
| 533 | } else { | 532 | } else { |
| 534 | /* | 533 | /* |
| 535 | * Do not allow no accounting for OVERCOMMIT_NEVER, even | 534 | * Do not allow no accounting for OVERCOMMIT_NEVER, even |
| 536 | * if it's asked for. | 535 | * if it's asked for. |
| 537 | */ | 536 | */ |
| 538 | if ((shmflg & SHM_NORESERVE) && | 537 | if ((shmflg & SHM_NORESERVE) && |
| 539 | sysctl_overcommit_memory != OVERCOMMIT_NEVER) | 538 | sysctl_overcommit_memory != OVERCOMMIT_NEVER) |
| @@ -628,7 +627,7 @@ SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg) | |||
| 628 | 627 | ||
| 629 | static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) | 628 | static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) |
| 630 | { | 629 | { |
| 631 | switch(version) { | 630 | switch (version) { |
| 632 | case IPC_64: | 631 | case IPC_64: |
| 633 | return copy_to_user(buf, in, sizeof(*in)); | 632 | return copy_to_user(buf, in, sizeof(*in)); |
| 634 | case IPC_OLD: | 633 | case IPC_OLD: |
| @@ -655,7 +654,7 @@ static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ | |||
| 655 | static inline unsigned long | 654 | static inline unsigned long |
| 656 | copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version) | 655 | copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version) |
| 657 | { | 656 | { |
| 658 | switch(version) { | 657 | switch (version) { |
| 659 | case IPC_64: | 658 | case IPC_64: |
| 660 | if (copy_from_user(out, buf, sizeof(*out))) | 659 | if (copy_from_user(out, buf, sizeof(*out))) |
| 661 | return -EFAULT; | 660 | return -EFAULT; |
| @@ -680,14 +679,14 @@ copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version) | |||
| 680 | 679 | ||
| 681 | static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version) | 680 | static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version) |
| 682 | { | 681 | { |
| 683 | switch(version) { | 682 | switch (version) { |
| 684 | case IPC_64: | 683 | case IPC_64: |
| 685 | return copy_to_user(buf, in, sizeof(*in)); | 684 | return copy_to_user(buf, in, sizeof(*in)); |
| 686 | case IPC_OLD: | 685 | case IPC_OLD: |
| 687 | { | 686 | { |
| 688 | struct shminfo out; | 687 | struct shminfo out; |
| 689 | 688 | ||
| 690 | if(in->shmmax > INT_MAX) | 689 | if (in->shmmax > INT_MAX) |
| 691 | out.shmmax = INT_MAX; | 690 | out.shmmax = INT_MAX; |
| 692 | else | 691 | else |
| 693 | out.shmmax = (int)in->shmmax; | 692 | out.shmmax = (int)in->shmmax; |
| @@ -846,14 +845,14 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid, | |||
| 846 | shminfo.shmall = ns->shm_ctlall; | 845 | shminfo.shmall = ns->shm_ctlall; |
| 847 | 846 | ||
| 848 | shminfo.shmmin = SHMMIN; | 847 | shminfo.shmmin = SHMMIN; |
| 849 | if(copy_shminfo_to_user (buf, &shminfo, version)) | 848 | if (copy_shminfo_to_user(buf, &shminfo, version)) |
| 850 | return -EFAULT; | 849 | return -EFAULT; |
| 851 | 850 | ||
| 852 | down_read(&shm_ids(ns).rwsem); | 851 | down_read(&shm_ids(ns).rwsem); |
| 853 | err = ipc_get_maxid(&shm_ids(ns)); | 852 | err = ipc_get_maxid(&shm_ids(ns)); |
| 854 | up_read(&shm_ids(ns).rwsem); | 853 | up_read(&shm_ids(ns).rwsem); |
| 855 | 854 | ||
| 856 | if(err<0) | 855 | if (err < 0) |
| 857 | err = 0; | 856 | err = 0; |
| 858 | goto out; | 857 | goto out; |
| 859 | } | 858 | } |
| @@ -864,7 +863,7 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid, | |||
| 864 | memset(&shm_info, 0, sizeof(shm_info)); | 863 | memset(&shm_info, 0, sizeof(shm_info)); |
| 865 | down_read(&shm_ids(ns).rwsem); | 864 | down_read(&shm_ids(ns).rwsem); |
| 866 | shm_info.used_ids = shm_ids(ns).in_use; | 865 | shm_info.used_ids = shm_ids(ns).in_use; |
| 867 | shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); | 866 | shm_get_stat(ns, &shm_info.shm_rss, &shm_info.shm_swp); |
| 868 | shm_info.shm_tot = ns->shm_tot; | 867 | shm_info.shm_tot = ns->shm_tot; |
| 869 | shm_info.swap_attempts = 0; | 868 | shm_info.swap_attempts = 0; |
| 870 | shm_info.swap_successes = 0; | 869 | shm_info.swap_successes = 0; |
| @@ -975,6 +974,13 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 975 | goto out_unlock1; | 974 | goto out_unlock1; |
| 976 | 975 | ||
| 977 | ipc_lock_object(&shp->shm_perm); | 976 | ipc_lock_object(&shp->shm_perm); |
| 977 | |||
| 978 | /* check if shm_destroy() is tearing down shp */ | ||
| 979 | if (!ipc_valid_object(&shp->shm_perm)) { | ||
| 980 | err = -EIDRM; | ||
| 981 | goto out_unlock0; | ||
| 982 | } | ||
| 983 | |||
| 978 | if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { | 984 | if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) { |
| 979 | kuid_t euid = current_euid(); | 985 | kuid_t euid = current_euid(); |
| 980 | if (!uid_eq(euid, shp->shm_perm.uid) && | 986 | if (!uid_eq(euid, shp->shm_perm.uid) && |
| @@ -989,13 +995,6 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
| 989 | } | 995 | } |
| 990 | 996 | ||
| 991 | shm_file = shp->shm_file; | 997 | shm_file = shp->shm_file; |
| 992 | |||
| 993 | /* check if shm_destroy() is tearing down shp */ | ||
| 994 | if (shm_file == NULL) { | ||
| 995 | err = -EIDRM; | ||
| 996 | goto out_unlock0; | ||
| 997 | } | ||
| 998 | |||
| 999 | if (is_file_hugepages(shm_file)) | 998 | if (is_file_hugepages(shm_file)) |
| 1000 | goto out_unlock0; | 999 | goto out_unlock0; |
| 1001 | 1000 | ||
| @@ -1047,7 +1046,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, | |||
| 1047 | struct shmid_kernel *shp; | 1046 | struct shmid_kernel *shp; |
| 1048 | unsigned long addr; | 1047 | unsigned long addr; |
| 1049 | unsigned long size; | 1048 | unsigned long size; |
| 1050 | struct file * file; | 1049 | struct file *file; |
| 1051 | int err; | 1050 | int err; |
| 1052 | unsigned long flags; | 1051 | unsigned long flags; |
| 1053 | unsigned long prot; | 1052 | unsigned long prot; |
| @@ -1116,7 +1115,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, | |||
| 1116 | ipc_lock_object(&shp->shm_perm); | 1115 | ipc_lock_object(&shp->shm_perm); |
| 1117 | 1116 | ||
| 1118 | /* check if shm_destroy() is tearing down shp */ | 1117 | /* check if shm_destroy() is tearing down shp */ |
| 1119 | if (shp->shm_file == NULL) { | 1118 | if (!ipc_valid_object(&shp->shm_perm)) { |
| 1120 | ipc_unlock_object(&shp->shm_perm); | 1119 | ipc_unlock_object(&shp->shm_perm); |
| 1121 | err = -EIDRM; | 1120 | err = -EIDRM; |
| 1122 | goto out_unlock; | 1121 | goto out_unlock; |
diff --git a/ipc/util.c b/ipc/util.c index 3ae17a4ace5b..e1b4c6db8aa0 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
| @@ -110,15 +110,15 @@ static struct notifier_block ipc_memory_nb = { | |||
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | /** | 112 | /** |
| 113 | * ipc_init - initialise IPC subsystem | 113 | * ipc_init - initialise ipc subsystem |
| 114 | * | 114 | * |
| 115 | * The various system5 IPC resources (semaphores, messages and shared | 115 | * The various sysv ipc resources (semaphores, messages and shared |
| 116 | * memory) are initialised | 116 | * memory) are initialised. |
| 117 | * A callback routine is registered into the memory hotplug notifier | 117 | * |
| 118 | * chain: since msgmni scales to lowmem this callback routine will be | 118 | * A callback routine is registered into the memory hotplug notifier |
| 119 | * called upon successful memory add / remove to recompute msmgni. | 119 | * chain: since msgmni scales to lowmem this callback routine will be |
| 120 | * called upon successful memory add / remove to recompute msmgni. | ||
| 120 | */ | 121 | */ |
| 121 | |||
| 122 | static int __init ipc_init(void) | 122 | static int __init ipc_init(void) |
| 123 | { | 123 | { |
| 124 | sem_init(); | 124 | sem_init(); |
| @@ -131,39 +131,29 @@ static int __init ipc_init(void) | |||
| 131 | __initcall(ipc_init); | 131 | __initcall(ipc_init); |
| 132 | 132 | ||
| 133 | /** | 133 | /** |
| 134 | * ipc_init_ids - initialise IPC identifiers | 134 | * ipc_init_ids - initialise ipc identifiers |
| 135 | * @ids: Identifier set | 135 | * @ids: ipc identifier set |
| 136 | * | 136 | * |
| 137 | * Set up the sequence range to use for the ipc identifier range (limited | 137 | * Set up the sequence range to use for the ipc identifier range (limited |
| 138 | * below IPCMNI) then initialise the ids idr. | 138 | * below IPCMNI) then initialise the ids idr. |
| 139 | */ | 139 | */ |
| 140 | |||
| 141 | void ipc_init_ids(struct ipc_ids *ids) | 140 | void ipc_init_ids(struct ipc_ids *ids) |
| 142 | { | 141 | { |
| 143 | init_rwsem(&ids->rwsem); | ||
| 144 | |||
| 145 | ids->in_use = 0; | 142 | ids->in_use = 0; |
| 146 | ids->seq = 0; | 143 | ids->seq = 0; |
| 147 | ids->next_id = -1; | 144 | ids->next_id = -1; |
| 148 | { | 145 | init_rwsem(&ids->rwsem); |
| 149 | int seq_limit = INT_MAX/SEQ_MULTIPLIER; | ||
| 150 | if (seq_limit > USHRT_MAX) | ||
| 151 | ids->seq_max = USHRT_MAX; | ||
| 152 | else | ||
| 153 | ids->seq_max = seq_limit; | ||
| 154 | } | ||
| 155 | |||
| 156 | idr_init(&ids->ipcs_idr); | 146 | idr_init(&ids->ipcs_idr); |
| 157 | } | 147 | } |
| 158 | 148 | ||
| 159 | #ifdef CONFIG_PROC_FS | 149 | #ifdef CONFIG_PROC_FS |
| 160 | static const struct file_operations sysvipc_proc_fops; | 150 | static const struct file_operations sysvipc_proc_fops; |
| 161 | /** | 151 | /** |
| 162 | * ipc_init_proc_interface - Create a proc interface for sysipc types using a seq_file interface. | 152 | * ipc_init_proc_interface - create a proc interface for sysipc types using a seq_file interface. |
| 163 | * @path: Path in procfs | 153 | * @path: Path in procfs |
| 164 | * @header: Banner to be printed at the beginning of the file. | 154 | * @header: Banner to be printed at the beginning of the file. |
| 165 | * @ids: ipc id table to iterate. | 155 | * @ids: ipc id table to iterate. |
| 166 | * @show: show routine. | 156 | * @show: show routine. |
| 167 | */ | 157 | */ |
| 168 | void __init ipc_init_proc_interface(const char *path, const char *header, | 158 | void __init ipc_init_proc_interface(const char *path, const char *header, |
| 169 | int ids, int (*show)(struct seq_file *, void *)) | 159 | int ids, int (*show)(struct seq_file *, void *)) |
| @@ -184,23 +174,21 @@ void __init ipc_init_proc_interface(const char *path, const char *header, | |||
| 184 | NULL, /* parent dir */ | 174 | NULL, /* parent dir */ |
| 185 | &sysvipc_proc_fops, | 175 | &sysvipc_proc_fops, |
| 186 | iface); | 176 | iface); |
| 187 | if (!pde) { | 177 | if (!pde) |
| 188 | kfree(iface); | 178 | kfree(iface); |
| 189 | } | ||
| 190 | } | 179 | } |
| 191 | #endif | 180 | #endif |
| 192 | 181 | ||
| 193 | /** | 182 | /** |
| 194 | * ipc_findkey - find a key in an ipc identifier set | 183 | * ipc_findkey - find a key in an ipc identifier set |
| 195 | * @ids: Identifier set | 184 | * @ids: ipc identifier set |
| 196 | * @key: The key to find | 185 | * @key: key to find |
| 197 | * | 186 | * |
| 198 | * Requires ipc_ids.rwsem locked. | 187 | * Returns the locked pointer to the ipc structure if found or NULL |
| 199 | * Returns the LOCKED pointer to the ipc structure if found or NULL | 188 | * otherwise. If key is found ipc points to the owning ipc structure |
| 200 | * if not. | 189 | * |
| 201 | * If key is found ipc points to the owning ipc structure | 190 | * Called with ipc_ids.rwsem held. |
| 202 | */ | 191 | */ |
| 203 | |||
| 204 | static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) | 192 | static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) |
| 205 | { | 193 | { |
| 206 | struct kern_ipc_perm *ipc; | 194 | struct kern_ipc_perm *ipc; |
| @@ -227,12 +215,11 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) | |||
| 227 | } | 215 | } |
| 228 | 216 | ||
| 229 | /** | 217 | /** |
| 230 | * ipc_get_maxid - get the last assigned id | 218 | * ipc_get_maxid - get the last assigned id |
| 231 | * @ids: IPC identifier set | 219 | * @ids: ipc identifier set |
| 232 | * | 220 | * |
| 233 | * Called with ipc_ids.rwsem held. | 221 | * Called with ipc_ids.rwsem held. |
| 234 | */ | 222 | */ |
| 235 | |||
| 236 | int ipc_get_maxid(struct ipc_ids *ids) | 223 | int ipc_get_maxid(struct ipc_ids *ids) |
| 237 | { | 224 | { |
| 238 | struct kern_ipc_perm *ipc; | 225 | struct kern_ipc_perm *ipc; |
| @@ -258,19 +245,19 @@ int ipc_get_maxid(struct ipc_ids *ids) | |||
| 258 | } | 245 | } |
| 259 | 246 | ||
| 260 | /** | 247 | /** |
| 261 | * ipc_addid - add an IPC identifier | 248 | * ipc_addid - add an ipc identifier |
| 262 | * @ids: IPC identifier set | 249 | * @ids: ipc identifier set |
| 263 | * @new: new IPC permission set | 250 | * @new: new ipc permission set |
| 264 | * @size: limit for the number of used ids | 251 | * @size: limit for the number of used ids |
| 265 | * | 252 | * |
| 266 | * Add an entry 'new' to the IPC ids idr. The permissions object is | 253 | * Add an entry 'new' to the ipc ids idr. The permissions object is |
| 267 | * initialised and the first free entry is set up and the id assigned | 254 | * initialised and the first free entry is set up and the id assigned |
| 268 | * is returned. The 'new' entry is returned in a locked state on success. | 255 | * is returned. The 'new' entry is returned in a locked state on success. |
| 269 | * On failure the entry is not locked and a negative err-code is returned. | 256 | * On failure the entry is not locked and a negative err-code is returned. |
| 270 | * | 257 | * |
| 271 | * Called with writer ipc_ids.rwsem held. | 258 | * Called with writer ipc_ids.rwsem held. |
| 272 | */ | 259 | */ |
| 273 | int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | 260 | int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) |
| 274 | { | 261 | { |
| 275 | kuid_t euid; | 262 | kuid_t euid; |
| 276 | kgid_t egid; | 263 | kgid_t egid; |
| @@ -286,7 +273,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
| 286 | idr_preload(GFP_KERNEL); | 273 | idr_preload(GFP_KERNEL); |
| 287 | 274 | ||
| 288 | spin_lock_init(&new->lock); | 275 | spin_lock_init(&new->lock); |
| 289 | new->deleted = 0; | 276 | new->deleted = false; |
| 290 | rcu_read_lock(); | 277 | rcu_read_lock(); |
| 291 | spin_lock(&new->lock); | 278 | spin_lock(&new->lock); |
| 292 | 279 | ||
| @@ -308,7 +295,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
| 308 | 295 | ||
| 309 | if (next_id < 0) { | 296 | if (next_id < 0) { |
| 310 | new->seq = ids->seq++; | 297 | new->seq = ids->seq++; |
| 311 | if (ids->seq > ids->seq_max) | 298 | if (ids->seq > IPCID_SEQ_MAX) |
| 312 | ids->seq = 0; | 299 | ids->seq = 0; |
| 313 | } else { | 300 | } else { |
| 314 | new->seq = ipcid_to_seqx(next_id); | 301 | new->seq = ipcid_to_seqx(next_id); |
| @@ -320,14 +307,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
| 320 | } | 307 | } |
| 321 | 308 | ||
| 322 | /** | 309 | /** |
| 323 | * ipcget_new - create a new ipc object | 310 | * ipcget_new - create a new ipc object |
| 324 | * @ns: namespace | 311 | * @ns: ipc namespace |
| 325 | * @ids: IPC identifer set | 312 | * @ids: ipc identifer set |
| 326 | * @ops: the actual creation routine to call | 313 | * @ops: the actual creation routine to call |
| 327 | * @params: its parameters | 314 | * @params: its parameters |
| 328 | * | 315 | * |
| 329 | * This routine is called by sys_msgget, sys_semget() and sys_shmget() | 316 | * This routine is called by sys_msgget, sys_semget() and sys_shmget() |
| 330 | * when the key is IPC_PRIVATE. | 317 | * when the key is IPC_PRIVATE. |
| 331 | */ | 318 | */ |
| 332 | static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, | 319 | static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, |
| 333 | struct ipc_ops *ops, struct ipc_params *params) | 320 | struct ipc_ops *ops, struct ipc_params *params) |
| @@ -341,19 +328,19 @@ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
| 341 | } | 328 | } |
| 342 | 329 | ||
| 343 | /** | 330 | /** |
| 344 | * ipc_check_perms - check security and permissions for an IPC | 331 | * ipc_check_perms - check security and permissions for an ipc object |
| 345 | * @ns: IPC namespace | 332 | * @ns: ipc namespace |
| 346 | * @ipcp: ipc permission set | 333 | * @ipcp: ipc permission set |
| 347 | * @ops: the actual security routine to call | 334 | * @ops: the actual security routine to call |
| 348 | * @params: its parameters | 335 | * @params: its parameters |
| 349 | * | 336 | * |
| 350 | * This routine is called by sys_msgget(), sys_semget() and sys_shmget() | 337 | * This routine is called by sys_msgget(), sys_semget() and sys_shmget() |
| 351 | * when the key is not IPC_PRIVATE and that key already exists in the | 338 | * when the key is not IPC_PRIVATE and that key already exists in the |
| 352 | * ids IDR. | 339 | * ds IDR. |
| 353 | * | 340 | * |
| 354 | * On success, the IPC id is returned. | 341 | * On success, the ipc id is returned. |
| 355 | * | 342 | * |
| 356 | * It is called with ipc_ids.rwsem and ipcp->lock held. | 343 | * It is called with ipc_ids.rwsem and ipcp->lock held. |
| 357 | */ | 344 | */ |
| 358 | static int ipc_check_perms(struct ipc_namespace *ns, | 345 | static int ipc_check_perms(struct ipc_namespace *ns, |
| 359 | struct kern_ipc_perm *ipcp, | 346 | struct kern_ipc_perm *ipcp, |
| @@ -374,18 +361,18 @@ static int ipc_check_perms(struct ipc_namespace *ns, | |||
| 374 | } | 361 | } |
| 375 | 362 | ||
| 376 | /** | 363 | /** |
| 377 | * ipcget_public - get an ipc object or create a new one | 364 | * ipcget_public - get an ipc object or create a new one |
| 378 | * @ns: namespace | 365 | * @ns: ipc namespace |
| 379 | * @ids: IPC identifer set | 366 | * @ids: ipc identifer set |
| 380 | * @ops: the actual creation routine to call | 367 | * @ops: the actual creation routine to call |
| 381 | * @params: its parameters | 368 | * @params: its parameters |
| 382 | * | 369 | * |
| 383 | * This routine is called by sys_msgget, sys_semget() and sys_shmget() | 370 | * This routine is called by sys_msgget, sys_semget() and sys_shmget() |
| 384 | * when the key is not IPC_PRIVATE. | 371 | * when the key is not IPC_PRIVATE. |
| 385 | * It adds a new entry if the key is not found and does some permission | 372 | * It adds a new entry if the key is not found and does some permission |
| 386 | * / security checkings if the key is found. | 373 | * / security checkings if the key is found. |
| 387 | * | 374 | * |
| 388 | * On success, the ipc id is returned. | 375 | * On success, the ipc id is returned. |
| 389 | */ | 376 | */ |
| 390 | static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, | 377 | static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, |
| 391 | struct ipc_ops *ops, struct ipc_params *params) | 378 | struct ipc_ops *ops, struct ipc_params *params) |
| @@ -431,39 +418,33 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
| 431 | 418 | ||
| 432 | 419 | ||
| 433 | /** | 420 | /** |
| 434 | * ipc_rmid - remove an IPC identifier | 421 | * ipc_rmid - remove an ipc identifier |
| 435 | * @ids: IPC identifier set | 422 | * @ids: ipc identifier set |
| 436 | * @ipcp: ipc perm structure containing the identifier to remove | 423 | * @ipcp: ipc perm structure containing the identifier to remove |
| 437 | * | 424 | * |
| 438 | * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held | 425 | * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held |
| 439 | * before this function is called, and remain locked on the exit. | 426 | * before this function is called, and remain locked on the exit. |
| 440 | */ | 427 | */ |
| 441 | |||
| 442 | void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp) | 428 | void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp) |
| 443 | { | 429 | { |
| 444 | int lid = ipcid_to_idx(ipcp->id); | 430 | int lid = ipcid_to_idx(ipcp->id); |
| 445 | 431 | ||
| 446 | idr_remove(&ids->ipcs_idr, lid); | 432 | idr_remove(&ids->ipcs_idr, lid); |
| 447 | |||
| 448 | ids->in_use--; | 433 | ids->in_use--; |
| 449 | 434 | ipcp->deleted = true; | |
| 450 | ipcp->deleted = 1; | ||
| 451 | |||
| 452 | return; | ||
| 453 | } | 435 | } |
| 454 | 436 | ||
| 455 | /** | 437 | /** |
| 456 | * ipc_alloc - allocate ipc space | 438 | * ipc_alloc - allocate ipc space |
| 457 | * @size: size desired | 439 | * @size: size desired |
| 458 | * | 440 | * |
| 459 | * Allocate memory from the appropriate pools and return a pointer to it. | 441 | * Allocate memory from the appropriate pools and return a pointer to it. |
| 460 | * NULL is returned if the allocation fails | 442 | * NULL is returned if the allocation fails |
| 461 | */ | 443 | */ |
| 462 | |||
| 463 | void *ipc_alloc(int size) | 444 | void *ipc_alloc(int size) |
| 464 | { | 445 | { |
| 465 | void *out; | 446 | void *out; |
| 466 | if(size > PAGE_SIZE) | 447 | if (size > PAGE_SIZE) |
| 467 | out = vmalloc(size); | 448 | out = vmalloc(size); |
| 468 | else | 449 | else |
| 469 | out = kmalloc(size, GFP_KERNEL); | 450 | out = kmalloc(size, GFP_KERNEL); |
| @@ -471,28 +452,27 @@ void *ipc_alloc(int size) | |||
| 471 | } | 452 | } |
| 472 | 453 | ||
| 473 | /** | 454 | /** |
| 474 | * ipc_free - free ipc space | 455 | * ipc_free - free ipc space |
| 475 | * @ptr: pointer returned by ipc_alloc | 456 | * @ptr: pointer returned by ipc_alloc |
| 476 | * @size: size of block | 457 | * @size: size of block |
| 477 | * | 458 | * |
| 478 | * Free a block created with ipc_alloc(). The caller must know the size | 459 | * Free a block created with ipc_alloc(). The caller must know the size |
| 479 | * used in the allocation call. | 460 | * used in the allocation call. |
| 480 | */ | 461 | */ |
| 481 | 462 | void ipc_free(void *ptr, int size) | |
| 482 | void ipc_free(void* ptr, int size) | ||
| 483 | { | 463 | { |
| 484 | if(size > PAGE_SIZE) | 464 | if (size > PAGE_SIZE) |
| 485 | vfree(ptr); | 465 | vfree(ptr); |
| 486 | else | 466 | else |
| 487 | kfree(ptr); | 467 | kfree(ptr); |
| 488 | } | 468 | } |
| 489 | 469 | ||
| 490 | /** | 470 | /** |
| 491 | * ipc_rcu_alloc - allocate ipc and rcu space | 471 | * ipc_rcu_alloc - allocate ipc and rcu space |
| 492 | * @size: size desired | 472 | * @size: size desired |
| 493 | * | 473 | * |
| 494 | * Allocate memory for the rcu header structure + the object. | 474 | * Allocate memory for the rcu header structure + the object. |
| 495 | * Returns the pointer to the object or NULL upon failure. | 475 | * Returns the pointer to the object or NULL upon failure. |
| 496 | */ | 476 | */ |
| 497 | void *ipc_rcu_alloc(int size) | 477 | void *ipc_rcu_alloc(int size) |
| 498 | { | 478 | { |
| @@ -534,17 +514,16 @@ void ipc_rcu_free(struct rcu_head *head) | |||
| 534 | } | 514 | } |
| 535 | 515 | ||
| 536 | /** | 516 | /** |
| 537 | * ipcperms - check IPC permissions | 517 | * ipcperms - check ipc permissions |
| 538 | * @ns: IPC namespace | 518 | * @ns: ipc namespace |
| 539 | * @ipcp: IPC permission set | 519 | * @ipcp: ipc permission set |
| 540 | * @flag: desired permission set. | 520 | * @flag: desired permission set |
| 541 | * | 521 | * |
| 542 | * Check user, group, other permissions for access | 522 | * Check user, group, other permissions for access |
| 543 | * to ipc resources. return 0 if allowed | 523 | * to ipc resources. return 0 if allowed |
| 544 | * | 524 | * |
| 545 | * @flag will most probably be 0 or S_...UGO from <linux/stat.h> | 525 | * @flag will most probably be 0 or S_...UGO from <linux/stat.h> |
| 546 | */ | 526 | */ |
| 547 | |||
| 548 | int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) | 527 | int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) |
| 549 | { | 528 | { |
| 550 | kuid_t euid = current_euid(); | 529 | kuid_t euid = current_euid(); |
| @@ -572,16 +551,14 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag) | |||
| 572 | */ | 551 | */ |
| 573 | 552 | ||
| 574 | /** | 553 | /** |
| 575 | * kernel_to_ipc64_perm - convert kernel ipc permissions to user | 554 | * kernel_to_ipc64_perm - convert kernel ipc permissions to user |
| 576 | * @in: kernel permissions | 555 | * @in: kernel permissions |
| 577 | * @out: new style IPC permissions | 556 | * @out: new style ipc permissions |
| 578 | * | 557 | * |
| 579 | * Turn the kernel object @in into a set of permissions descriptions | 558 | * Turn the kernel object @in into a set of permissions descriptions |
| 580 | * for returning to userspace (@out). | 559 | * for returning to userspace (@out). |
| 581 | */ | 560 | */ |
| 582 | 561 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out) | |
| 583 | |||
| 584 | void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out) | ||
| 585 | { | 562 | { |
| 586 | out->key = in->key; | 563 | out->key = in->key; |
| 587 | out->uid = from_kuid_munged(current_user_ns(), in->uid); | 564 | out->uid = from_kuid_munged(current_user_ns(), in->uid); |
| @@ -593,15 +570,14 @@ void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out) | |||
| 593 | } | 570 | } |
| 594 | 571 | ||
| 595 | /** | 572 | /** |
| 596 | * ipc64_perm_to_ipc_perm - convert new ipc permissions to old | 573 | * ipc64_perm_to_ipc_perm - convert new ipc permissions to old |
| 597 | * @in: new style IPC permissions | 574 | * @in: new style ipc permissions |
| 598 | * @out: old style IPC permissions | 575 | * @out: old style ipc permissions |
| 599 | * | 576 | * |
| 600 | * Turn the new style permissions object @in into a compatibility | 577 | * Turn the new style permissions object @in into a compatibility |
| 601 | * object and store it into the @out pointer. | 578 | * object and store it into the @out pointer. |
| 602 | */ | 579 | */ |
| 603 | 580 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out) | |
| 604 | void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out) | ||
| 605 | { | 581 | { |
| 606 | out->key = in->key; | 582 | out->key = in->key; |
| 607 | SET_UID(out->uid, in->uid); | 583 | SET_UID(out->uid, in->uid); |
| @@ -635,8 +611,8 @@ struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id) | |||
| 635 | } | 611 | } |
| 636 | 612 | ||
| 637 | /** | 613 | /** |
| 638 | * ipc_lock - Lock an ipc structure without rwsem held | 614 | * ipc_lock - lock an ipc structure without rwsem held |
| 639 | * @ids: IPC identifier set | 615 | * @ids: ipc identifier set |
| 640 | * @id: ipc id to look for | 616 | * @id: ipc id to look for |
| 641 | * | 617 | * |
| 642 | * Look for an id in the ipc ids idr and lock the associated ipc object. | 618 | * Look for an id in the ipc ids idr and lock the associated ipc object. |
| @@ -657,7 +633,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) | |||
| 657 | /* ipc_rmid() may have already freed the ID while ipc_lock | 633 | /* ipc_rmid() may have already freed the ID while ipc_lock |
| 658 | * was spinning: here verify that the structure is still valid | 634 | * was spinning: here verify that the structure is still valid |
| 659 | */ | 635 | */ |
| 660 | if (!out->deleted) | 636 | if (ipc_valid_object(out)) |
| 661 | return out; | 637 | return out; |
| 662 | 638 | ||
| 663 | spin_unlock(&out->lock); | 639 | spin_unlock(&out->lock); |
| @@ -693,11 +669,11 @@ out: | |||
| 693 | 669 | ||
| 694 | /** | 670 | /** |
| 695 | * ipcget - Common sys_*get() code | 671 | * ipcget - Common sys_*get() code |
| 696 | * @ns : namsepace | 672 | * @ns: namsepace |
| 697 | * @ids : IPC identifier set | 673 | * @ids: ipc identifier set |
| 698 | * @ops : operations to be called on ipc object creation, permission checks | 674 | * @ops: operations to be called on ipc object creation, permission checks |
| 699 | * and further checks | 675 | * and further checks |
| 700 | * @params : the parameters needed by the previous operations. | 676 | * @params: the parameters needed by the previous operations. |
| 701 | * | 677 | * |
| 702 | * Common routine called by sys_msgget(), sys_semget() and sys_shmget(). | 678 | * Common routine called by sys_msgget(), sys_semget() and sys_shmget(). |
| 703 | */ | 679 | */ |
| @@ -711,7 +687,7 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
| 711 | } | 687 | } |
| 712 | 688 | ||
| 713 | /** | 689 | /** |
| 714 | * ipc_update_perm - update the permissions of an IPC. | 690 | * ipc_update_perm - update the permissions of an ipc object |
| 715 | * @in: the permission given as input. | 691 | * @in: the permission given as input. |
| 716 | * @out: the permission of the ipc to set. | 692 | * @out: the permission of the ipc to set. |
| 717 | */ | 693 | */ |
| @@ -732,7 +708,7 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) | |||
| 732 | 708 | ||
| 733 | /** | 709 | /** |
| 734 | * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd | 710 | * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd |
| 735 | * @ns: the ipc namespace | 711 | * @ns: ipc namespace |
| 736 | * @ids: the table of ids where to look for the ipc | 712 | * @ids: the table of ids where to look for the ipc |
| 737 | * @id: the id of the ipc to retrieve | 713 | * @id: the id of the ipc to retrieve |
| 738 | * @cmd: the cmd to check | 714 | * @cmd: the cmd to check |
| @@ -779,15 +755,14 @@ err: | |||
| 779 | 755 | ||
| 780 | 756 | ||
| 781 | /** | 757 | /** |
| 782 | * ipc_parse_version - IPC call version | 758 | * ipc_parse_version - ipc call version |
| 783 | * @cmd: pointer to command | 759 | * @cmd: pointer to command |
| 784 | * | 760 | * |
| 785 | * Return IPC_64 for new style IPC and IPC_OLD for old style IPC. | 761 | * Return IPC_64 for new style IPC and IPC_OLD for old style IPC. |
| 786 | * The @cmd value is turned from an encoding command and version into | 762 | * The @cmd value is turned from an encoding command and version into |
| 787 | * just the command code. | 763 | * just the command code. |
| 788 | */ | 764 | */ |
| 789 | 765 | int ipc_parse_version(int *cmd) | |
| 790 | int ipc_parse_version (int *cmd) | ||
| 791 | { | 766 | { |
| 792 | if (*cmd & IPC_64) { | 767 | if (*cmd & IPC_64) { |
| 793 | *cmd ^= IPC_64; | 768 | *cmd ^= IPC_64; |
| @@ -824,7 +799,7 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, | |||
| 824 | if (total >= ids->in_use) | 799 | if (total >= ids->in_use) |
| 825 | return NULL; | 800 | return NULL; |
| 826 | 801 | ||
| 827 | for ( ; pos < IPCMNI; pos++) { | 802 | for (; pos < IPCMNI; pos++) { |
| 828 | ipc = idr_find(&ids->ipcs_idr, pos); | 803 | ipc = idr_find(&ids->ipcs_idr, pos); |
| 829 | if (ipc != NULL) { | 804 | if (ipc != NULL) { |
| 830 | *new_pos = pos + 1; | 805 | *new_pos = pos + 1; |
| @@ -927,8 +902,10 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file) | |||
| 927 | goto out; | 902 | goto out; |
| 928 | 903 | ||
| 929 | ret = seq_open(file, &sysvipc_proc_seqops); | 904 | ret = seq_open(file, &sysvipc_proc_seqops); |
| 930 | if (ret) | 905 | if (ret) { |
| 931 | goto out_kfree; | 906 | kfree(iter); |
| 907 | goto out; | ||
| 908 | } | ||
| 932 | 909 | ||
| 933 | seq = file->private_data; | 910 | seq = file->private_data; |
| 934 | seq->private = iter; | 911 | seq->private = iter; |
| @@ -937,9 +914,6 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file) | |||
| 937 | iter->ns = get_ipc_ns(current->nsproxy->ipc_ns); | 914 | iter->ns = get_ipc_ns(current->nsproxy->ipc_ns); |
| 938 | out: | 915 | out: |
| 939 | return ret; | 916 | return ret; |
| 940 | out_kfree: | ||
| 941 | kfree(iter); | ||
| 942 | goto out; | ||
| 943 | } | 917 | } |
| 944 | 918 | ||
| 945 | static int sysvipc_proc_release(struct inode *inode, struct file *file) | 919 | static int sysvipc_proc_release(struct inode *inode, struct file *file) |
diff --git a/ipc/util.h b/ipc/util.h index 59d78aa94987..9c47d6f6c7b4 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
| @@ -15,9 +15,9 @@ | |||
| 15 | 15 | ||
| 16 | #define SEQ_MULTIPLIER (IPCMNI) | 16 | #define SEQ_MULTIPLIER (IPCMNI) |
| 17 | 17 | ||
| 18 | void sem_init (void); | 18 | void sem_init(void); |
| 19 | void msg_init (void); | 19 | void msg_init(void); |
| 20 | void shm_init (void); | 20 | void shm_init(void); |
| 21 | 21 | ||
| 22 | struct ipc_namespace; | 22 | struct ipc_namespace; |
| 23 | 23 | ||
| @@ -100,6 +100,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header, | |||
| 100 | 100 | ||
| 101 | #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) | 101 | #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) |
| 102 | #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER) | 102 | #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER) |
| 103 | #define IPCID_SEQ_MAX min_t(int, INT_MAX/SEQ_MULTIPLIER, USHRT_MAX) | ||
| 103 | 104 | ||
| 104 | /* must be called with ids->rwsem acquired for writing */ | 105 | /* must be called with ids->rwsem acquired for writing */ |
| 105 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); | 106 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); |
| @@ -116,8 +117,8 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); | |||
| 116 | /* for rare, potentially huge allocations. | 117 | /* for rare, potentially huge allocations. |
| 117 | * both function can sleep | 118 | * both function can sleep |
| 118 | */ | 119 | */ |
| 119 | void* ipc_alloc(int size); | 120 | void *ipc_alloc(int size); |
| 120 | void ipc_free(void* ptr, int size); | 121 | void ipc_free(void *ptr, int size); |
| 121 | 122 | ||
| 122 | /* | 123 | /* |
| 123 | * For allocation that need to be freed by RCU. | 124 | * For allocation that need to be freed by RCU. |
| @@ -125,7 +126,7 @@ void ipc_free(void* ptr, int size); | |||
| 125 | * getref increases the refcount, the putref call that reduces the recount | 126 | * getref increases the refcount, the putref call that reduces the recount |
| 126 | * to 0 schedules the rcu destruction. Caller must guarantee locking. | 127 | * to 0 schedules the rcu destruction. Caller must guarantee locking. |
| 127 | */ | 128 | */ |
| 128 | void* ipc_rcu_alloc(int size); | 129 | void *ipc_rcu_alloc(int size); |
| 129 | int ipc_rcu_getref(void *ptr); | 130 | int ipc_rcu_getref(void *ptr); |
| 130 | void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head)); | 131 | void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head)); |
| 131 | void ipc_rcu_free(struct rcu_head *head); | 132 | void ipc_rcu_free(struct rcu_head *head); |
| @@ -144,7 +145,7 @@ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns, | |||
| 144 | /* On IA-64, we always use the "64-bit version" of the IPC structures. */ | 145 | /* On IA-64, we always use the "64-bit version" of the IPC structures. */ |
| 145 | # define ipc_parse_version(cmd) IPC_64 | 146 | # define ipc_parse_version(cmd) IPC_64 |
| 146 | #else | 147 | #else |
| 147 | int ipc_parse_version (int *cmd); | 148 | int ipc_parse_version(int *cmd); |
| 148 | #endif | 149 | #endif |
| 149 | 150 | ||
| 150 | extern void free_msg(struct msg_msg *msg); | 151 | extern void free_msg(struct msg_msg *msg); |
| @@ -185,6 +186,19 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm) | |||
| 185 | rcu_read_unlock(); | 186 | rcu_read_unlock(); |
| 186 | } | 187 | } |
| 187 | 188 | ||
| 189 | /* | ||
| 190 | * ipc_valid_object() - helper to sort out IPC_RMID races for codepaths | ||
| 191 | * where the respective ipc_ids.rwsem is not being held down. | ||
| 192 | * Checks whether the ipc object is still around or if it's gone already, as | ||
| 193 | * ipc_rmid() may have already freed the ID while the ipc lock was spinning. | ||
| 194 | * Needs to be called with kern_ipc_perm.lock held -- exception made for one | ||
| 195 | * checkpoint case at sys_semtimedop() as noted in code commentary. | ||
| 196 | */ | ||
| 197 | static inline bool ipc_valid_object(struct kern_ipc_perm *perm) | ||
| 198 | { | ||
| 199 | return !perm->deleted; | ||
| 200 | } | ||
| 201 | |||
| 188 | struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id); | 202 | struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id); |
| 189 | int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, | 203 | int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, |
| 190 | struct ipc_ops *ops, struct ipc_params *params); | 204 | struct ipc_ops *ops, struct ipc_params *params); |
