1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73#include <linux/slab.h>
74#include <linux/spinlock.h>
75#include <linux/init.h>
76#include <linux/proc_fs.h>
77#include <linux/time.h>
78#include <linux/security.h>
79#include <linux/syscalls.h>
80#include <linux/audit.h>
81#include <linux/capability.h>
82#include <linux/seq_file.h>
83#include <linux/rwsem.h>
84#include <linux/nsproxy.h>
85#include <linux/ipc_namespace.h>
86
87#include <asm/uaccess.h>
88#include "util.h"
89
90#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS])
91
92#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
93#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid)
94
95static int newary(struct ipc_namespace *, struct ipc_params *);
96static void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
97#ifdef CONFIG_PROC_FS
98static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
99#endif
100
101#define SEMMSL_FAST 256
102#define SEMOPM_FAST 64
103
104
105
106
107
108
109
110
111
112
113#define sc_semmsl sem_ctls[0]
114#define sc_semmns sem_ctls[1]
115#define sc_semopm sem_ctls[2]
116#define sc_semmni sem_ctls[3]
117
118void sem_init_ns(struct ipc_namespace *ns)
119{
120 ns->sc_semmsl = SEMMSL;
121 ns->sc_semmns = SEMMNS;
122 ns->sc_semopm = SEMOPM;
123 ns->sc_semmni = SEMMNI;
124 ns->used_sems = 0;
125 ipc_init_ids(&ns->ids[IPC_SEM_IDS]);
126}
127
128#ifdef CONFIG_IPC_NS
129void sem_exit_ns(struct ipc_namespace *ns)
130{
131 free_ipcs(ns, &sem_ids(ns), freeary);
132}
133#endif
134
135void __init sem_init (void)
136{
137 sem_init_ns(&init_ipc_ns);
138 ipc_init_proc_interface("sysvipc/sem",
139 " key semid perms nsems uid gid cuid cgid otime ctime\n",
140 IPC_SEM_IDS, sysvipc_sem_proc_show);
141}
142
143
144
145
146
147static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
148{
149 struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
150
151 if (IS_ERR(ipcp))
152 return (struct sem_array *)ipcp;
153
154 return container_of(ipcp, struct sem_array, sem_perm);
155}
156
157static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
158 int id)
159{
160 struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
161
162 if (IS_ERR(ipcp))
163 return (struct sem_array *)ipcp;
164
165 return container_of(ipcp, struct sem_array, sem_perm);
166}
167
168static inline void sem_lock_and_putref(struct sem_array *sma)
169{
170 ipc_lock_by_ptr(&sma->sem_perm);
171 ipc_rcu_putref(sma);
172}
173
174static inline void sem_getref_and_unlock(struct sem_array *sma)
175{
176 ipc_rcu_getref(sma);
177 ipc_unlock(&(sma)->sem_perm);
178}
179
180static inline void sem_putref(struct sem_array *sma)
181{
182 ipc_lock_by_ptr(&sma->sem_perm);
183 ipc_rcu_putref(sma);
184 ipc_unlock(&(sma)->sem_perm);
185}
186
187static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
188{
189 ipc_rmid(&sem_ids(ns), &s->sem_perm);
190}
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224#define IN_WAKEUP 1
225
226
227
228
229
230
231
232
233
234static int newary(struct ipc_namespace *ns, struct ipc_params *params)
235{
236 int id;
237 int retval;
238 struct sem_array *sma;
239 int size;
240 key_t key = params->key;
241 int nsems = params->u.nsems;
242 int semflg = params->flg;
243
244 if (!nsems)
245 return -EINVAL;
246 if (ns->used_sems + nsems > ns->sc_semmns)
247 return -ENOSPC;
248
249 size = sizeof (*sma) + nsems * sizeof (struct sem);
250 sma = ipc_rcu_alloc(size);
251 if (!sma) {
252 return -ENOMEM;
253 }
254 memset (sma, 0, size);
255
256 sma->sem_perm.mode = (semflg & S_IRWXUGO);
257 sma->sem_perm.key = key;
258
259 sma->sem_perm.security = NULL;
260 retval = security_sem_alloc(sma);
261 if (retval) {
262 ipc_rcu_putref(sma);
263 return retval;
264 }
265
266 id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
267 if (id < 0) {
268 security_sem_free(sma);
269 ipc_rcu_putref(sma);
270 return id;
271 }
272 ns->used_sems += nsems;
273
274 sma->sem_base = (struct sem *) &sma[1];
275 INIT_LIST_HEAD(&sma->sem_pending);
276 INIT_LIST_HEAD(&sma->list_id);
277 sma->sem_nsems = nsems;
278 sma->sem_ctime = get_seconds();
279 sem_unlock(sma);
280
281 return sma->sem_perm.id;
282}
283
284
285
286
287
288static inline int sem_security(struct kern_ipc_perm *ipcp, int semflg)
289{
290 struct sem_array *sma;
291
292 sma = container_of(ipcp, struct sem_array, sem_perm);
293 return security_sem_associate(sma, semflg);
294}
295
296
297
298
299static inline int sem_more_checks(struct kern_ipc_perm *ipcp,
300 struct ipc_params *params)
301{
302 struct sem_array *sma;
303
304 sma = container_of(ipcp, struct sem_array, sem_perm);
305 if (params->u.nsems > sma->sem_nsems)
306 return -EINVAL;
307
308 return 0;
309}
310
311asmlinkage long sys_semget(key_t key, int nsems, int semflg)
312{
313 struct ipc_namespace *ns;
314 struct ipc_ops sem_ops;
315 struct ipc_params sem_params;
316
317 ns = current->nsproxy->ipc_ns;
318
319 if (nsems < 0 || nsems > ns->sc_semmsl)
320 return -EINVAL;
321
322 sem_ops.getnew = newary;
323 sem_ops.associate = sem_security;
324 sem_ops.more_checks = sem_more_checks;
325
326 sem_params.key = key;
327 sem_params.flg = semflg;
328 sem_params.u.nsems = nsems;
329
330 return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
331}
332
333
334
335
336
337
338static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
339 int nsops, struct sem_undo *un, int pid)
340{
341 int result, sem_op;
342 struct sembuf *sop;
343 struct sem * curr;
344
345 for (sop = sops; sop < sops + nsops; sop++) {
346 curr = sma->sem_base + sop->sem_num;
347 sem_op = sop->sem_op;
348 result = curr->semval;
349
350 if (!sem_op && result)
351 goto would_block;
352
353 result += sem_op;
354 if (result < 0)
355 goto would_block;
356 if (result > SEMVMX)
357 goto out_of_range;
358 if (sop->sem_flg & SEM_UNDO) {
359 int undo = un->semadj[sop->sem_num] - sem_op;
360
361
362
363 if (undo < (-SEMAEM - 1) || undo > SEMAEM)
364 goto out_of_range;
365 }
366 curr->semval = result;
367 }
368
369 sop--;
370 while (sop >= sops) {
371 sma->sem_base[sop->sem_num].sempid = pid;
372 if (sop->sem_flg & SEM_UNDO)
373 un->semadj[sop->sem_num] -= sop->sem_op;
374 sop--;
375 }
376
377 sma->sem_otime = get_seconds();
378 return 0;
379
380out_of_range:
381 result = -ERANGE;
382 goto undo;
383
384would_block:
385 if (sop->sem_flg & IPC_NOWAIT)
386 result = -EAGAIN;
387 else
388 result = 1;
389
390undo:
391 sop--;
392 while (sop >= sops) {
393 sma->sem_base[sop->sem_num].semval -= sop->sem_op;
394 sop--;
395 }
396
397 return result;
398}
399
400
401
402
403static void update_queue (struct sem_array * sma)
404{
405 int error;
406 struct sem_queue * q;
407
408 q = list_entry(sma->sem_pending.next, struct sem_queue, list);
409 while (&q->list != &sma->sem_pending) {
410 error = try_atomic_semop(sma, q->sops, q->nsops,
411 q->undo, q->pid);
412
413
414 if (error <= 0) {
415 struct sem_queue *n;
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434 if (q->alter) {
435 list_del(&q->list);
436 n = list_entry(sma->sem_pending.next,
437 struct sem_queue, list);
438 } else {
439 n = list_entry(q->list.next, struct sem_queue,
440 list);
441 list_del(&q->list);
442 }
443
444
445 q->status = IN_WAKEUP;
446
447 wake_up_process(q->sleeper);
448
449
450
451 smp_wmb();
452 q->status = error;
453 q = n;
454 } else {
455 q = list_entry(q->list.next, struct sem_queue, list);
456 }
457 }
458}
459
460
461
462
463
464
465
466
467
468
469static int count_semncnt (struct sem_array * sma, ushort semnum)
470{
471 int semncnt;
472 struct sem_queue * q;
473
474 semncnt = 0;
475 list_for_each_entry(q, &sma->sem_pending, list) {
476 struct sembuf * sops = q->sops;
477 int nsops = q->nsops;
478 int i;
479 for (i = 0; i < nsops; i++)
480 if (sops[i].sem_num == semnum
481 && (sops[i].sem_op < 0)
482 && !(sops[i].sem_flg & IPC_NOWAIT))
483 semncnt++;
484 }
485 return semncnt;
486}
487
488static int count_semzcnt (struct sem_array * sma, ushort semnum)
489{
490 int semzcnt;
491 struct sem_queue * q;
492
493 semzcnt = 0;
494 list_for_each_entry(q, &sma->sem_pending, list) {
495 struct sembuf * sops = q->sops;
496 int nsops = q->nsops;
497 int i;
498 for (i = 0; i < nsops; i++)
499 if (sops[i].sem_num == semnum
500 && (sops[i].sem_op == 0)
501 && !(sops[i].sem_flg & IPC_NOWAIT))
502 semzcnt++;
503 }
504 return semzcnt;
505}
506
507static void free_un(struct rcu_head *head)
508{
509 struct sem_undo *un = container_of(head, struct sem_undo, rcu);
510 kfree(un);
511}
512
513
514
515
516
517static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
518{
519 struct sem_undo *un, *tu;
520 struct sem_queue *q, *tq;
521 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
522
523
524 assert_spin_locked(&sma->sem_perm.lock);
525 list_for_each_entry_safe(un, tu, &sma->list_id, list_id) {
526 list_del(&un->list_id);
527 spin_lock(&un->ulp->lock);
528 un->semid = -1;
529 list_del_rcu(&un->list_proc);
530 spin_unlock(&un->ulp->lock);
531 call_rcu(&un->rcu, free_un);
532 }
533
534
535 list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
536 list_del(&q->list);
537
538 q->status = IN_WAKEUP;
539 wake_up_process(q->sleeper);
540 smp_wmb();
541 q->status = -EIDRM;
542 }
543
544
545 sem_rmid(ns, sma);
546 sem_unlock(sma);
547
548 ns->used_sems -= sma->sem_nsems;
549 security_sem_free(sma);
550 ipc_rcu_putref(sma);
551}
552
553static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
554{
555 switch(version) {
556 case IPC_64:
557 return copy_to_user(buf, in, sizeof(*in));
558 case IPC_OLD:
559 {
560 struct semid_ds out;
561
562 ipc64_perm_to_ipc_perm(&in->sem_perm, &out.sem_perm);
563
564 out.sem_otime = in->sem_otime;
565 out.sem_ctime = in->sem_ctime;
566 out.sem_nsems = in->sem_nsems;
567
568 return copy_to_user(buf, &out, sizeof(out));
569 }
570 default:
571 return -EINVAL;
572 }
573}
574
575static int semctl_nolock(struct ipc_namespace *ns, int semid,
576 int cmd, int version, union semun arg)
577{
578 int err = -EINVAL;
579 struct sem_array *sma;
580
581 switch(cmd) {
582 case IPC_INFO:
583 case SEM_INFO:
584 {
585 struct seminfo seminfo;
586 int max_id;
587
588 err = security_sem_semctl(NULL, cmd);
589 if (err)
590 return err;
591
592 memset(&seminfo,0,sizeof(seminfo));
593 seminfo.semmni = ns->sc_semmni;
594 seminfo.semmns = ns->sc_semmns;
595 seminfo.semmsl = ns->sc_semmsl;
596 seminfo.semopm = ns->sc_semopm;
597 seminfo.semvmx = SEMVMX;
598 seminfo.semmnu = SEMMNU;
599 seminfo.semmap = SEMMAP;
600 seminfo.semume = SEMUME;
601 down_read(&sem_ids(ns).rw_mutex);
602 if (cmd == SEM_INFO) {
603 seminfo.semusz = sem_ids(ns).in_use;
604 seminfo.semaem = ns->used_sems;
605 } else {
606 seminfo.semusz = SEMUSZ;
607 seminfo.semaem = SEMAEM;
608 }
609 max_id = ipc_get_maxid(&sem_ids(ns));
610 up_read(&sem_ids(ns).rw_mutex);
611 if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
612 return -EFAULT;
613 return (max_id < 0) ? 0: max_id;
614 }
615 case IPC_STAT:
616 case SEM_STAT:
617 {
618 struct semid64_ds tbuf;
619 int id;
620
621 if (cmd == SEM_STAT) {
622 sma = sem_lock(ns, semid);
623 if (IS_ERR(sma))
624 return PTR_ERR(sma);
625 id = sma->sem_perm.id;
626 } else {
627 sma = sem_lock_check(ns, semid);
628 if (IS_ERR(sma))
629 return PTR_ERR(sma);
630 id = 0;
631 }
632
633 err = -EACCES;
634 if (ipcperms (&sma->sem_perm, S_IRUGO))
635 goto out_unlock;
636
637 err = security_sem_semctl(sma, cmd);
638 if (err)
639 goto out_unlock;
640
641 memset(&tbuf, 0, sizeof(tbuf));
642
643 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
644 tbuf.sem_otime = sma->sem_otime;
645 tbuf.sem_ctime = sma->sem_ctime;
646 tbuf.sem_nsems = sma->sem_nsems;
647 sem_unlock(sma);
648 if (copy_semid_to_user (arg.buf, &tbuf, version))
649 return -EFAULT;
650 return id;
651 }
652 default:
653 return -EINVAL;
654 }
655 return err;
656out_unlock:
657 sem_unlock(sma);
658 return err;
659}
660
661static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
662 int cmd, int version, union semun arg)
663{
664 struct sem_array *sma;
665 struct sem* curr;
666 int err;
667 ushort fast_sem_io[SEMMSL_FAST];
668 ushort* sem_io = fast_sem_io;
669 int nsems;
670
671 sma = sem_lock_check(ns, semid);
672 if (IS_ERR(sma))
673 return PTR_ERR(sma);
674
675 nsems = sma->sem_nsems;
676
677 err = -EACCES;
678 if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO))
679 goto out_unlock;
680
681 err = security_sem_semctl(sma, cmd);
682 if (err)
683 goto out_unlock;
684
685 err = -EACCES;
686 switch (cmd) {
687 case GETALL:
688 {
689 ushort __user *array = arg.array;
690 int i;
691
692 if(nsems > SEMMSL_FAST) {
693 sem_getref_and_unlock(sma);
694
695 sem_io = ipc_alloc(sizeof(ushort)*nsems);
696 if(sem_io == NULL) {
697 sem_putref(sma);
698 return -ENOMEM;
699 }
700
701 sem_lock_and_putref(sma);
702 if (sma->sem_perm.deleted) {
703 sem_unlock(sma);
704 err = -EIDRM;
705 goto out_free;
706 }
707 }
708
709 for (i = 0; i < sma->sem_nsems; i++)
710 sem_io[i] = sma->sem_base[i].semval;
711 sem_unlock(sma);
712 err = 0;
713 if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
714 err = -EFAULT;
715 goto out_free;
716 }
717 case SETALL:
718 {
719 int i;
720 struct sem_undo *un;
721
722 sem_getref_and_unlock(sma);
723
724 if(nsems > SEMMSL_FAST) {
725 sem_io = ipc_alloc(sizeof(ushort)*nsems);
726 if(sem_io == NULL) {
727 sem_putref(sma);
728 return -ENOMEM;
729 }
730 }
731
732 if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
733 sem_putref(sma);
734 err = -EFAULT;
735 goto out_free;
736 }
737
738 for (i = 0; i < nsems; i++) {
739 if (sem_io[i] > SEMVMX) {
740 sem_putref(sma);
741 err = -ERANGE;
742 goto out_free;
743 }
744 }
745 sem_lock_and_putref(sma);
746 if (sma->sem_perm.deleted) {
747 sem_unlock(sma);
748 err = -EIDRM;
749 goto out_free;
750 }
751
752 for (i = 0; i < nsems; i++)
753 sma->sem_base[i].semval = sem_io[i];
754
755 assert_spin_locked(&sma->sem_perm.lock);
756 list_for_each_entry(un, &sma->list_id, list_id) {
757 for (i = 0; i < nsems; i++)
758 un->semadj[i] = 0;
759 }
760 sma->sem_ctime = get_seconds();
761
762 update_queue(sma);
763 err = 0;
764 goto out_unlock;
765 }
766
767 }
768 err = -EINVAL;
769 if(semnum < 0 || semnum >= nsems)
770 goto out_unlock;
771
772 curr = &sma->sem_base[semnum];
773
774 switch (cmd) {
775 case GETVAL:
776 err = curr->semval;
777 goto out_unlock;
778 case GETPID:
779 err = curr->sempid;
780 goto out_unlock;
781 case GETNCNT:
782 err = count_semncnt(sma,semnum);
783 goto out_unlock;
784 case GETZCNT:
785 err = count_semzcnt(sma,semnum);
786 goto out_unlock;
787 case SETVAL:
788 {
789 int val = arg.val;
790 struct sem_undo *un;
791
792 err = -ERANGE;
793 if (val > SEMVMX || val < 0)
794 goto out_unlock;
795
796 assert_spin_locked(&sma->sem_perm.lock);
797 list_for_each_entry(un, &sma->list_id, list_id)
798 un->semadj[semnum] = 0;
799
800 curr->semval = val;
801 curr->sempid = task_tgid_vnr(current);
802 sma->sem_ctime = get_seconds();
803
804 update_queue(sma);
805 err = 0;
806 goto out_unlock;
807 }
808 }
809out_unlock:
810 sem_unlock(sma);
811out_free:
812 if(sem_io != fast_sem_io)
813 ipc_free(sem_io, sizeof(ushort)*nsems);
814 return err;
815}
816
817static inline unsigned long
818copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
819{
820 switch(version) {
821 case IPC_64:
822 if (copy_from_user(out, buf, sizeof(*out)))
823 return -EFAULT;
824 return 0;
825 case IPC_OLD:
826 {
827 struct semid_ds tbuf_old;
828
829 if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
830 return -EFAULT;
831
832 out->sem_perm.uid = tbuf_old.sem_perm.uid;
833 out->sem_perm.gid = tbuf_old.sem_perm.gid;
834 out->sem_perm.mode = tbuf_old.sem_perm.mode;
835
836 return 0;
837 }
838 default:
839 return -EINVAL;
840 }
841}
842
843
844
845
846
847
848static int semctl_down(struct ipc_namespace *ns, int semid,
849 int cmd, int version, union semun arg)
850{
851 struct sem_array *sma;
852 int err;
853 struct semid64_ds semid64;
854 struct kern_ipc_perm *ipcp;
855
856 if(cmd == IPC_SET) {
857 if (copy_semid_from_user(&semid64, arg.buf, version))
858 return -EFAULT;
859 }
860
861 ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0);
862 if (IS_ERR(ipcp))
863 return PTR_ERR(ipcp);
864
865 sma = container_of(ipcp, struct sem_array, sem_perm);
866
867 err = security_sem_semctl(sma, cmd);
868 if (err)
869 goto out_unlock;
870
871 switch(cmd){
872 case IPC_RMID:
873 freeary(ns, ipcp);
874 goto out_up;
875 case IPC_SET:
876 ipc_update_perm(&semid64.sem_perm, ipcp);
877 sma->sem_ctime = get_seconds();
878 break;
879 default:
880 err = -EINVAL;
881 }
882
883out_unlock:
884 sem_unlock(sma);
885out_up:
886 up_write(&sem_ids(ns).rw_mutex);
887 return err;
888}
889
890asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
891{
892 int err = -EINVAL;
893 int version;
894 struct ipc_namespace *ns;
895
896 if (semid < 0)
897 return -EINVAL;
898
899 version = ipc_parse_version(&cmd);
900 ns = current->nsproxy->ipc_ns;
901
902 switch(cmd) {
903 case IPC_INFO:
904 case SEM_INFO:
905 case IPC_STAT:
906 case SEM_STAT:
907 err = semctl_nolock(ns, semid, cmd, version, arg);
908 return err;
909 case GETALL:
910 case GETVAL:
911 case GETPID:
912 case GETNCNT:
913 case GETZCNT:
914 case SETVAL:
915 case SETALL:
916 err = semctl_main(ns,semid,semnum,cmd,version,arg);
917 return err;
918 case IPC_RMID:
919 case IPC_SET:
920 err = semctl_down(ns, semid, cmd, version, arg);
921 return err;
922 default:
923 return -EINVAL;
924 }
925}
926
927
928
929
930
931
932
933
934
935
936
937
938static inline int get_undo_list(struct sem_undo_list **undo_listp)
939{
940 struct sem_undo_list *undo_list;
941
942 undo_list = current->sysvsem.undo_list;
943 if (!undo_list) {
944 undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL);
945 if (undo_list == NULL)
946 return -ENOMEM;
947 spin_lock_init(&undo_list->lock);
948 atomic_set(&undo_list->refcnt, 1);
949 INIT_LIST_HEAD(&undo_list->list_proc);
950
951 current->sysvsem.undo_list = undo_list;
952 }
953 *undo_listp = undo_list;
954 return 0;
955}
956
957static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
958{
959 struct sem_undo *walk;
960
961 list_for_each_entry_rcu(walk, &ulp->list_proc, list_proc) {
962 if (walk->semid == semid)
963 return walk;
964 }
965 return NULL;
966}
967
968
969
970
971
972
973
974
975
976
977
978
979static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
980{
981 struct sem_array *sma;
982 struct sem_undo_list *ulp;
983 struct sem_undo *un, *new;
984 int nsems;
985 int error;
986
987 error = get_undo_list(&ulp);
988 if (error)
989 return ERR_PTR(error);
990
991 rcu_read_lock();
992 spin_lock(&ulp->lock);
993 un = lookup_undo(ulp, semid);
994 spin_unlock(&ulp->lock);
995 if (likely(un!=NULL))
996 goto out;
997 rcu_read_unlock();
998
999
1000
1001 sma = sem_lock_check(ns, semid);
1002 if (IS_ERR(sma))
1003 return ERR_PTR(PTR_ERR(sma));
1004
1005 nsems = sma->sem_nsems;
1006 sem_getref_and_unlock(sma);
1007
1008
1009 new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
1010 if (!new) {
1011 sem_putref(sma);
1012 return ERR_PTR(-ENOMEM);
1013 }
1014
1015
1016 sem_lock_and_putref(sma);
1017 if (sma->sem_perm.deleted) {
1018 sem_unlock(sma);
1019 kfree(new);
1020 un = ERR_PTR(-EIDRM);
1021 goto out;
1022 }
1023 spin_lock(&ulp->lock);
1024
1025
1026
1027
1028 un = lookup_undo(ulp, semid);
1029 if (un) {
1030 kfree(new);
1031 goto success;
1032 }
1033
1034 new->semadj = (short *) &new[1];
1035 new->ulp = ulp;
1036 new->semid = semid;
1037 assert_spin_locked(&ulp->lock);
1038 list_add_rcu(&new->list_proc, &ulp->list_proc);
1039 assert_spin_locked(&sma->sem_perm.lock);
1040 list_add(&new->list_id, &sma->list_id);
1041 un = new;
1042
1043success:
1044 spin_unlock(&ulp->lock);
1045 rcu_read_lock();
1046 sem_unlock(sma);
1047out:
1048 return un;
1049}
1050
1051asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
1052 unsigned nsops, const struct timespec __user *timeout)
1053{
1054 int error = -EINVAL;
1055 struct sem_array *sma;
1056 struct sembuf fast_sops[SEMOPM_FAST];
1057 struct sembuf* sops = fast_sops, *sop;
1058 struct sem_undo *un;
1059 int undos = 0, alter = 0, max;
1060 struct sem_queue queue;
1061 unsigned long jiffies_left = 0;
1062 struct ipc_namespace *ns;
1063
1064 ns = current->nsproxy->ipc_ns;
1065
1066 if (nsops < 1 || semid < 0)
1067 return -EINVAL;
1068 if (nsops > ns->sc_semopm)
1069 return -E2BIG;
1070 if(nsops > SEMOPM_FAST) {
1071 sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
1072 if(sops==NULL)
1073 return -ENOMEM;
1074 }
1075 if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
1076 error=-EFAULT;
1077 goto out_free;
1078 }
1079 if (timeout) {
1080 struct timespec _timeout;
1081 if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) {
1082 error = -EFAULT;
1083 goto out_free;
1084 }
1085 if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 ||
1086 _timeout.tv_nsec >= 1000000000L) {
1087 error = -EINVAL;
1088 goto out_free;
1089 }
1090 jiffies_left = timespec_to_jiffies(&_timeout);
1091 }
1092 max = 0;
1093 for (sop = sops; sop < sops + nsops; sop++) {
1094 if (sop->sem_num >= max)
1095 max = sop->sem_num;
1096 if (sop->sem_flg & SEM_UNDO)
1097 undos = 1;
1098 if (sop->sem_op != 0)
1099 alter = 1;
1100 }
1101
1102 if (undos) {
1103 un = find_alloc_undo(ns, semid);
1104 if (IS_ERR(un)) {
1105 error = PTR_ERR(un);
1106 goto out_free;
1107 }
1108 } else
1109 un = NULL;
1110
1111 sma = sem_lock_check(ns, semid);
1112 if (IS_ERR(sma)) {
1113 if (un)
1114 rcu_read_unlock();
1115 error = PTR_ERR(sma);
1116 goto out_free;
1117 }
1118
1119
1120
1121
1122
1123
1124
1125
1126 error = -EIDRM;
1127 if (un) {
1128 if (un->semid == -1) {
1129 rcu_read_unlock();
1130 goto out_unlock_free;
1131 } else {
1132
1133
1134
1135
1136
1137
1138
1139
1140 rcu_read_unlock();
1141 }
1142 }
1143
1144 error = -EFBIG;
1145 if (max >= sma->sem_nsems)
1146 goto out_unlock_free;
1147
1148 error = -EACCES;
1149 if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
1150 goto out_unlock_free;
1151
1152 error = security_sem_semop(sma, sops, nsops, alter);
1153 if (error)
1154 goto out_unlock_free;
1155
1156 error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
1157 if (error <= 0) {
1158 if (alter && error == 0)
1159 update_queue (sma);
1160 goto out_unlock_free;
1161 }
1162
1163
1164
1165
1166
1167 queue.sops = sops;
1168 queue.nsops = nsops;
1169 queue.undo = un;
1170 queue.pid = task_tgid_vnr(current);
1171 queue.alter = alter;
1172 if (alter)
1173 list_add_tail(&queue.list, &sma->sem_pending);
1174 else
1175 list_add(&queue.list, &sma->sem_pending);
1176
1177 queue.status = -EINTR;
1178 queue.sleeper = current;
1179 current->state = TASK_INTERRUPTIBLE;
1180 sem_unlock(sma);
1181
1182 if (timeout)
1183 jiffies_left = schedule_timeout(jiffies_left);
1184 else
1185 schedule();
1186
1187 error = queue.status;
1188 while(unlikely(error == IN_WAKEUP)) {
1189 cpu_relax();
1190 error = queue.status;
1191 }
1192
1193 if (error != -EINTR) {
1194
1195
1196 goto out_free;
1197 }
1198
1199 sma = sem_lock(ns, semid);
1200 if (IS_ERR(sma)) {
1201 error = -EIDRM;
1202 goto out_free;
1203 }
1204
1205
1206
1207
1208 error = queue.status;
1209 if (error != -EINTR) {
1210 goto out_unlock_free;
1211 }
1212
1213
1214
1215
1216 if (timeout && jiffies_left == 0)
1217 error = -EAGAIN;
1218 list_del(&queue.list);
1219 goto out_unlock_free;
1220
1221out_unlock_free:
1222 sem_unlock(sma);
1223out_free:
1224 if(sops != fast_sops)
1225 kfree(sops);
1226 return error;
1227}
1228
1229asmlinkage long sys_semop (int semid, struct sembuf __user *tsops, unsigned nsops)
1230{
1231 return sys_semtimedop(semid, tsops, nsops, NULL);
1232}
1233
1234
1235
1236
1237
1238int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
1239{
1240 struct sem_undo_list *undo_list;
1241 int error;
1242
1243 if (clone_flags & CLONE_SYSVSEM) {
1244 error = get_undo_list(&undo_list);
1245 if (error)
1246 return error;
1247 atomic_inc(&undo_list->refcnt);
1248 tsk->sysvsem.undo_list = undo_list;
1249 } else
1250 tsk->sysvsem.undo_list = NULL;
1251
1252 return 0;
1253}
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267void exit_sem(struct task_struct *tsk)
1268{
1269 struct sem_undo_list *ulp;
1270
1271 ulp = tsk->sysvsem.undo_list;
1272 if (!ulp)
1273 return;
1274 tsk->sysvsem.undo_list = NULL;
1275
1276 if (!atomic_dec_and_test(&ulp->refcnt))
1277 return;
1278
1279 for (;;) {
1280 struct sem_array *sma;
1281 struct sem_undo *un;
1282 int semid;
1283 int i;
1284
1285 rcu_read_lock();
1286 un = list_entry(rcu_dereference(ulp->list_proc.next),
1287 struct sem_undo, list_proc);
1288 if (&un->list_proc == &ulp->list_proc)
1289 semid = -1;
1290 else
1291 semid = un->semid;
1292 rcu_read_unlock();
1293
1294 if (semid == -1)
1295 break;
1296
1297 sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
1298
1299
1300 if (IS_ERR(sma))
1301 continue;
1302
1303 un = lookup_undo(ulp, semid);
1304 if (un == NULL) {
1305
1306
1307
1308 sem_unlock(sma);
1309 continue;
1310 }
1311
1312
1313 assert_spin_locked(&sma->sem_perm.lock);
1314 list_del(&un->list_id);
1315
1316 spin_lock(&ulp->lock);
1317 list_del_rcu(&un->list_proc);
1318 spin_unlock(&ulp->lock);
1319
1320
1321 for (i = 0; i < sma->sem_nsems; i++) {
1322 struct sem * semaphore = &sma->sem_base[i];
1323 if (un->semadj[i]) {
1324 semaphore->semval += un->semadj[i];
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338 if (semaphore->semval < 0)
1339 semaphore->semval = 0;
1340 if (semaphore->semval > SEMVMX)
1341 semaphore->semval = SEMVMX;
1342 semaphore->sempid = task_tgid_vnr(current);
1343 }
1344 }
1345 sma->sem_otime = get_seconds();
1346
1347 update_queue(sma);
1348 sem_unlock(sma);
1349
1350 call_rcu(&un->rcu, free_un);
1351 }
1352 kfree(ulp);
1353}
1354
1355#ifdef CONFIG_PROC_FS
1356static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
1357{
1358 struct sem_array *sma = it;
1359
1360 return seq_printf(s,
1361 "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
1362 sma->sem_perm.key,
1363 sma->sem_perm.id,
1364 sma->sem_perm.mode,
1365 sma->sem_nsems,
1366 sma->sem_perm.uid,
1367 sma->sem_perm.gid,
1368 sma->sem_perm.cuid,
1369 sma->sem_perm.cgid,
1370 sma->sem_otime,
1371 sma->sem_ctime);
1372}
1373#endif