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