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
692
693
694
695
696static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
697{
698 struct sem_undo *un, *tu;
699 struct sem_queue *q, *tq;
700 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
701 struct list_head tasks;
702
703
704 assert_spin_locked(&sma->sem_perm.lock);
705 list_for_each_entry_safe(un, tu, &sma->list_id, list_id) {
706 list_del(&un->list_id);
707 spin_lock(&un->ulp->lock);
708 un->semid = -1;
709 list_del_rcu(&un->list_proc);
710 spin_unlock(&un->ulp->lock);
711 kfree_rcu(un, rcu);
712 }
713
714
715 INIT_LIST_HEAD(&tasks);
716 list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
717 unlink_queue(sma, q);
718 wake_up_sem_queue_prepare(&tasks, q, -EIDRM);
719 }
720
721
722 sem_rmid(ns, sma);
723 sem_unlock(sma);
724
725 wake_up_sem_queue_do(&tasks);
726 ns->used_sems -= sma->sem_nsems;
727 security_sem_free(sma);
728 ipc_rcu_putref(sma);
729}
730
731static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
732{
733 switch(version) {
734 case IPC_64:
735 return copy_to_user(buf, in, sizeof(*in));
736 case IPC_OLD:
737 {
738 struct semid_ds out;
739
740 memset(&out, 0, sizeof(out));
741
742 ipc64_perm_to_ipc_perm(&in->sem_perm, &out.sem_perm);
743
744 out.sem_otime = in->sem_otime;
745 out.sem_ctime = in->sem_ctime;
746 out.sem_nsems = in->sem_nsems;
747
748 return copy_to_user(buf, &out, sizeof(out));
749 }
750 default:
751 return -EINVAL;
752 }
753}
754
755static int semctl_nolock(struct ipc_namespace *ns, int semid,
756 int cmd, int version, union semun arg)
757{
758 int err;
759 struct sem_array *sma;
760
761 switch(cmd) {
762 case IPC_INFO:
763 case SEM_INFO:
764 {
765 struct seminfo seminfo;
766 int max_id;
767
768 err = security_sem_semctl(NULL, cmd);
769 if (err)
770 return err;
771
772 memset(&seminfo,0,sizeof(seminfo));
773 seminfo.semmni = ns->sc_semmni;
774 seminfo.semmns = ns->sc_semmns;
775 seminfo.semmsl = ns->sc_semmsl;
776 seminfo.semopm = ns->sc_semopm;
777 seminfo.semvmx = SEMVMX;
778 seminfo.semmnu = SEMMNU;
779 seminfo.semmap = SEMMAP;
780 seminfo.semume = SEMUME;
781 down_read(&sem_ids(ns).rw_mutex);
782 if (cmd == SEM_INFO) {
783 seminfo.semusz = sem_ids(ns).in_use;
784 seminfo.semaem = ns->used_sems;
785 } else {
786 seminfo.semusz = SEMUSZ;
787 seminfo.semaem = SEMAEM;
788 }
789 max_id = ipc_get_maxid(&sem_ids(ns));
790 up_read(&sem_ids(ns).rw_mutex);
791 if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
792 return -EFAULT;
793 return (max_id < 0) ? 0: max_id;
794 }
795 case IPC_STAT:
796 case SEM_STAT:
797 {
798 struct semid64_ds tbuf;
799 int id;
800
801 if (cmd == SEM_STAT) {
802 sma = sem_lock(ns, semid);
803 if (IS_ERR(sma))
804 return PTR_ERR(sma);
805 id = sma->sem_perm.id;
806 } else {
807 sma = sem_lock_check(ns, semid);
808 if (IS_ERR(sma))
809 return PTR_ERR(sma);
810 id = 0;
811 }
812
813 err = -EACCES;
814 if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
815 goto out_unlock;
816
817 err = security_sem_semctl(sma, cmd);
818 if (err)
819 goto out_unlock;
820
821 memset(&tbuf, 0, sizeof(tbuf));
822
823 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
824 tbuf.sem_otime = sma->sem_otime;
825 tbuf.sem_ctime = sma->sem_ctime;
826 tbuf.sem_nsems = sma->sem_nsems;
827 sem_unlock(sma);
828 if (copy_semid_to_user (arg.buf, &tbuf, version))
829 return -EFAULT;
830 return id;
831 }
832 default:
833 return -EINVAL;
834 }
835out_unlock:
836 sem_unlock(sma);
837 return err;
838}
839
840static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
841 int cmd, int version, union semun arg)
842{
843 struct sem_array *sma;
844 struct sem* curr;
845 int err;
846 ushort fast_sem_io[SEMMSL_FAST];
847 ushort* sem_io = fast_sem_io;
848 int nsems;
849 struct list_head tasks;
850
851 sma = sem_lock_check(ns, semid);
852 if (IS_ERR(sma))
853 return PTR_ERR(sma);
854
855 INIT_LIST_HEAD(&tasks);
856 nsems = sma->sem_nsems;
857
858 err = -EACCES;
859 if (ipcperms(ns, &sma->sem_perm,
860 (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO))
861 goto out_unlock;
862
863 err = security_sem_semctl(sma, cmd);
864 if (err)
865 goto out_unlock;
866
867 err = -EACCES;
868 switch (cmd) {
869 case GETALL:
870 {
871 ushort __user *array = arg.array;
872 int i;
873
874 if(nsems > SEMMSL_FAST) {
875 sem_getref_and_unlock(sma);
876
877 sem_io = ipc_alloc(sizeof(ushort)*nsems);
878 if(sem_io == NULL) {
879 sem_putref(sma);
880 return -ENOMEM;
881 }
882
883 sem_lock_and_putref(sma);
884 if (sma->sem_perm.deleted) {
885 sem_unlock(sma);
886 err = -EIDRM;
887 goto out_free;
888 }
889 }
890
891 for (i = 0; i < sma->sem_nsems; i++)
892 sem_io[i] = sma->sem_base[i].semval;
893 sem_unlock(sma);
894 err = 0;
895 if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
896 err = -EFAULT;
897 goto out_free;
898 }
899 case SETALL:
900 {
901 int i;
902 struct sem_undo *un;
903
904 sem_getref_and_unlock(sma);
905
906 if(nsems > SEMMSL_FAST) {
907 sem_io = ipc_alloc(sizeof(ushort)*nsems);
908 if(sem_io == NULL) {
909 sem_putref(sma);
910 return -ENOMEM;
911 }
912 }
913
914 if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
915 sem_putref(sma);
916 err = -EFAULT;
917 goto out_free;
918 }
919
920 for (i = 0; i < nsems; i++) {
921 if (sem_io[i] > SEMVMX) {
922 sem_putref(sma);
923 err = -ERANGE;
924 goto out_free;
925 }
926 }
927 sem_lock_and_putref(sma);
928 if (sma->sem_perm.deleted) {
929 sem_unlock(sma);
930 err = -EIDRM;
931 goto out_free;
932 }
933
934 for (i = 0; i < nsems; i++)
935 sma->sem_base[i].semval = sem_io[i];
936
937 assert_spin_locked(&sma->sem_perm.lock);
938 list_for_each_entry(un, &sma->list_id, list_id) {
939 for (i = 0; i < nsems; i++)
940 un->semadj[i] = 0;
941 }
942 sma->sem_ctime = get_seconds();
943
944 do_smart_update(sma, NULL, 0, 0, &tasks);
945 err = 0;
946 goto out_unlock;
947 }
948
949 }
950 err = -EINVAL;
951 if(semnum < 0 || semnum >= nsems)
952 goto out_unlock;
953
954 curr = &sma->sem_base[semnum];
955
956 switch (cmd) {
957 case GETVAL:
958 err = curr->semval;
959 goto out_unlock;
960 case GETPID:
961 err = curr->sempid;
962 goto out_unlock;
963 case GETNCNT:
964 err = count_semncnt(sma,semnum);
965 goto out_unlock;
966 case GETZCNT:
967 err = count_semzcnt(sma,semnum);
968 goto out_unlock;
969 case SETVAL:
970 {
971 int val = arg.val;
972 struct sem_undo *un;
973
974 err = -ERANGE;
975 if (val > SEMVMX || val < 0)
976 goto out_unlock;
977
978 assert_spin_locked(&sma->sem_perm.lock);
979 list_for_each_entry(un, &sma->list_id, list_id)
980 un->semadj[semnum] = 0;
981
982 curr->semval = val;
983 curr->sempid = task_tgid_vnr(current);
984 sma->sem_ctime = get_seconds();
985
986 do_smart_update(sma, NULL, 0, 0, &tasks);
987 err = 0;
988 goto out_unlock;
989 }
990 }
991out_unlock:
992 sem_unlock(sma);
993 wake_up_sem_queue_do(&tasks);
994
995out_free:
996 if(sem_io != fast_sem_io)
997 ipc_free(sem_io, sizeof(ushort)*nsems);
998 return err;
999}
1000
1001static inline unsigned long
1002copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
1003{
1004 switch(version) {
1005 case IPC_64:
1006 if (copy_from_user(out, buf, sizeof(*out)))
1007 return -EFAULT;
1008 return 0;
1009 case IPC_OLD:
1010 {
1011 struct semid_ds tbuf_old;
1012
1013 if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
1014 return -EFAULT;
1015
1016 out->sem_perm.uid = tbuf_old.sem_perm.uid;
1017 out->sem_perm.gid = tbuf_old.sem_perm.gid;
1018 out->sem_perm.mode = tbuf_old.sem_perm.mode;
1019
1020 return 0;
1021 }
1022 default:
1023 return -EINVAL;
1024 }
1025}
1026
1027
1028
1029
1030
1031
1032static int semctl_down(struct ipc_namespace *ns, int semid,
1033 int cmd, int version, union semun arg)
1034{
1035 struct sem_array *sma;
1036 int err;
1037 struct semid64_ds semid64;
1038 struct kern_ipc_perm *ipcp;
1039
1040 if(cmd == IPC_SET) {
1041 if (copy_semid_from_user(&semid64, arg.buf, version))
1042 return -EFAULT;
1043 }
1044
1045 ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
1046 &semid64.sem_perm, 0);
1047 if (IS_ERR(ipcp))
1048 return PTR_ERR(ipcp);
1049
1050 sma = container_of(ipcp, struct sem_array, sem_perm);
1051
1052 err = security_sem_semctl(sma, cmd);
1053 if (err)
1054 goto out_unlock;
1055
1056 switch(cmd){
1057 case IPC_RMID:
1058 freeary(ns, ipcp);
1059 goto out_up;
1060 case IPC_SET:
1061 ipc_update_perm(&semid64.sem_perm, ipcp);
1062 sma->sem_ctime = get_seconds();
1063 break;
1064 default:
1065 err = -EINVAL;
1066 }
1067
1068out_unlock:
1069 sem_unlock(sma);
1070out_up:
1071 up_write(&sem_ids(ns).rw_mutex);
1072 return err;
1073}
1074
1075SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg)
1076{
1077 int err = -EINVAL;
1078 int version;
1079 struct ipc_namespace *ns;
1080
1081 if (semid < 0)
1082 return -EINVAL;
1083
1084 version = ipc_parse_version(&cmd);
1085 ns = current->nsproxy->ipc_ns;
1086
1087 switch(cmd) {
1088 case IPC_INFO:
1089 case SEM_INFO:
1090 case IPC_STAT:
1091 case SEM_STAT:
1092 err = semctl_nolock(ns, semid, cmd, version, arg);
1093 return err;
1094 case GETALL:
1095 case GETVAL:
1096 case GETPID:
1097 case GETNCNT:
1098 case GETZCNT:
1099 case SETVAL:
1100 case SETALL:
1101 err = semctl_main(ns,semid,semnum,cmd,version,arg);
1102 return err;
1103 case IPC_RMID:
1104 case IPC_SET:
1105 err = semctl_down(ns, semid, cmd, version, arg);
1106 return err;
1107 default:
1108 return -EINVAL;
1109 }
1110}
1111#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
1112asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg)
1113{
1114 return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg);
1115}
1116SYSCALL_ALIAS(sys_semctl, SyS_semctl);
1117#endif
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130static inline int get_undo_list(struct sem_undo_list **undo_listp)
1131{
1132 struct sem_undo_list *undo_list;
1133
1134 undo_list = current->sysvsem.undo_list;
1135 if (!undo_list) {
1136 undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL);
1137 if (undo_list == NULL)
1138 return -ENOMEM;
1139 spin_lock_init(&undo_list->lock);
1140 atomic_set(&undo_list->refcnt, 1);
1141 INIT_LIST_HEAD(&undo_list->list_proc);
1142
1143 current->sysvsem.undo_list = undo_list;
1144 }
1145 *undo_listp = undo_list;
1146 return 0;
1147}
1148
1149static struct sem_undo *__lookup_undo(struct sem_undo_list *ulp, int semid)
1150{
1151 struct sem_undo *un;
1152
1153 list_for_each_entry_rcu(un, &ulp->list_proc, list_proc) {
1154 if (un->semid == semid)
1155 return un;
1156 }
1157 return NULL;
1158}
1159
1160static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
1161{
1162 struct sem_undo *un;
1163
1164 assert_spin_locked(&ulp->lock);
1165
1166 un = __lookup_undo(ulp, semid);
1167 if (un) {
1168 list_del_rcu(&un->list_proc);
1169 list_add_rcu(&un->list_proc, &ulp->list_proc);
1170 }
1171 return un;
1172}
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
1186{
1187 struct sem_array *sma;
1188 struct sem_undo_list *ulp;
1189 struct sem_undo *un, *new;
1190 int nsems;
1191 int error;
1192
1193 error = get_undo_list(&ulp);
1194 if (error)
1195 return ERR_PTR(error);
1196
1197 rcu_read_lock();
1198 spin_lock(&ulp->lock);
1199 un = lookup_undo(ulp, semid);
1200 spin_unlock(&ulp->lock);
1201 if (likely(un!=NULL))
1202 goto out;
1203 rcu_read_unlock();
1204
1205
1206
1207 sma = sem_lock_check(ns, semid);
1208 if (IS_ERR(sma))
1209 return ERR_CAST(sma);
1210
1211 nsems = sma->sem_nsems;
1212 sem_getref_and_unlock(sma);
1213
1214
1215 new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
1216 if (!new) {
1217 sem_putref(sma);
1218 return ERR_PTR(-ENOMEM);
1219 }
1220
1221
1222 sem_lock_and_putref(sma);
1223 if (sma->sem_perm.deleted) {
1224 sem_unlock(sma);
1225 kfree(new);
1226 un = ERR_PTR(-EIDRM);
1227 goto out;
1228 }
1229 spin_lock(&ulp->lock);
1230
1231
1232
1233
1234 un = lookup_undo(ulp, semid);
1235 if (un) {
1236 kfree(new);
1237 goto success;
1238 }
1239
1240 new->semadj = (short *) &new[1];
1241 new->ulp = ulp;
1242 new->semid = semid;
1243 assert_spin_locked(&ulp->lock);
1244 list_add_rcu(&new->list_proc, &ulp->list_proc);
1245 assert_spin_locked(&sma->sem_perm.lock);
1246 list_add(&new->list_id, &sma->list_id);
1247 un = new;
1248
1249success:
1250 spin_unlock(&ulp->lock);
1251 rcu_read_lock();
1252 sem_unlock(sma);
1253out:
1254 return un;
1255}
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270static int get_queue_result(struct sem_queue *q)
1271{
1272 int error;
1273
1274 error = q->status;
1275 while (unlikely(error == IN_WAKEUP)) {
1276 cpu_relax();
1277 error = q->status;
1278 }
1279
1280 return error;
1281}
1282
1283
1284SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1285 unsigned, nsops, const struct timespec __user *, timeout)
1286{
1287 int error = -EINVAL;
1288 struct sem_array *sma;
1289 struct sembuf fast_sops[SEMOPM_FAST];
1290 struct sembuf* sops = fast_sops, *sop;
1291 struct sem_undo *un;
1292 int undos = 0, alter = 0, max;
1293 struct sem_queue queue;
1294 unsigned long jiffies_left = 0;
1295 struct ipc_namespace *ns;
1296 struct list_head tasks;
1297
1298 ns = current->nsproxy->ipc_ns;
1299
1300 if (nsops < 1 || semid < 0)
1301 return -EINVAL;
1302 if (nsops > ns->sc_semopm)
1303 return -E2BIG;
1304 if(nsops > SEMOPM_FAST) {
1305 sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
1306 if(sops==NULL)
1307 return -ENOMEM;
1308 }
1309 if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
1310 error=-EFAULT;
1311 goto out_free;
1312 }
1313 if (timeout) {
1314 struct timespec _timeout;
1315 if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) {
1316 error = -EFAULT;
1317 goto out_free;
1318 }
1319 if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 ||
1320 _timeout.tv_nsec >= 1000000000L) {
1321 error = -EINVAL;
1322 goto out_free;
1323 }
1324 jiffies_left = timespec_to_jiffies(&_timeout);
1325 }
1326 max = 0;
1327 for (sop = sops; sop < sops + nsops; sop++) {
1328 if (sop->sem_num >= max)
1329 max = sop->sem_num;
1330 if (sop->sem_flg & SEM_UNDO)
1331 undos = 1;
1332 if (sop->sem_op != 0)
1333 alter = 1;
1334 }
1335
1336 if (undos) {
1337 un = find_alloc_undo(ns, semid);
1338 if (IS_ERR(un)) {
1339 error = PTR_ERR(un);
1340 goto out_free;
1341 }
1342 } else
1343 un = NULL;
1344
1345 INIT_LIST_HEAD(&tasks);
1346
1347 sma = sem_lock_check(ns, semid);
1348 if (IS_ERR(sma)) {
1349 if (un)
1350 rcu_read_unlock();
1351 error = PTR_ERR(sma);
1352 goto out_free;
1353 }
1354
1355
1356
1357
1358
1359
1360
1361
1362 error = -EIDRM;
1363 if (un) {
1364 if (un->semid == -1) {
1365 rcu_read_unlock();
1366 goto out_unlock_free;
1367 } else {
1368
1369
1370
1371
1372
1373
1374
1375
1376 rcu_read_unlock();
1377 }
1378 }
1379
1380 error = -EFBIG;
1381 if (max >= sma->sem_nsems)
1382 goto out_unlock_free;
1383
1384 error = -EACCES;
1385 if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
1386 goto out_unlock_free;
1387
1388 error = security_sem_semop(sma, sops, nsops, alter);
1389 if (error)
1390 goto out_unlock_free;
1391
1392 error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
1393 if (error <= 0) {
1394 if (alter && error == 0)
1395 do_smart_update(sma, sops, nsops, 1, &tasks);
1396
1397 goto out_unlock_free;
1398 }
1399
1400
1401
1402
1403
1404 queue.sops = sops;
1405 queue.nsops = nsops;
1406 queue.undo = un;
1407 queue.pid = task_tgid_vnr(current);
1408 queue.alter = alter;
1409 if (alter)
1410 list_add_tail(&queue.list, &sma->sem_pending);
1411 else
1412 list_add(&queue.list, &sma->sem_pending);
1413
1414 if (nsops == 1) {
1415 struct sem *curr;
1416 curr = &sma->sem_base[sops->sem_num];
1417
1418 if (alter)
1419 list_add_tail(&queue.simple_list, &curr->sem_pending);
1420 else
1421 list_add(&queue.simple_list, &curr->sem_pending);
1422 } else {
1423 INIT_LIST_HEAD(&queue.simple_list);
1424 sma->complex_count++;
1425 }
1426
1427 queue.status = -EINTR;
1428 queue.sleeper = current;
1429 current->state = TASK_INTERRUPTIBLE;
1430 sem_unlock(sma);
1431
1432 if (timeout)
1433 jiffies_left = schedule_timeout(jiffies_left);
1434 else
1435 schedule();
1436
1437 error = get_queue_result(&queue);
1438
1439 if (error != -EINTR) {
1440
1441
1442
1443
1444
1445
1446
1447 smp_mb();
1448
1449 goto out_free;
1450 }
1451
1452 sma = sem_lock(ns, semid);
1453
1454
1455
1456
1457 error = get_queue_result(&queue);
1458
1459
1460
1461
1462 if (IS_ERR(sma)) {
1463 error = -EIDRM;
1464 goto out_free;
1465 }
1466
1467
1468
1469
1470
1471
1472
1473 if (error != -EINTR) {
1474 goto out_unlock_free;
1475 }
1476
1477
1478
1479
1480 if (timeout && jiffies_left == 0)
1481 error = -EAGAIN;
1482 unlink_queue(sma, &queue);
1483
1484out_unlock_free:
1485 sem_unlock(sma);
1486
1487 wake_up_sem_queue_do(&tasks);
1488out_free:
1489 if(sops != fast_sops)
1490 kfree(sops);
1491 return error;
1492}
1493
1494SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops,
1495 unsigned, nsops)
1496{
1497 return sys_semtimedop(semid, tsops, nsops, NULL);
1498}
1499
1500
1501
1502
1503
1504int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
1505{
1506 struct sem_undo_list *undo_list;
1507 int error;
1508
1509 if (clone_flags & CLONE_SYSVSEM) {
1510 error = get_undo_list(&undo_list);
1511 if (error)
1512 return error;
1513 atomic_inc(&undo_list->refcnt);
1514 tsk->sysvsem.undo_list = undo_list;
1515 } else
1516 tsk->sysvsem.undo_list = NULL;
1517
1518 return 0;
1519}
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533void exit_sem(struct task_struct *tsk)
1534{
1535 struct sem_undo_list *ulp;
1536
1537 ulp = tsk->sysvsem.undo_list;
1538 if (!ulp)
1539 return;
1540 tsk->sysvsem.undo_list = NULL;
1541
1542 if (!atomic_dec_and_test(&ulp->refcnt))
1543 return;
1544
1545 for (;;) {
1546 struct sem_array *sma;
1547 struct sem_undo *un;
1548 struct list_head tasks;
1549 int semid;
1550 int i;
1551
1552 rcu_read_lock();
1553 un = list_entry_rcu(ulp->list_proc.next,
1554 struct sem_undo, list_proc);
1555 if (&un->list_proc == &ulp->list_proc)
1556 semid = -1;
1557 else
1558 semid = un->semid;
1559 rcu_read_unlock();
1560
1561 if (semid == -1)
1562 break;
1563
1564 sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
1565
1566
1567 if (IS_ERR(sma))
1568 continue;
1569
1570 un = __lookup_undo(ulp, semid);
1571 if (un == NULL) {
1572
1573
1574
1575 sem_unlock(sma);
1576 continue;
1577 }
1578
1579
1580 assert_spin_locked(&sma->sem_perm.lock);
1581 list_del(&un->list_id);
1582
1583 spin_lock(&ulp->lock);
1584 list_del_rcu(&un->list_proc);
1585 spin_unlock(&ulp->lock);
1586
1587
1588 for (i = 0; i < sma->sem_nsems; i++) {
1589 struct sem * semaphore = &sma->sem_base[i];
1590 if (un->semadj[i]) {
1591 semaphore->semval += un->semadj[i];
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605 if (semaphore->semval < 0)
1606 semaphore->semval = 0;
1607 if (semaphore->semval > SEMVMX)
1608 semaphore->semval = SEMVMX;
1609 semaphore->sempid = task_tgid_vnr(current);
1610 }
1611 }
1612
1613 INIT_LIST_HEAD(&tasks);
1614 do_smart_update(sma, NULL, 0, 1, &tasks);
1615 sem_unlock(sma);
1616 wake_up_sem_queue_do(&tasks);
1617
1618 kfree_rcu(un, rcu);
1619 }
1620 kfree(ulp);
1621}
1622
1623#ifdef CONFIG_PROC_FS
1624static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
1625{
1626 struct sem_array *sma = it;
1627
1628 return seq_printf(s,
1629 "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n",
1630 sma->sem_perm.key,
1631 sma->sem_perm.id,
1632 sma->sem_perm.mode,
1633 sma->sem_nsems,
1634 sma->sem_perm.uid,
1635 sma->sem_perm.gid,
1636 sma->sem_perm.cuid,
1637 sma->sem_perm.cgid,
1638 sma->sem_otime,
1639 sma->sem_ctime);
1640}
1641#endif
1642