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 > USHRT_MAX)
128 ids->seq_max = USHRT_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
332
333static int ipc_check_perms(struct ipc_namespace *ns,
334 struct kern_ipc_perm *ipcp,
335 struct ipc_ops *ops,
336 struct ipc_params *params)
337{
338 int err;
339
340 if (ipcperms(ns, ipcp, params->flg))
341 err = -EACCES;
342 else {
343 err = ops->associate(ipcp, params->flg);
344 if (!err)
345 err = ipcp->id;
346 }
347
348 return err;
349}
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
366 struct ipc_ops *ops, struct ipc_params *params)
367{
368 struct kern_ipc_perm *ipcp;
369 int flg = params->flg;
370 int err;
371retry:
372 err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
373
374
375
376
377
378 down_write(&ids->rw_mutex);
379 ipcp = ipc_findkey(ids, params->key);
380 if (ipcp == NULL) {
381
382 if (!(flg & IPC_CREAT))
383 err = -ENOENT;
384 else if (!err)
385 err = -ENOMEM;
386 else
387 err = ops->getnew(ns, params);
388 } else {
389
390
391 if (flg & IPC_CREAT && flg & IPC_EXCL)
392 err = -EEXIST;
393 else {
394 err = 0;
395 if (ops->more_checks)
396 err = ops->more_checks(ipcp, params);
397 if (!err)
398
399
400
401
402 err = ipc_check_perms(ns, ipcp, ops, params);
403 }
404 ipc_unlock(ipcp);
405 }
406 up_write(&ids->rw_mutex);
407
408 if (err == -EAGAIN)
409 goto retry;
410
411 return err;
412}
413
414
415
416
417
418
419
420
421
422
423
424void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
425{
426 int lid = ipcid_to_idx(ipcp->id);
427
428 idr_remove(&ids->ipcs_idr, lid);
429
430 ids->in_use--;
431
432 ipcp->deleted = 1;
433
434 return;
435}
436
437
438
439
440
441
442
443
444
445void* ipc_alloc(int size)
446{
447 void* out;
448 if(size > PAGE_SIZE)
449 out = vmalloc(size);
450 else
451 out = kmalloc(size, GFP_KERNEL);
452 return out;
453}
454
455
456
457
458
459
460
461
462
463
464void ipc_free(void* ptr, int size)
465{
466 if(size > PAGE_SIZE)
467 vfree(ptr);
468 else
469 kfree(ptr);
470}
471
472
473
474
475
476
477
478
479
480
481
482struct ipc_rcu_hdr
483{
484 int refcount;
485 int is_vmalloc;
486 void *data[0];
487};
488
489
490struct ipc_rcu_grace
491{
492 struct rcu_head rcu;
493
494 void *data[0];
495};
496
497struct ipc_rcu_sched
498{
499 struct work_struct work;
500
501 void *data[0];
502};
503
504#define HDRLEN_KMALLOC (sizeof(struct ipc_rcu_grace) > sizeof(struct ipc_rcu_hdr) ? \
505 sizeof(struct ipc_rcu_grace) : sizeof(struct ipc_rcu_hdr))
506#define HDRLEN_VMALLOC (sizeof(struct ipc_rcu_sched) > HDRLEN_KMALLOC ? \
507 sizeof(struct ipc_rcu_sched) : HDRLEN_KMALLOC)
508
509static inline int rcu_use_vmalloc(int size)
510{
511
512 if (HDRLEN_KMALLOC + size > PAGE_SIZE)
513 return 1;
514 return 0;
515}
516
517
518
519
520
521
522
523
524
525
526void* ipc_rcu_alloc(int size)
527{
528 void* out;
529
530
531
532
533 if (rcu_use_vmalloc(size)) {
534 out = vmalloc(HDRLEN_VMALLOC + size);
535 if (out) {
536 out += HDRLEN_VMALLOC;
537 container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
538 container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
539 }
540 } else {
541 out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL);
542 if (out) {
543 out += HDRLEN_KMALLOC;
544 container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
545 container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
546 }
547 }
548
549 return out;
550}
551
552void ipc_rcu_getref(void *ptr)
553{
554 container_of(ptr, struct ipc_rcu_hdr, data)->refcount++;
555}
556
557static void ipc_do_vfree(struct work_struct *work)
558{
559 vfree(container_of(work, struct ipc_rcu_sched, work));
560}
561
562
563
564
565
566
567
568
569static void ipc_schedule_free(struct rcu_head *head)
570{
571 struct ipc_rcu_grace *grace;
572 struct ipc_rcu_sched *sched;
573
574 grace = container_of(head, struct ipc_rcu_grace, rcu);
575 sched = container_of(&(grace->data[0]), struct ipc_rcu_sched,
576 data[0]);
577
578 INIT_WORK(&sched->work, ipc_do_vfree);
579 schedule_work(&sched->work);
580}
581
582
583
584
585
586
587
588static void ipc_immediate_free(struct rcu_head *head)
589{
590 struct ipc_rcu_grace *free =
591 container_of(head, struct ipc_rcu_grace, rcu);
592 kfree(free);
593}
594
595void ipc_rcu_putref(void *ptr)
596{
597 if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0)
598 return;
599
600 if (container_of(ptr, struct ipc_rcu_hdr, data)->is_vmalloc) {
601 call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
602 ipc_schedule_free);
603 } else {
604 call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
605 ipc_immediate_free);
606 }
607}
608
609
610
611
612
613
614
615
616
617
618
619
620
621int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
622{
623 uid_t euid = current_euid();
624 int requested_mode, granted_mode;
625
626 audit_ipc_obj(ipcp);
627 requested_mode = (flag >> 6) | (flag >> 3) | flag;
628 granted_mode = ipcp->mode;
629 if (euid == ipcp->cuid ||
630 euid == ipcp->uid)
631 granted_mode >>= 6;
632 else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
633 granted_mode >>= 3;
634
635 if ((requested_mode & ~granted_mode & 0007) &&
636 !ns_capable(ns->user_ns, CAP_IPC_OWNER))
637 return -1;
638
639 return security_ipc_permission(ipcp, flag);
640}
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
658{
659 out->key = in->key;
660 out->uid = in->uid;
661 out->gid = in->gid;
662 out->cuid = in->cuid;
663 out->cgid = in->cgid;
664 out->mode = in->mode;
665 out->seq = in->seq;
666}
667
668
669
670
671
672
673
674
675
676
677void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
678{
679 out->key = in->key;
680 SET_UID(out->uid, in->uid);
681 SET_GID(out->gid, in->gid);
682 SET_UID(out->cuid, in->cuid);
683 SET_GID(out->cgid, in->cgid);
684 out->mode = in->mode;
685 out->seq = in->seq;
686}
687
688
689
690
691
692
693
694
695
696
697
698struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
699{
700 struct kern_ipc_perm *out;
701 int lid = ipcid_to_idx(id);
702
703 rcu_read_lock();
704 out = idr_find(&ids->ipcs_idr, lid);
705 if (out == NULL) {
706 rcu_read_unlock();
707 return ERR_PTR(-EINVAL);
708 }
709
710 spin_lock(&out->lock);
711
712
713
714
715 if (out->deleted) {
716 spin_unlock(&out->lock);
717 rcu_read_unlock();
718 return ERR_PTR(-EINVAL);
719 }
720
721 return out;
722}
723
724struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
725{
726 struct kern_ipc_perm *out;
727
728 out = ipc_lock(ids, id);
729 if (IS_ERR(out))
730 return out;
731
732 if (ipc_checkid(out, id)) {
733 ipc_unlock(out);
734 return ERR_PTR(-EIDRM);
735 }
736
737 return out;
738}
739
740
741
742
743
744
745
746
747
748
749
750int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
751 struct ipc_ops *ops, struct ipc_params *params)
752{
753 if (params->key == IPC_PRIVATE)
754 return ipcget_new(ns, ids, ops, params);
755 else
756 return ipcget_public(ns, ids, ops, params);
757}
758
759
760
761
762
763
764void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
765{
766 out->uid = in->uid;
767 out->gid = in->gid;
768 out->mode = (out->mode & ~S_IRWXUGO)
769 | (in->mode & S_IRWXUGO);
770}
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
790 struct ipc_ids *ids, int id, int cmd,
791 struct ipc64_perm *perm, int extra_perm)
792{
793 struct kern_ipc_perm *ipcp;
794 uid_t euid;
795 int err;
796
797 down_write(&ids->rw_mutex);
798 ipcp = ipc_lock_check(ids, id);
799 if (IS_ERR(ipcp)) {
800 err = PTR_ERR(ipcp);
801 goto out_up;
802 }
803
804 audit_ipc_obj(ipcp);
805 if (cmd == IPC_SET)
806 audit_ipc_set_perm(extra_perm, perm->uid,
807 perm->gid, perm->mode);
808
809 euid = current_euid();
810 if (euid == ipcp->cuid || euid == ipcp->uid ||
811 ns_capable(ns->user_ns, CAP_SYS_ADMIN))
812 return ipcp;
813
814 err = -EPERM;
815 ipc_unlock(ipcp);
816out_up:
817 up_write(&ids->rw_mutex);
818 return ERR_PTR(err);
819}
820
821#ifdef __ARCH_WANT_IPC_PARSE_VERSION
822
823
824
825
826
827
828
829
830
831
832
833int ipc_parse_version (int *cmd)
834{
835 if (*cmd & IPC_64) {
836 *cmd ^= IPC_64;
837 return IPC_64;
838 } else {
839 return IPC_OLD;
840 }
841}
842
843#endif
844
845#ifdef CONFIG_PROC_FS
846struct ipc_proc_iter {
847 struct ipc_namespace *ns;
848 struct ipc_proc_iface *iface;
849};
850
851
852
853
854static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
855 loff_t *new_pos)
856{
857 struct kern_ipc_perm *ipc;
858 int total, id;
859
860 total = 0;
861 for (id = 0; id < pos && total < ids->in_use; id++) {
862 ipc = idr_find(&ids->ipcs_idr, id);
863 if (ipc != NULL)
864 total++;
865 }
866
867 if (total >= ids->in_use)
868 return NULL;
869
870 for ( ; pos < IPCMNI; pos++) {
871 ipc = idr_find(&ids->ipcs_idr, pos);
872 if (ipc != NULL) {
873 *new_pos = pos + 1;
874 ipc_lock_by_ptr(ipc);
875 return ipc;
876 }
877 }
878
879
880 return NULL;
881}
882
883static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
884{
885 struct ipc_proc_iter *iter = s->private;
886 struct ipc_proc_iface *iface = iter->iface;
887 struct kern_ipc_perm *ipc = it;
888
889
890 if (ipc && ipc != SEQ_START_TOKEN)
891 ipc_unlock(ipc);
892
893 return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos);
894}
895
896
897
898
899
900static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
901{
902 struct ipc_proc_iter *iter = s->private;
903 struct ipc_proc_iface *iface = iter->iface;
904 struct ipc_ids *ids;
905
906 ids = &iter->ns->ids[iface->ids];
907
908
909
910
911
912 down_read(&ids->rw_mutex);
913
914
915 if (*pos < 0)
916 return NULL;
917
918
919 if (*pos == 0)
920 return SEQ_START_TOKEN;
921
922
923 return sysvipc_find_ipc(ids, *pos - 1, pos);
924}
925
926static void sysvipc_proc_stop(struct seq_file *s, void *it)
927{
928 struct kern_ipc_perm *ipc = it;
929 struct ipc_proc_iter *iter = s->private;
930 struct ipc_proc_iface *iface = iter->iface;
931 struct ipc_ids *ids;
932
933
934 if (ipc && ipc != SEQ_START_TOKEN)
935 ipc_unlock(ipc);
936
937 ids = &iter->ns->ids[iface->ids];
938
939 up_read(&ids->rw_mutex);
940}
941
942static int sysvipc_proc_show(struct seq_file *s, void *it)
943{
944 struct ipc_proc_iter *iter = s->private;
945 struct ipc_proc_iface *iface = iter->iface;
946
947 if (it == SEQ_START_TOKEN)
948 return seq_puts(s, iface->header);
949
950 return iface->show(s, it);
951}
952
953static const struct seq_operations sysvipc_proc_seqops = {
954 .start = sysvipc_proc_start,
955 .stop = sysvipc_proc_stop,
956 .next = sysvipc_proc_next,
957 .show = sysvipc_proc_show,
958};
959
960static int sysvipc_proc_open(struct inode *inode, struct file *file)
961{
962 int ret;
963 struct seq_file *seq;
964 struct ipc_proc_iter *iter;
965
966 ret = -ENOMEM;
967 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
968 if (!iter)
969 goto out;
970
971 ret = seq_open(file, &sysvipc_proc_seqops);
972 if (ret)
973 goto out_kfree;
974
975 seq = file->private_data;
976 seq->private = iter;
977
978 iter->iface = PDE(inode)->data;
979 iter->ns = get_ipc_ns(current->nsproxy->ipc_ns);
980out:
981 return ret;
982out_kfree:
983 kfree(iter);
984 goto out;
985}
986
987static int sysvipc_proc_release(struct inode *inode, struct file *file)
988{
989 struct seq_file *seq = file->private_data;
990 struct ipc_proc_iter *iter = seq->private;
991 put_ipc_ns(iter->ns);
992 return seq_release_private(inode, file);
993}
994
995static const struct file_operations sysvipc_proc_fops = {
996 .open = sysvipc_proc_open,
997 .read = seq_read,
998 .llseek = seq_lseek,
999 .release = sysvipc_proc_release,
1000};
1001#endif
1002