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