1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/mm.h>
21#include <linux/shm.h>
22#include <linux/init.h>
23#include <linux/msg.h>
24#include <linux/vmalloc.h>
25#include <linux/slab.h>
26#include <linux/capability.h>
27#include <linux/highuid.h>
28#include <linux/security.h>
29#include <linux/rcupdate.h>
30#include <linux/workqueue.h>
31#include <linux/seq_file.h>
32#include <linux/proc_fs.h>
33#include <linux/audit.h>
34#include <linux/nsproxy.h>
35#include <linux/rwsem.h>
36#include <linux/memory.h>
37#include <linux/ipc_namespace.h>
38
39#include <asm/unistd.h>
40
41#include "util.h"
42
43struct ipc_proc_iface {
44 const char *path;
45 const char *header;
46 int ids;
47 int (*show)(struct seq_file *, void *);
48};
49
50#ifdef CONFIG_MEMORY_HOTPLUG
51
52static void ipc_memory_notifier(struct work_struct *work)
53{
54 ipcns_notify(IPCNS_MEMCHANGED);
55}
56
57static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
58
59
60static int ipc_memory_callback(struct notifier_block *self,
61 unsigned long action, void *arg)
62{
63 switch (action) {
64 case MEM_ONLINE:
65 case MEM_OFFLINE:
66
67
68
69
70
71
72
73
74 if (!work_pending(&ipc_memory_wq))
75 schedule_work(&ipc_memory_wq);
76 break;
77 case MEM_GOING_ONLINE:
78 case MEM_GOING_OFFLINE:
79 case MEM_CANCEL_ONLINE:
80 case MEM_CANCEL_OFFLINE:
81 default:
82 break;
83 }
84
85 return NOTIFY_OK;
86}
87
88#endif
89
90
91
92
93
94
95
96
97
98
99
100static int __init ipc_init(void)
101{
102 sem_init();
103 msg_init();
104 shm_init();
105 hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
106 register_ipcns_notifier(&init_ipc_ns);
107 return 0;
108}
109__initcall(ipc_init);
110
111
112
113
114
115
116
117
118
119void ipc_init_ids(struct ipc_ids *ids)
120{
121 init_rwsem(&ids->rw_mutex);
122
123 ids->in_use = 0;
124 ids->seq = 0;
125 {
126 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
127 if (seq_limit > USHORT_MAX)
128 ids->seq_max = USHORT_MAX;
129 else
130 ids->seq_max = seq_limit;
131 }
132
133 idr_init(&ids->ipcs_idr);
134}
135
136#ifdef CONFIG_PROC_FS
137static const struct file_operations sysvipc_proc_fops;
138
139
140
141
142
143
144
145void __init ipc_init_proc_interface(const char *path, const char *header,
146 int ids, int (*show)(struct seq_file *, void *))
147{
148 struct proc_dir_entry *pde;
149 struct ipc_proc_iface *iface;
150
151 iface = kmalloc(sizeof(*iface), GFP_KERNEL);
152 if (!iface)
153 return;
154 iface->path = path;
155 iface->header = header;
156 iface->ids = ids;
157 iface->show = show;
158
159 pde = proc_create_data(path,
160 S_IRUGO,
161 NULL,
162 &sysvipc_proc_fops,
163 iface);
164 if (!pde) {
165 kfree(iface);
166 }
167}
168#endif
169
170
171
172
173
174
175
176
177
178
179
180
181static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
182{
183 struct kern_ipc_perm *ipc;
184 int next_id;
185 int total;
186
187 for (total = 0, next_id = 0; total < ids->in_use; next_id++) {
188 ipc = idr_find(&ids->ipcs_idr, next_id);
189
190 if (ipc == NULL)
191 continue;
192
193 if (ipc->key != key) {
194 total++;
195 continue;
196 }
197
198 ipc_lock_by_ptr(ipc);
199 return ipc;
200 }
201
202 return NULL;
203}
204
205
206
207
208
209
210
211
212int ipc_get_maxid(struct ipc_ids *ids)
213{
214 struct kern_ipc_perm *ipc;
215 int max_id = -1;
216 int total, id;
217
218 if (ids->in_use == 0)
219 return -1;
220
221 if (ids->in_use == IPCMNI)
222 return IPCMNI - 1;
223
224
225 total = 0;
226 for (id = 0; id < IPCMNI && total < ids->in_use; id++) {
227 ipc = idr_find(&ids->ipcs_idr, id);
228 if (ipc != NULL) {
229 max_id = id;
230 total++;
231 }
232 }
233 return max_id;
234}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
251{
252 uid_t euid;
253 gid_t egid;
254 int id, err;
255
256 if (size > IPCMNI)
257 size = IPCMNI;
258
259 if (ids->in_use >= size)
260 return -ENOSPC;
261
262 spin_lock_init(&new->lock);
263 new->deleted = 0;
264 rcu_read_lock();
265 spin_lock(&new->lock);
266
267 err = idr_get_new(&ids->ipcs_idr, new, &id);
268 if (err) {
269 spin_unlock(&new->lock);
270 rcu_read_unlock();
271 return err;
272 }
273
274 ids->in_use++;
275
276 current_euid_egid(&euid, &egid);
277 new->cuid = new->uid = euid;
278 new->gid = new->cgid = egid;
279
280 new->seq = ids->seq++;
281 if(ids->seq > ids->seq_max)
282 ids->seq = 0;
283
284 new->id = ipc_buildid(id, new->seq);
285 return id;
286}
287
288
289
290
291
292
293
294
295
296
297
298static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
299 struct ipc_ops *ops, struct ipc_params *params)
300{
301 int err;
302retry:
303 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
304
305 if (!err)
306 return -ENOMEM;
307
308 down_write(&ids->rw_mutex);
309 err = ops->getnew(ns, params);
310 up_write(&ids->rw_mutex);
311
312 if (err == -EAGAIN)
313 goto retry;
314
315 return err;
316}
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
333 struct ipc_params *params)
334{
335 int err;
336
337 if (ipcperms(ipcp, params->flg))
338 err = -EACCES;
339 else {
340 err = ops->associate(ipcp, params->flg);
341 if (!err)
342 err = ipcp->id;
343 }
344
345 return err;
346}
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
363 struct ipc_ops *ops, struct ipc_params *params)
364{
365 struct kern_ipc_perm *ipcp;
366 int flg = params->flg;
367 int err;
368retry:
369 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
370
371
372
373
374
375 down_write(&ids->rw_mutex);
376 ipcp = ipc_findkey(ids, params->key);
377 if (ipcp == NULL) {
378
379 if (!(flg & IPC_CREAT))
380 err = -ENOENT;
381 else if (!err)
382 err = -ENOMEM;
383 else
384 err = ops->getnew(ns, params);
385 } else {
386
387
388 if (flg & IPC_CREAT && flg & IPC_EXCL)
389 err = -EEXIST;
390 else {
391 err = 0;
392 if (ops->more_checks)
393 err = ops->more_checks(ipcp, params);
394 if (!err)
395
396
397
398
399 err = ipc_check_perms(ipcp, ops, params);
400 }
401 ipc_unlock(ipcp);
402 }
403 up_write(&ids->rw_mutex);
404
405 if (err == -EAGAIN)
406 goto retry;
407
408 return err;
409}
410
411
412
413
414
415
416
417
418
419
420
421void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
422{
423 int lid = ipcid_to_idx(ipcp->id);
424
425 idr_remove(&ids->ipcs_idr, lid);
426
427 ids->in_use--;
428
429 ipcp->deleted = 1;
430
431 return;
432}
433
434
435
436
437
438
439
440
441
442void* ipc_alloc(int size)
443{
444 void* out;
445 if(size > PAGE_SIZE)
446 out = vmalloc(size);
447 else
448 out = kmalloc(size, GFP_KERNEL);
449 return out;
450}
451
452
453
454
455
456
457
458
459
460
461void ipc_free(void* ptr, int size)
462{
463 if(size > PAGE_SIZE)
464 vfree(ptr);
465 else
466 kfree(ptr);
467}
468
469
470
471
472
473
474
475
476
477
478
479struct ipc_rcu_hdr
480{
481 int refcount;
482 int is_vmalloc;
483 void *data[0];
484};
485
486
487struct ipc_rcu_grace
488{
489 struct rcu_head rcu;
490
491 void *data[0];
492};
493
494struct ipc_rcu_sched
495{
496 struct work_struct work;
497
498 void *data[0];
499};
500
501#define HDRLEN_KMALLOC (sizeof(struct ipc_rcu_grace) > sizeof(struct ipc_rcu_hdr) ? \
502 sizeof(struct ipc_rcu_grace) : sizeof(struct ipc_rcu_hdr))
503#define HDRLEN_VMALLOC (sizeof(struct ipc_rcu_sched) > HDRLEN_KMALLOC ? \
504 sizeof(struct ipc_rcu_sched) : HDRLEN_KMALLOC)
505
506static inline int rcu_use_vmalloc(int size)
507{
508
509 if (HDRLEN_KMALLOC + size > PAGE_SIZE)
510 return 1;
511 return 0;
512}
513
514
515
516
517
518
519
520
521
522
523void* ipc_rcu_alloc(int size)
524{
525 void* out;
526
527
528
529
530 if (rcu_use_vmalloc(size)) {
531 out = vmalloc(HDRLEN_VMALLOC + size);
532 if (out) {
533 out += HDRLEN_VMALLOC;
534 container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
535 container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
536 }
537 } else {
538 out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL);
539 if (out) {
540 out += HDRLEN_KMALLOC;
541 container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
542 container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
543 }
544 }
545
546 return out;
547}
548
549void ipc_rcu_getref(void *ptr)
550{
551 container_of(ptr, struct ipc_rcu_hdr, data)->refcount++;
552}
553
554static void ipc_do_vfree(struct work_struct *work)
555{
556 vfree(container_of(work, struct ipc_rcu_sched, work));
557}
558
559
560
561
562
563
564
565
566static void ipc_schedule_free(struct rcu_head *head)
567{
568 struct ipc_rcu_grace *grace;
569 struct ipc_rcu_sched *sched;
570
571 grace = container_of(head, struct ipc_rcu_grace, rcu);
572 sched = container_of(&(grace->data[0]), struct ipc_rcu_sched,
573 data[0]);
574
575 INIT_WORK(&sched->work, ipc_do_vfree);
576 schedule_work(&sched->work);
577}
578
579
580
581
582
583
584
585static void ipc_immediate_free(struct rcu_head *head)
586{
587 struct ipc_rcu_grace *free =
588 container_of(head, struct ipc_rcu_grace, rcu);
589 kfree(free);
590}
591
592void ipc_rcu_putref(void *ptr)
593{
594 if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0)
595 return;
596
597 if (container_of(ptr, struct ipc_rcu_hdr, data)->is_vmalloc) {
598 call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
599 ipc_schedule_free);
600 } else {
601 call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
602 ipc_immediate_free);
603 }
604}
605
606
607
608
609
610
611
612
613
614
615int ipcperms (struct kern_ipc_perm *ipcp, short flag)
616{
617 uid_t euid = current_euid();
618 int requested_mode, granted_mode;
619
620 audit_ipc_obj(ipcp);
621 requested_mode = (flag >> 6) | (flag >> 3) | flag;
622 granted_mode = ipcp->mode;
623 if (euid == ipcp->cuid ||
624 euid == ipcp->uid)
625 granted_mode >>= 6;
626 else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
627 granted_mode >>= 3;
628
629 if ((requested_mode & ~granted_mode & 0007) &&
630 !capable(CAP_IPC_OWNER))
631 return -1;
632
633 return security_ipc_permission(ipcp, flag);
634}
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
652{
653 out->key = in->key;
654 out->uid = in->uid;
655 out->gid = in->gid;
656 out->cuid = in->cuid;
657 out->cgid = in->cgid;
658 out->mode = in->mode;
659 out->seq = in->seq;
660}
661
662
663
664
665
666
667
668
669
670
671void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
672{
673 out->key = in->key;
674 SET_UID(out->uid, in->uid);
675 SET_GID(out->gid, in->gid);
676 SET_UID(out->cuid, in->cuid);
677 SET_GID(out->cgid, in->cgid);
678 out->mode = in->mode;
679 out->seq = in->seq;
680}
681
682
683
684
685
686
687
688
689
690
691
692struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
693{
694 struct kern_ipc_perm *out;
695 int lid = ipcid_to_idx(id);
696
697 rcu_read_lock();
698 out = idr_find(&ids->ipcs_idr, lid);
699 if (out == NULL) {
700 rcu_read_unlock();
701 return ERR_PTR(-EINVAL);
702 }
703
704 spin_lock(&out->lock);
705
706
707
708
709 if (out->deleted) {
710 spin_unlock(&out->lock);
711 rcu_read_unlock();
712 return ERR_PTR(-EINVAL);
713 }
714
715 return out;
716}
717
718struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
719{
720 struct kern_ipc_perm *out;
721
722 out = ipc_lock(ids, id);
723 if (IS_ERR(out))
724 return out;
725
726 if (ipc_checkid(out, id)) {
727 ipc_unlock(out);
728 return ERR_PTR(-EIDRM);
729 }
730
731 return out;
732}
733
734
735
736
737
738
739
740
741
742
743
744int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
745 struct ipc_ops *ops, struct ipc_params *params)
746{
747 if (params->key == IPC_PRIVATE)
748 return ipcget_new(ns, ids, ops, params);
749 else
750 return ipcget_public(ns, ids, ops, params);
751}
752
753
754
755
756
757
758void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
759{
760 out->uid = in->uid;
761 out->gid = in->gid;
762 out->mode = (out->mode & ~S_IRWXUGO)
763 | (in->mode & S_IRWXUGO);
764}
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
783 struct ipc64_perm *perm, int extra_perm)
784{
785 struct kern_ipc_perm *ipcp;
786 uid_t euid;
787 int err;
788
789 down_write(&ids->rw_mutex);
790 ipcp = ipc_lock_check(ids, id);
791 if (IS_ERR(ipcp)) {
792 err = PTR_ERR(ipcp);
793 goto out_up;
794 }
795
796 audit_ipc_obj(ipcp);
797 if (cmd == IPC_SET)
798 audit_ipc_set_perm(extra_perm, perm->uid,
799 perm->gid, perm->mode);
800
801 euid = current_euid();
802 if (euid == ipcp->cuid ||
803 euid == ipcp->uid || capable(CAP_SYS_ADMIN))
804 return ipcp;
805
806 err = -EPERM;
807 ipc_unlock(ipcp);
808out_up:
809 up_write(&ids->rw_mutex);
810 return ERR_PTR(err);
811}
812
813#ifdef __ARCH_WANT_IPC_PARSE_VERSION
814
815
816
817
818
819
820
821
822
823
824
825int ipc_parse_version (int *cmd)
826{
827 if (*cmd & IPC_64) {
828 *cmd ^= IPC_64;
829 return IPC_64;
830 } else {
831 return IPC_OLD;
832 }
833}
834
835#endif
836
837#ifdef CONFIG_PROC_FS
838struct ipc_proc_iter {
839 struct ipc_namespace *ns;
840 struct ipc_proc_iface *iface;
841};
842
843
844
845
846static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
847 loff_t *new_pos)
848{
849 struct kern_ipc_perm *ipc;
850 int total, id;
851
852 total = 0;
853 for (id = 0; id < pos && total < ids->in_use; id++) {
854 ipc = idr_find(&ids->ipcs_idr, id);
855 if (ipc != NULL)
856 total++;
857 }
858
859 if (total >= ids->in_use)
860 return NULL;
861
862 for ( ; pos < IPCMNI; pos++) {
863 ipc = idr_find(&ids->ipcs_idr, pos);
864 if (ipc != NULL) {
865 *new_pos = pos + 1;
866 ipc_lock_by_ptr(ipc);
867 return ipc;
868 }
869 }
870
871
872 return NULL;
873}
874
875static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
876{
877 struct ipc_proc_iter *iter = s->private;
878 struct ipc_proc_iface *iface = iter->iface;
879 struct kern_ipc_perm *ipc = it;
880
881
882 if (ipc && ipc != SEQ_START_TOKEN)
883 ipc_unlock(ipc);
884
885 return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos);
886}
887
888
889
890
891
892static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
893{
894 struct ipc_proc_iter *iter = s->private;
895 struct ipc_proc_iface *iface = iter->iface;
896 struct ipc_ids *ids;
897
898 ids = &iter->ns->ids[iface->ids];
899
900
901
902
903
904 down_read(&ids->rw_mutex);
905
906
907 if (*pos < 0)
908 return NULL;
909
910
911 if (*pos == 0)
912 return SEQ_START_TOKEN;
913
914
915 return sysvipc_find_ipc(ids, *pos - 1, pos);
916}
917
918static void sysvipc_proc_stop(struct seq_file *s, void *it)
919{
920 struct kern_ipc_perm *ipc = it;
921 struct ipc_proc_iter *iter = s->private;
922 struct ipc_proc_iface *iface = iter->iface;
923 struct ipc_ids *ids;
924
925
926 if (ipc && ipc != SEQ_START_TOKEN)
927 ipc_unlock(ipc);
928
929 ids = &iter->ns->ids[iface->ids];
930
931 up_read(&ids->rw_mutex);
932}
933
934static int sysvipc_proc_show(struct seq_file *s, void *it)
935{
936 struct ipc_proc_iter *iter = s->private;
937 struct ipc_proc_iface *iface = iter->iface;
938
939 if (it == SEQ_START_TOKEN)
940 return seq_puts(s, iface->header);
941
942 return iface->show(s, it);
943}
944
945static struct seq_operations sysvipc_proc_seqops = {
946 .start = sysvipc_proc_start,
947 .stop = sysvipc_proc_stop,
948 .next = sysvipc_proc_next,
949 .show = sysvipc_proc_show,
950};
951
952static int sysvipc_proc_open(struct inode *inode, struct file *file)
953{
954 int ret;
955 struct seq_file *seq;
956 struct ipc_proc_iter *iter;
957
958 ret = -ENOMEM;
959 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
960 if (!iter)
961 goto out;
962
963 ret = seq_open(file, &sysvipc_proc_seqops);
964 if (ret)
965 goto out_kfree;
966
967 seq = file->private_data;
968 seq->private = iter;
969
970 iter->iface = PDE(inode)->data;
971 iter->ns = get_ipc_ns(current->nsproxy->ipc_ns);
972out:
973 return ret;
974out_kfree:
975 kfree(iter);
976 goto out;
977}
978
979static int sysvipc_proc_release(struct inode *inode, struct file *file)
980{
981 struct seq_file *seq = file->private_data;
982 struct ipc_proc_iter *iter = seq->private;
983 put_ipc_ns(iter->ns);
984 return seq_release_private(inode, file);
985}
986
987static const struct file_operations sysvipc_proc_fops = {
988 .open = sysvipc_proc_open,
989 .read = seq_read,
990 .llseek = seq_lseek,
991 .release = sysvipc_proc_release,
992};
993#endif
994