• R/O
  • SSH
  • HTTPS

caitsith: コミット


コミットメタ情報

リビジョン2 (tree)
日時2012-04-01 15:31:21
作者kumaneko

ログメッセージ

(メッセージはありません)

変更サマリ

差分

--- trunk/caitsith-patch/include/linux/ccsecurity.h (nonexistent)
+++ trunk/caitsith-patch/include/linux/ccsecurity.h (revision 2)
@@ -0,0 +1,782 @@
1+/*
2+ * include/linux/ccsecurity.h
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#ifndef _LINUX_CCSECURITY_H
10+#define _LINUX_CCSECURITY_H
11+
12+#include <linux/version.h>
13+
14+#ifndef __user
15+#define __user
16+#endif
17+
18+struct nameidata;
19+struct path;
20+struct dentry;
21+struct vfsmount;
22+struct linux_binprm;
23+struct pt_regs;
24+struct file;
25+struct ctl_table;
26+struct socket;
27+struct sockaddr;
28+struct sock;
29+struct sk_buff;
30+struct msghdr;
31+struct pid_namespace;
32+int search_binary_handler(struct linux_binprm *bprm, struct pt_regs *regs);
33+
34+#ifdef CONFIG_CCSECURITY
35+
36+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
37+/* Obtain prototype of __d_path() or d_absolute_path(). */
38+#include <linux/dcache.h>
39+#endif
40+/* Obtain prototype of find_task_by_vpid() and find_task_by_pid_ns(). */
41+#include <linux/sched.h>
42+
43+/* For exporting variables and functions. */
44+struct ccsecurity_exports {
45+ void (*load_policy) (const char *filename);
46+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
47+ typeof(d_absolute_path) (*d_absolute_path);
48+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
49+ typeof(__d_path) (*__d_path);
50+#else
51+ spinlock_t *vfsmount_lock;
52+#endif
53+ typeof(find_task_by_vpid) (*find_task_by_vpid);
54+ typeof(find_task_by_pid_ns) (*find_task_by_pid_ns);
55+};
56+
57+/* For doing access control. */
58+struct ccsecurity_operations {
59+ void (*check_profile) (void);
60+ int (*chroot_permission) (struct path *path);
61+ int (*pivot_root_permission) (struct path *old_path,
62+ struct path *new_path);
63+ int (*mount_permission) (char *dev_name, struct path *path,
64+ const char *type, unsigned long flags,
65+ void *data_page);
66+ int (*umount_permission) (struct vfsmount *mnt, int flags);
67+ _Bool (*lport_reserved) (const u16 port); /* Not implemented. */
68+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
69+ void (*save_open_mode) (int mode);
70+ void (*clear_open_mode) (void);
71+ int (*open_permission) (struct dentry *dentry, struct vfsmount *mnt,
72+ const int flag);
73+#else
74+ int (*open_permission) (struct file *file);
75+#endif
76+ int (*ptrace_permission) (long request, long pid);
77+ int (*ioctl_permission) (struct file *filp, unsigned int cmd,
78+ unsigned long arg);
79+ int (*parse_table) (int __user *name, int nlen, void __user *oldval,
80+ void __user *newval, struct ctl_table *table);
81+ _Bool (*capable) (const u8 operation);
82+ int (*mknod_permission) (struct dentry *dentry, struct vfsmount *mnt,
83+ unsigned int mode, unsigned int dev);
84+ int (*mkdir_permission) (struct dentry *dentry, struct vfsmount *mnt,
85+ unsigned int mode);
86+ int (*rmdir_permission) (struct dentry *dentry, struct vfsmount *mnt);
87+ int (*unlink_permission) (struct dentry *dentry, struct vfsmount *mnt);
88+ int (*symlink_permission) (struct dentry *dentry, struct vfsmount *mnt,
89+ const char *from);
90+ int (*truncate_permission) (struct dentry *dentry,
91+ struct vfsmount *mnt);
92+ int (*rename_permission) (struct dentry *old_dentry,
93+ struct dentry *new_dentry,
94+ struct vfsmount *mnt);
95+ int (*link_permission) (struct dentry *old_dentry,
96+ struct dentry *new_dentry,
97+ struct vfsmount *mnt);
98+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
99+ int (*open_exec_permission) (struct dentry *dentry,
100+ struct vfsmount *mnt);
101+ int (*uselib_permission) (struct dentry *dentry, struct vfsmount *mnt);
102+#endif
103+ int (*fcntl_permission) (struct file *file, unsigned int cmd,
104+ unsigned long arg);
105+ int (*kill_permission) (pid_t pid, int sig);
106+ int (*tgkill_permission) (pid_t tgid, pid_t pid, int sig);
107+ int (*tkill_permission) (pid_t pid, int sig);
108+ int (*socket_create_permission) (int family, int type, int protocol);
109+ int (*socket_listen_permission) (struct socket *sock);
110+ int (*socket_connect_permission) (struct socket *sock,
111+ struct sockaddr *addr, int addr_len);
112+ int (*socket_bind_permission) (struct socket *sock,
113+ struct sockaddr *addr, int addr_len);
114+ int (*socket_post_accept_permission) (struct socket *sock,
115+ struct socket *newsock);
116+ int (*socket_sendmsg_permission) (struct socket *sock,
117+ struct msghdr *msg, int size);
118+ int (*socket_post_recvmsg_permission) (struct sock *sk,
119+ struct sk_buff *skb, int flags);
120+ int (*chown_permission) (struct dentry *dentry, struct vfsmount *mnt,
121+ uid_t user, gid_t group);
122+ int (*chmod_permission) (struct dentry *dentry, struct vfsmount *mnt,
123+ mode_t mode);
124+ int (*getattr_permission) (struct vfsmount *mnt,
125+ struct dentry *dentry);
126+ int (*sigqueue_permission) (pid_t pid, int sig);
127+ int (*tgsigqueue_permission) (pid_t tgid, pid_t pid, int sig);
128+ int (*search_binary_handler) (struct linux_binprm *bprm,
129+ struct pt_regs *regs);
130+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
131+ int (*alloc_task_security) (const struct task_struct *task);
132+ void (*free_task_security) (const struct task_struct *task);
133+#endif
134+ _Bool disabled;
135+};
136+
137+extern struct ccsecurity_operations ccsecurity_ops;
138+
139+static inline int ccs_chroot_permission(struct path *path)
140+{
141+ int (*func) (struct path *) = ccsecurity_ops.chroot_permission;
142+ return func ? func(path) : 0;
143+}
144+
145+static inline int ccs_pivot_root_permission(struct path *old_path,
146+ struct path *new_path)
147+{
148+ int (*func) (struct path *, struct path *)
149+ = ccsecurity_ops.pivot_root_permission;
150+ return func ? func(old_path, new_path) : 0;
151+}
152+
153+static inline int ccs_mount_permission(char *dev_name, struct path *path,
154+ char *type, unsigned long flags,
155+ void *data_page)
156+{
157+ int (*func) (char *, struct path *, const char *, unsigned long,
158+ void *) = ccsecurity_ops.mount_permission;
159+ return func ? func(dev_name, path, (const char *) type, flags,
160+ data_page) : 0;
161+}
162+
163+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
164+{
165+ int (*func) (struct vfsmount *, int)
166+ = ccsecurity_ops.umount_permission;
167+ return func ? func(mnt, flags) : 0;
168+}
169+
170+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
171+
172+static inline void ccs_save_open_mode(int mode)
173+{
174+ void (*func) (int) = ccsecurity_ops.save_open_mode;
175+ if (func)
176+ func(mode);
177+}
178+
179+static inline void ccs_clear_open_mode(void)
180+{
181+ void (*func) (void) = ccsecurity_ops.clear_open_mode;
182+ if (func)
183+ func();
184+}
185+
186+static inline int ccs_open_permission(struct dentry *dentry,
187+ struct vfsmount *mnt, const int flag)
188+{
189+ int (*func) (struct dentry *, struct vfsmount *, const int)
190+ = ccsecurity_ops.open_permission;
191+ return func ? func(dentry, mnt, flag) : 0;
192+}
193+
194+#else
195+
196+static inline int ccs_open_permission(struct file *filp)
197+{
198+ int (*func) (struct file *) = ccsecurity_ops.open_permission;
199+ return func ? func(filp) : 0;
200+}
201+
202+#endif
203+
204+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
205+ unsigned long arg)
206+{
207+ int (*func) (struct file *, unsigned int, unsigned long)
208+ = ccsecurity_ops.fcntl_permission;
209+ return func ? func(file, cmd, arg) : 0;
210+}
211+
212+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
213+ unsigned long arg)
214+{
215+ int (*func) (struct file *, unsigned int, unsigned long)
216+ = ccsecurity_ops.ioctl_permission;
217+ return func ? func(filp, cmd, arg) : 0;
218+}
219+
220+static inline int ccs_parse_table(int __user *name, int nlen,
221+ void __user *oldval, void __user *newval,
222+ struct ctl_table *table)
223+{
224+ int (*func) (int __user *, int, void __user *, void __user *,
225+ struct ctl_table *) = ccsecurity_ops.parse_table;
226+ return func ? func(name, nlen, oldval, newval, table) : 0;
227+}
228+
229+static inline int ccs_mknod_permission(struct dentry *dentry,
230+ struct vfsmount *mnt, unsigned int mode,
231+ unsigned int dev)
232+{
233+ int (*func) (struct dentry *, struct vfsmount *, unsigned int,
234+ unsigned int) = ccsecurity_ops.mknod_permission;
235+ return func ? func(dentry, mnt, mode, dev) : 0;
236+}
237+
238+static inline int ccs_mkdir_permission(struct dentry *dentry,
239+ struct vfsmount *mnt, unsigned int mode)
240+{
241+ int (*func) (struct dentry *, struct vfsmount *, unsigned int)
242+ = ccsecurity_ops.mkdir_permission;
243+ return func ? func(dentry, mnt, mode) : 0;
244+}
245+
246+static inline int ccs_rmdir_permission(struct dentry *dentry,
247+ struct vfsmount *mnt)
248+{
249+ int (*func) (struct dentry *, struct vfsmount *)
250+ = ccsecurity_ops.rmdir_permission;
251+ return func ? func(dentry, mnt) : 0;
252+}
253+
254+static inline int ccs_unlink_permission(struct dentry *dentry,
255+ struct vfsmount *mnt)
256+{
257+ int (*func) (struct dentry *, struct vfsmount *)
258+ = ccsecurity_ops.unlink_permission;
259+ return func ? func(dentry, mnt) : 0;
260+}
261+
262+static inline int ccs_symlink_permission(struct dentry *dentry,
263+ struct vfsmount *mnt,
264+ const char *from)
265+{
266+ int (*func) (struct dentry *, struct vfsmount *, const char *)
267+ = ccsecurity_ops.symlink_permission;
268+ return func ? func(dentry, mnt, from) : 0;
269+}
270+
271+static inline int ccs_truncate_permission(struct dentry *dentry,
272+ struct vfsmount *mnt)
273+{
274+ int (*func) (struct dentry *, struct vfsmount *)
275+ = ccsecurity_ops.truncate_permission;
276+ return func ? func(dentry, mnt) : 0;
277+}
278+
279+static inline int ccs_rename_permission(struct dentry *old_dentry,
280+ struct dentry *new_dentry,
281+ struct vfsmount *mnt)
282+{
283+ int (*func) (struct dentry *, struct dentry *, struct vfsmount *)
284+ = ccsecurity_ops.rename_permission;
285+ return func ? func(old_dentry, new_dentry, mnt) : 0;
286+}
287+
288+static inline int ccs_link_permission(struct dentry *old_dentry,
289+ struct dentry *new_dentry,
290+ struct vfsmount *mnt)
291+{
292+ int (*func) (struct dentry *, struct dentry *, struct vfsmount *)
293+ = ccsecurity_ops.link_permission;
294+ return func ? func(old_dentry, new_dentry, mnt) : 0;
295+}
296+
297+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
298+
299+static inline int ccs_open_exec_permission(struct dentry *dentry,
300+ struct vfsmount *mnt)
301+{
302+ int (*func) (struct dentry *, struct vfsmount *)
303+ = ccsecurity_ops.open_exec_permission;
304+ return func ? func(dentry, mnt) : 0;
305+}
306+
307+static inline int ccs_uselib_permission(struct dentry *dentry,
308+ struct vfsmount *mnt)
309+{
310+ int (*func) (struct dentry *, struct vfsmount *)
311+ = ccsecurity_ops.uselib_permission;
312+ return func ? func(dentry, mnt) : 0;
313+}
314+
315+#endif
316+
317+static inline int ccs_chown_permission(struct dentry *dentry,
318+ struct vfsmount *mnt, uid_t user,
319+ gid_t group)
320+{
321+ int (*func) (struct dentry *, struct vfsmount *, uid_t, gid_t)
322+ = ccsecurity_ops.chown_permission;
323+ return func ? func(dentry, mnt, user, group) : 0;
324+}
325+
326+static inline int ccs_chmod_permission(struct dentry *dentry,
327+ struct vfsmount *mnt, mode_t mode)
328+{
329+ int (*func) (struct dentry *, struct vfsmount *, mode_t)
330+ = ccsecurity_ops.chmod_permission;
331+ return func ? func(dentry, mnt, mode) : 0;
332+}
333+
334+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
335+ struct pt_regs *regs)
336+{
337+ return ccsecurity_ops.search_binary_handler(bprm, regs);
338+}
339+
340+#else
341+
342+static inline int ccs_chroot_permission(struct path *path)
343+{
344+ return 0;
345+}
346+
347+static inline int ccs_pivot_root_permission(struct path *old_path,
348+ struct path *new_path)
349+{
350+ return 0;
351+}
352+
353+static inline int ccs_mount_permission(char *dev_name, struct path *path,
354+ char *type, unsigned long flags,
355+ void *data_page)
356+{
357+ return 0;
358+}
359+
360+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
361+{
362+ return 0;
363+}
364+
365+static inline void ccs_save_open_mode(int mode)
366+{
367+}
368+
369+static inline void ccs_clear_open_mode(void)
370+{
371+}
372+
373+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
374+
375+static inline int ccs_open_permission(struct dentry *dentry,
376+ struct vfsmount *mnt, const int flag)
377+{
378+ return 0;
379+}
380+
381+#else
382+
383+static inline int ccs_open_permission(struct file *filp)
384+{
385+ return 0;
386+}
387+
388+#endif
389+
390+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
391+ unsigned long arg)
392+{
393+ return 0;
394+}
395+
396+static inline int ccs_parse_table(int __user *name, int nlen,
397+ void __user *oldval, void __user *newval,
398+ struct ctl_table *table)
399+{
400+ return 0;
401+}
402+
403+static inline int ccs_mknod_permission(struct dentry *dentry,
404+ struct vfsmount *mnt, unsigned int mode,
405+ unsigned int dev)
406+{
407+ return 0;
408+}
409+
410+static inline int ccs_mkdir_permission(struct dentry *dentry,
411+ struct vfsmount *mnt, unsigned int mode)
412+{
413+ return 0;
414+}
415+
416+static inline int ccs_rmdir_permission(struct dentry *dentry,
417+ struct vfsmount *mnt)
418+{
419+ return 0;
420+}
421+
422+static inline int ccs_unlink_permission(struct dentry *dentry,
423+ struct vfsmount *mnt)
424+{
425+ return 0;
426+}
427+
428+static inline int ccs_symlink_permission(struct dentry *dentry,
429+ struct vfsmount *mnt,
430+ const char *from)
431+{
432+ return 0;
433+}
434+
435+static inline int ccs_truncate_permission(struct dentry *dentry,
436+ struct vfsmount *mnt)
437+{
438+ return 0;
439+}
440+
441+static inline int ccs_rename_permission(struct dentry *old_dentry,
442+ struct dentry *new_dentry,
443+ struct vfsmount *mnt)
444+{
445+ return 0;
446+}
447+
448+static inline int ccs_link_permission(struct dentry *old_dentry,
449+ struct dentry *new_dentry,
450+ struct vfsmount *mnt)
451+{
452+ return 0;
453+}
454+
455+static inline int ccs_open_exec_permission(struct dentry *dentry,
456+ struct vfsmount *mnt)
457+{
458+ return 0;
459+}
460+
461+static inline int ccs_uselib_permission(struct dentry *dentry,
462+ struct vfsmount *mnt)
463+{
464+ return 0;
465+}
466+
467+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
468+ unsigned long arg)
469+{
470+ return 0;
471+}
472+
473+static inline int ccs_chown_permission(struct dentry *dentry,
474+ struct vfsmount *mnt, uid_t user,
475+ gid_t group)
476+{
477+ return 0;
478+}
479+
480+static inline int ccs_chmod_permission(struct dentry *dentry,
481+ struct vfsmount *mnt, mode_t mode)
482+{
483+ return 0;
484+}
485+
486+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
487+ struct pt_regs *regs)
488+{
489+ return search_binary_handler(bprm, regs);
490+}
491+
492+#endif
493+
494+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
495+
496+static inline int ccs_alloc_task_security(const struct task_struct *task)
497+{
498+ int (*func) (const struct task_struct *)
499+ = ccsecurity_ops.alloc_task_security;
500+ return func ? func(task) : 0;
501+}
502+
503+static inline void ccs_free_task_security(const struct task_struct *task)
504+{
505+ void (*func) (const struct task_struct *)
506+ = ccsecurity_ops.free_task_security;
507+ if (func)
508+ func(task);
509+}
510+
511+#else
512+
513+static inline int ccs_alloc_task_security(const struct task_struct *task)
514+{
515+ return 0;
516+}
517+
518+static inline void ccs_free_task_security(const struct task_struct *task)
519+{
520+}
521+
522+#endif
523+
524+#ifdef CONFIG_CCSECURITY_GETATTR
525+
526+static inline int ccs_getattr_permission(struct vfsmount *mnt,
527+ struct dentry *dentry)
528+{
529+ int (*func) (struct vfsmount *, struct dentry *)
530+ = ccsecurity_ops.getattr_permission;
531+ return func ? func(mnt, dentry) : 0;
532+}
533+
534+#else
535+
536+static inline int ccs_getattr_permission(struct vfsmount *mnt,
537+ struct dentry *dentry)
538+{
539+ return 0;
540+}
541+
542+#endif
543+
544+#ifdef CONFIG_CCSECURITY_NETWORK
545+
546+static inline int ccs_socket_listen_permission(struct socket *sock)
547+{
548+ int (*func) (struct socket *)
549+ = ccsecurity_ops.socket_listen_permission;
550+ return func ? func(sock) : 0;
551+}
552+
553+static inline int ccs_socket_connect_permission(struct socket *sock,
554+ struct sockaddr *addr,
555+ int addr_len)
556+{
557+ int (*func) (struct socket *, struct sockaddr *, int)
558+ = ccsecurity_ops.socket_connect_permission;
559+ return func ? func(sock, addr, addr_len) : 0;
560+}
561+
562+static inline int ccs_socket_bind_permission(struct socket *sock,
563+ struct sockaddr *addr,
564+ int addr_len)
565+{
566+ int (*func) (struct socket *, struct sockaddr *, int)
567+ = ccsecurity_ops.socket_bind_permission;
568+ return func ? func(sock, addr, addr_len) : 0;
569+}
570+
571+static inline int ccs_socket_post_accept_permission(struct socket *sock,
572+ struct socket *newsock)
573+{
574+ int (*func) (struct socket *, struct socket *)
575+ = ccsecurity_ops.socket_post_accept_permission;
576+ return func ? func(sock, newsock) : 0;
577+}
578+
579+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
580+ struct msghdr *msg,
581+ int size)
582+{
583+ int (*func) (struct socket *, struct msghdr *, int)
584+ = ccsecurity_ops.socket_sendmsg_permission;
585+ return func ? func(sock, msg, size) : 0;
586+}
587+
588+#else
589+
590+static inline int ccs_socket_listen_permission(struct socket *sock)
591+{
592+ return 0;
593+}
594+
595+static inline int ccs_socket_connect_permission(struct socket *sock,
596+ struct sockaddr *addr,
597+ int addr_len)
598+{
599+ return 0;
600+}
601+
602+static inline int ccs_socket_bind_permission(struct socket *sock,
603+ struct sockaddr *addr,
604+ int addr_len)
605+{
606+ return 0;
607+}
608+
609+static inline int ccs_socket_post_accept_permission(struct socket *sock,
610+ struct socket *newsock)
611+{
612+ return 0;
613+}
614+
615+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
616+ struct msghdr *msg,
617+ int size)
618+{
619+ return 0;
620+}
621+
622+#endif
623+
624+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
625+
626+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
627+ struct sk_buff *skb,
628+ int flags)
629+{
630+ int (*func) (struct sock *, struct sk_buff *, int)
631+ = ccsecurity_ops.socket_post_recvmsg_permission;
632+ return func ? func(sk, skb, flags) : 0;
633+}
634+
635+#else
636+
637+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
638+ struct sk_buff *skb,
639+ int flags)
640+{
641+ return 0;
642+}
643+
644+#endif
645+
646+static inline _Bool ccs_lport_reserved(const u16 port)
647+{
648+ return 0;
649+}
650+
651+#ifdef CONFIG_CCSECURITY_CAPABILITY
652+
653+static inline _Bool ccs_capable(const u8 operation)
654+{
655+ _Bool (*func) (const u8) = ccsecurity_ops.capable;
656+ return func ? func(operation) : 1;
657+}
658+
659+static inline int ccs_socket_create_permission(int family, int type,
660+ int protocol)
661+{
662+ int (*func) (int, int, int) = ccsecurity_ops.socket_create_permission;
663+ return func ? func(family, type, protocol) : 0;
664+}
665+
666+#else
667+
668+static inline _Bool ccs_capable(const u8 operation)
669+{
670+ return 1;
671+}
672+
673+static inline int ccs_socket_create_permission(int family, int type,
674+ int protocol)
675+{
676+ return 0;
677+}
678+
679+#endif
680+
681+#ifdef CONFIG_CCSECURITY_PTRACE
682+
683+static inline int ccs_ptrace_permission(long request, long pid)
684+{
685+ int (*func) (long, long) = ccsecurity_ops.ptrace_permission;
686+ return func ? func(request, pid) : 0;
687+}
688+
689+#else
690+
691+static inline int ccs_ptrace_permission(long request, long pid)
692+{
693+ return 0;
694+}
695+
696+#endif
697+
698+#ifdef CONFIG_CCSECURITY_SIGNAL
699+
700+static inline int ccs_kill_permission(pid_t pid, int sig)
701+{
702+ int (*func) (pid_t, int) = ccsecurity_ops.kill_permission;
703+ return func ? func(pid, sig) : 0;
704+}
705+
706+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
707+{
708+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgkill_permission;
709+ return func ? func(tgid, pid, sig) : 0;
710+}
711+
712+static inline int ccs_tkill_permission(pid_t pid, int sig)
713+{
714+ int (*func) (pid_t, int) = ccsecurity_ops.tkill_permission;
715+ return func ? func(pid, sig) : 0;
716+}
717+
718+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
719+{
720+ int (*func) (pid_t, int) = ccsecurity_ops.sigqueue_permission;
721+ return func ? func(pid, sig) : 0;
722+}
723+
724+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
725+{
726+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgsigqueue_permission;
727+ return func ? func(tgid, pid, sig) : 0;
728+}
729+
730+#else
731+
732+static inline int ccs_kill_permission(pid_t pid, int sig)
733+{
734+ return 0;
735+}
736+
737+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
738+{
739+ return 0;
740+}
741+
742+static inline int ccs_tkill_permission(pid_t pid, int sig)
743+{
744+ return 0;
745+}
746+
747+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
748+{
749+ return 0;
750+}
751+
752+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
753+{
754+ return 0;
755+}
756+
757+#endif
758+
759+/* Index numbers for Capability Controls. */
760+enum ccs_capability_acl_index {
761+ /* socket(PF_ROUTE, *, *) */
762+ CCS_USE_ROUTE_SOCKET,
763+ /* socket(PF_PACKET, *, *) */
764+ CCS_USE_PACKET_SOCKET,
765+ /* sys_reboot() */
766+ CCS_SYS_REBOOT,
767+ /* sys_vhangup() */
768+ CCS_SYS_VHANGUP,
769+ /* do_settimeofday(), sys_adjtimex() */
770+ CCS_SYS_SETTIME,
771+ /* sys_nice(), sys_setpriority() */
772+ CCS_SYS_NICE,
773+ /* sys_sethostname(), sys_setdomainname() */
774+ CCS_SYS_SETHOSTNAME,
775+ /* sys_create_module(), sys_init_module(), sys_delete_module() */
776+ CCS_USE_KERNEL_MODULE,
777+ /* sys_kexec_load() */
778+ CCS_SYS_KEXEC_LOAD,
779+ CCS_MAX_CAPABILITY_INDEX
780+};
781+
782+#endif
--- trunk/caitsith-patch/security/caitsith/load_policy.c (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/load_policy.c (revision 2)
@@ -0,0 +1,229 @@
1+/*
2+ * security/caitsith/load_policy.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#include <linux/version.h>
10+#include <linux/module.h>
11+#include <linux/init.h>
12+#include <linux/binfmts.h>
13+#include <linux/sched.h>
14+#include <linux/fs.h>
15+#include <linux/namei.h>
16+#ifndef LOOKUP_POSITIVE
17+#define LOOKUP_POSITIVE 0
18+#endif
19+
20+/*
21+ * TOMOYO specific part start.
22+ */
23+
24+#include <linux/caitsith.h>
25+
26+/**
27+ * ccs_setup - Set enable/disable upon boot.
28+ *
29+ * @str: "off" to disable, "on" to enable.
30+ *
31+ * Returns 0.
32+ */
33+static int __init ccs_setup(char *str)
34+{
35+ if (!strcmp(str, "off"))
36+ ccsecurity_ops.disabled = 1;
37+ else if (!strcmp(str, "on"))
38+ ccsecurity_ops.disabled = 0;
39+ return 0;
40+}
41+
42+__setup("caitsith=", ccs_setup);
43+
44+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
45+
46+/* Path to the policy loader. (default = CONFIG_CCSECURITY_POLICY_LOADER) */
47+static const char *ccs_loader;
48+
49+/**
50+ * ccs_loader_setup - Set policy loader.
51+ *
52+ * @str: Program to use as a policy loader (e.g. /sbin/caitsith-init ).
53+ *
54+ * Returns 0.
55+ */
56+static int __init ccs_loader_setup(char *str)
57+{
58+ ccs_loader = str;
59+ return 0;
60+}
61+
62+__setup("CCS_loader=", ccs_loader_setup);
63+
64+/**
65+ * ccs_policy_loader_exists - Check whether /sbin/caitsith-init exists.
66+ *
67+ * Returns true if /sbin/caitsith-init exists, false otherwise.
68+ */
69+static _Bool ccs_policy_loader_exists(void)
70+{
71+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
72+ struct path path;
73+ if (!ccs_loader)
74+ ccs_loader = CONFIG_CCSECURITY_POLICY_LOADER;
75+ if (kern_path(ccs_loader, LOOKUP_FOLLOW | LOOKUP_POSITIVE,
76+ &path) == 0) {
77+ path_put(&path);
78+ return 1;
79+ }
80+#else
81+ struct nameidata nd;
82+ if (!ccs_loader)
83+ ccs_loader = CONFIG_CCSECURITY_POLICY_LOADER;
84+ if (path_lookup(ccs_loader, LOOKUP_FOLLOW | LOOKUP_POSITIVE,
85+ &nd) == 0) {
86+ path_put(&nd.path);
87+ return 1;
88+ }
89+#endif
90+ printk(KERN_INFO "Not activating Mandatory Access Control "
91+ "as %s does not exist.\n", ccs_loader);
92+ return 0;
93+}
94+
95+/* Path to the trigger. (default = CONFIG_CCSECURITY_ACTIVATION_TRIGGER) */
96+static const char *ccs_trigger;
97+
98+/**
99+ * ccs_trigger_setup - Set trigger for activation.
100+ *
101+ * @str: Program to use as an activation trigger (e.g. /sbin/init ).
102+ *
103+ * Returns 0.
104+ */
105+static int __init ccs_trigger_setup(char *str)
106+{
107+ ccs_trigger = str;
108+ return 0;
109+}
110+
111+__setup("CCS_trigger=", ccs_trigger_setup);
112+
113+/**
114+ * ccs_load_policy - Run external policy loader to load policy.
115+ *
116+ * @filename: The program about to start.
117+ *
118+ * Returns nothing.
119+ *
120+ * This function checks whether @filename is /sbin/init, and if so
121+ * invoke /sbin/caitsith-init and wait for the termination of /sbin/caitsith-init
122+ * and then continues invocation of /sbin/init.
123+ * /sbin/caitsith-init reads policy files in /etc/ccs/ directory and
124+ * writes to /proc/ccs/ interfaces.
125+ */
126+static void ccs_load_policy(const char *filename)
127+{
128+ static _Bool done;
129+ if (ccsecurity_ops.disabled || done)
130+ return;
131+ if (!ccs_trigger)
132+ ccs_trigger = CONFIG_CCSECURITY_ACTIVATION_TRIGGER;
133+ if (strcmp(filename, ccs_trigger))
134+ return;
135+ if (!ccs_policy_loader_exists())
136+ return;
137+ done = 1;
138+ {
139+ char *argv[2];
140+ char *envp[3];
141+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
142+ ccs_loader);
143+ argv[0] = (char *) ccs_loader;
144+ argv[1] = NULL;
145+ envp[0] = "HOME=/";
146+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
147+ envp[2] = NULL;
148+ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
149+ }
150+ if (ccsecurity_ops.check_profile)
151+ ccsecurity_ops.check_profile();
152+ else
153+ panic("Failed to load policy.");
154+}
155+
156+#endif
157+
158+/**
159+ * __ccs_search_binary_handler - Load policy before calling search_binary_handler().
160+ *
161+ * @bprm: Pointer to "struct linux_binprm".
162+ * @regs: Pointer to "struct pt_regs".
163+ *
164+ * Returns 0 on success, negative value otherwise.
165+ */
166+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
167+ struct pt_regs *regs)
168+{
169+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
170+ ccs_load_policy(bprm->filename);
171+#endif
172+ /*
173+ * ccs_load_policy() executes /sbin/caitsith-init if bprm->filename is
174+ * /sbin/init. /sbin/caitsith-init executes
175+ * /etc/ccs/caitsith-load-module to load loadable kernel module.
176+ * The loadable kernel module modifies "struct ccsecurity_ops". Thus,
177+ * we need to transfer control to __ccs_search_binary_handler() in
178+ * security/caitsith/permission.c if "struct ccsecurity_ops" was
179+ * modified.
180+ */
181+ if (ccsecurity_ops.search_binary_handler
182+ != __ccs_search_binary_handler)
183+ return ccsecurity_ops.search_binary_handler(bprm, regs);
184+ return search_binary_handler(bprm, regs);
185+}
186+
187+/*
188+ * Some exports for loadable kernel module part.
189+ *
190+ * Although scripts/checkpatch.pl complains about use of "extern" in C file,
191+ * we don't put these into security/caitsith/internal.h because we want to
192+ * split built-in part and loadable kernel module part.
193+ */
194+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
195+extern spinlock_t vfsmount_lock;
196+#endif
197+
198+/* For exporting variables and functions. */
199+const struct ccsecurity_exports ccsecurity_exports = {
200+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
201+ .load_policy = ccs_load_policy,
202+#endif
203+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
204+ .d_absolute_path = d_absolute_path,
205+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
206+ .__d_path = __d_path,
207+#else
208+ .vfsmount_lock = &vfsmount_lock,
209+#endif
210+ .find_task_by_vpid = find_task_by_vpid,
211+ .find_task_by_pid_ns = find_task_by_pid_ns,
212+};
213+#ifdef CONFIG_CCSECURITY_LKM
214+/* Only ccsecurity module need to access this struct. */
215+EXPORT_SYMBOL_GPL(ccsecurity_exports);
216+#endif
217+
218+/* Members are updated by loadable kernel module. */
219+struct ccsecurity_operations ccsecurity_ops = {
220+ .search_binary_handler = __ccs_search_binary_handler,
221+#ifdef CONFIG_CCSECURITY_DISABLE_BY_DEFAULT
222+ .disabled = 1,
223+#endif
224+};
225+/*
226+ * Non-GPL modules might need to access this struct via inlined functions
227+ * embedded into include/linux/security.h and include/net/ip.h
228+ */
229+EXPORT_SYMBOL(ccsecurity_ops);
--- trunk/caitsith-patch/security/caitsith/realpath.c (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/realpath.c (revision 2)
@@ -0,0 +1,644 @@
1+/*
2+ * security/caitsith/realpath.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#include "internal.h"
10+
11+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
12+#include <linux/nsproxy.h>
13+#include <linux/mnt_namespace.h>
14+#endif
15+
16+/***** SECTION1: Constants definition *****/
17+
18+#define SOCKFS_MAGIC 0x534F434B
19+
20+/***** SECTION2: Structure definition *****/
21+
22+/***** SECTION3: Prototype definition section *****/
23+
24+static char *ccs_get_absolute_path(struct path *path, char * const buffer,
25+ const int buflen);
26+static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
27+ const int buflen);
28+static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
29+ const int buflen);
30+static char *ccs_get_socket_name(struct path *path, char * const buffer,
31+ const int buflen);
32+static int ccs_const_part_length(const char *filename);
33+
34+/***** SECTION4: Standalone functions section *****/
35+
36+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
37+
38+/**
39+ * ccs_realpath_lock - Take locks for __d_path().
40+ *
41+ * Returns nothing.
42+ */
43+static inline void ccs_realpath_lock(void)
44+{
45+ /* dcache_lock is locked by __d_path(). */
46+ /* vfsmount_lock is locked by __d_path(). */
47+}
48+
49+/**
50+ * ccs_realpath_unlock - Release locks for __d_path().
51+ *
52+ * Returns nothing.
53+ */
54+static inline void ccs_realpath_unlock(void)
55+{
56+ /* vfsmount_lock is unlocked by __d_path(). */
57+ /* dcache_lock is unlocked by __d_path(). */
58+}
59+
60+#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 36)
61+
62+/**
63+ * ccs_realpath_lock - Take locks for __d_path().
64+ *
65+ * Returns nothing.
66+ */
67+static inline void ccs_realpath_lock(void)
68+{
69+ spin_lock(&dcache_lock);
70+ /* vfsmount_lock is locked by __d_path(). */
71+}
72+
73+/**
74+ * ccs_realpath_unlock - Release locks for __d_path().
75+ *
76+ * Returns nothing.
77+ */
78+static inline void ccs_realpath_unlock(void)
79+{
80+ /* vfsmount_lock is unlocked by __d_path(). */
81+ spin_unlock(&dcache_lock);
82+}
83+
84+#elif defined(D_PATH_DISCONNECT) && !defined(CONFIG_SUSE_KERNEL)
85+
86+/**
87+ * ccs_realpath_lock - Take locks for __d_path().
88+ *
89+ * Returns nothing.
90+ *
91+ * Original unambiguous-__d_path.diff in patches.apparmor.tar.bz2 inversed the
92+ * order of holding dcache_lock and vfsmount_lock. That patch was applied on
93+ * (at least) SUSE 11.1 and Ubuntu 8.10 and Ubuntu 9.04 kernels.
94+ *
95+ * However, that patch was updated to use original order and the updated patch
96+ * is applied to (as far as I know) only SUSE kernels.
97+ *
98+ * Therefore, I need to use original order for SUSE 11.1 kernels and inversed
99+ * order for other kernels. I detect it by checking D_PATH_DISCONNECT and
100+ * CONFIG_SUSE_KERNEL. I don't know whether other distributions are using the
101+ * updated patch or not. If you got deadlock, check fs/dcache.c for locking
102+ * order, and add " && 0" to this "#elif " block if fs/dcache.c uses original
103+ * order.
104+ */
105+static inline void ccs_realpath_lock(void)
106+{
107+ spin_lock(ccsecurity_exports.vfsmount_lock);
108+ spin_lock(&dcache_lock);
109+}
110+
111+/**
112+ * ccs_realpath_unlock - Release locks for __d_path().
113+ *
114+ * Returns nothing.
115+ */
116+static inline void ccs_realpath_unlock(void)
117+{
118+ spin_unlock(&dcache_lock);
119+ spin_unlock(ccsecurity_exports.vfsmount_lock);
120+}
121+
122+#else
123+
124+/**
125+ * ccs_realpath_lock - Take locks for __d_path().
126+ *
127+ * Returns nothing.
128+ */
129+static inline void ccs_realpath_lock(void)
130+{
131+ spin_lock(&dcache_lock);
132+ spin_lock(ccsecurity_exports.vfsmount_lock);
133+}
134+
135+/**
136+ * ccs_realpath_unlock - Release locks for __d_path().
137+ *
138+ * Returns nothing.
139+ */
140+static inline void ccs_realpath_unlock(void)
141+{
142+ spin_unlock(ccsecurity_exports.vfsmount_lock);
143+ spin_unlock(&dcache_lock);
144+}
145+
146+#endif
147+
148+/***** SECTION5: Variables definition section *****/
149+
150+/***** SECTION6: Dependent functions section *****/
151+
152+/**
153+ * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
154+ *
155+ * @path: Pointer to "struct path".
156+ * @buffer: Pointer to buffer to return value in.
157+ * @buflen: Sizeof @buffer.
158+ *
159+ * Returns the buffer on success, an error code otherwise.
160+ *
161+ * Caller holds the dcache_lock and vfsmount_lock.
162+ * Based on __d_path() in fs/dcache.c
163+ */
164+static char *ccs_get_absolute_path(struct path *path, char * const buffer,
165+ const int buflen)
166+{
167+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
168+ if (buflen < 256)
169+ return ERR_PTR(-ENOMEM);
170+ return ccsecurity_exports.d_absolute_path(path, buffer, buflen - 1);
171+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
172+ /*
173+ * __d_path() will start returning NULL by backporting commit 02125a82
174+ * "fix apparmor dereferencing potentially freed dentry, sanitize
175+ * __d_path() API".
176+ *
177+ * Unfortunately, __d_path() after applying that commit always returns
178+ * NULL when root is empty. d_absolute_path() is provided for TOMOYO
179+ * 2.x and AppArmor but TOMOYO 1.x does not use it, for TOMOYO 1.x
180+ * might be built as a loadable kernel module and there is no warrantee
181+ * that TOMOYO 1.x is recompiled after applying that commit. Also,
182+ * I don't want to search /proc/kallsyms for d_absolute_path() because
183+ * I want to keep TOMOYO 1.x architecture independent. Thus, supply
184+ * non empty root like AppArmor's d_namespace_path() did.
185+ */
186+ static bool ccs_no_empty;
187+ char *pos;
188+ if (buflen < 256)
189+ return ERR_PTR(-ENOMEM);
190+ if (!ccs_no_empty) {
191+ struct path root = { };
192+ pos = ccsecurity_exports.__d_path(path, &root, buffer,
193+ buflen - 1);
194+ } else {
195+ pos = NULL;
196+ }
197+ if (!pos) {
198+ struct task_struct *task = current;
199+ struct path root;
200+ struct path tmp;
201+ spin_lock(&task->fs->lock);
202+ root.mnt = task->nsproxy->mnt_ns->root;
203+ root.dentry = root.mnt->mnt_root;
204+ path_get(&root);
205+ spin_unlock(&task->fs->lock);
206+ tmp = root;
207+ pos = ccsecurity_exports.__d_path(path, &tmp, buffer,
208+ buflen - 1);
209+ path_put(&root);
210+ if (pos)
211+ return pos;
212+ /* Remember if __d_path() needs non empty root. */
213+ ccs_no_empty = true;
214+ pos = ERR_PTR(-EINVAL);
215+ }
216+ return pos;
217+#else
218+ char *pos = buffer + buflen - 1;
219+ struct dentry *dentry = path->dentry;
220+ struct vfsmount *vfsmnt = path->mnt;
221+ const char *name;
222+ int len;
223+
224+ if (buflen < 256)
225+ goto out;
226+
227+ *pos = '\0';
228+ for (;;) {
229+ struct dentry *parent;
230+ if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
231+ if (vfsmnt->mnt_parent == vfsmnt)
232+ break;
233+ dentry = vfsmnt->mnt_mountpoint;
234+ vfsmnt = vfsmnt->mnt_parent;
235+ continue;
236+ }
237+ parent = dentry->d_parent;
238+ name = dentry->d_name.name;
239+ len = dentry->d_name.len;
240+ pos -= len;
241+ if (pos <= buffer)
242+ goto out;
243+ memmove(pos, name, len);
244+ *--pos = '/';
245+ dentry = parent;
246+ }
247+ if (*pos == '/')
248+ pos++;
249+ len = dentry->d_name.len;
250+ pos -= len;
251+ if (pos < buffer)
252+ goto out;
253+ memmove(pos, dentry->d_name.name, len);
254+ return pos;
255+out:
256+ return ERR_PTR(-ENOMEM);
257+#endif
258+}
259+
260+/**
261+ * ccs_get_dentry_path - Get the path of a dentry.
262+ *
263+ * @dentry: Pointer to "struct dentry".
264+ * @buffer: Pointer to buffer to return value in.
265+ * @buflen: Sizeof @buffer.
266+ *
267+ * Returns the buffer on success, an error code otherwise.
268+ *
269+ * Based on dentry_path() in fs/dcache.c
270+ */
271+static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
272+ const int buflen)
273+{
274+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
275+ if (buflen < 256)
276+ return ERR_PTR(-ENOMEM);
277+ /* rename_lock is locked/unlocked by dentry_path_raw(). */
278+ return dentry_path_raw(dentry, buffer, buflen - 1);
279+#else
280+ char *pos = buffer + buflen - 1;
281+ if (buflen < 256)
282+ return ERR_PTR(-ENOMEM);
283+ *pos = '\0';
284+ spin_lock(&dcache_lock);
285+ while (!IS_ROOT(dentry)) {
286+ struct dentry *parent = dentry->d_parent;
287+ const char *name = dentry->d_name.name;
288+ const int len = dentry->d_name.len;
289+ pos -= len;
290+ if (pos <= buffer) {
291+ pos = ERR_PTR(-ENOMEM);
292+ break;
293+ }
294+ memmove(pos, name, len);
295+ *--pos = '/';
296+ dentry = parent;
297+ }
298+ spin_unlock(&dcache_lock);
299+ if (pos == buffer + buflen - 1)
300+ *--pos = '/';
301+ return pos;
302+#endif
303+}
304+
305+/**
306+ * ccs_get_local_path - Get the path of a dentry.
307+ *
308+ * @dentry: Pointer to "struct dentry".
309+ * @buffer: Pointer to buffer to return value in.
310+ * @buflen: Sizeof @buffer.
311+ *
312+ * Returns the buffer on success, an error code otherwise.
313+ */
314+static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
315+ const int buflen)
316+{
317+ struct super_block *sb = dentry->d_sb;
318+ char *pos = ccs_get_dentry_path(dentry, buffer, buflen);
319+ if (IS_ERR(pos))
320+ return pos;
321+ /* Convert from $PID to self if $PID is current thread. */
322+ if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
323+ char *ep;
324+ const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
325+ if (*ep == '/' && pid && pid ==
326+ task_tgid_nr_ns(current, sb->s_fs_info)) {
327+ pos = ep - 5;
328+ if (pos < buffer)
329+ goto out;
330+ memmove(pos, "/self", 5);
331+ }
332+ goto prepend_filesystem_name;
333+ }
334+ /* Use filesystem name for unnamed devices. */
335+ if (!MAJOR(sb->s_dev))
336+ goto prepend_filesystem_name;
337+ {
338+ struct inode *inode = sb->s_root->d_inode;
339+ /*
340+ * Use filesystem name if filesystems does not support rename()
341+ * operation.
342+ */
343+ if (inode->i_op && !inode->i_op->rename)
344+ goto prepend_filesystem_name;
345+ }
346+ /* Prepend device name. */
347+ {
348+ char name[64];
349+ int name_len;
350+ const dev_t dev = sb->s_dev;
351+ name[sizeof(name) - 1] = '\0';
352+ snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
353+ MINOR(dev));
354+ name_len = strlen(name);
355+ pos -= name_len;
356+ if (pos < buffer)
357+ goto out;
358+ memmove(pos, name, name_len);
359+ return pos;
360+ }
361+ /* Prepend filesystem name. */
362+prepend_filesystem_name:
363+ {
364+ const char *name = sb->s_type->name;
365+ const int name_len = strlen(name);
366+ pos -= name_len + 1;
367+ if (pos < buffer)
368+ goto out;
369+ memmove(pos, name, name_len);
370+ pos[name_len] = ':';
371+ }
372+ return pos;
373+out:
374+ return ERR_PTR(-ENOMEM);
375+}
376+
377+/**
378+ * ccs_get_socket_name - Get the name of a socket.
379+ *
380+ * @path: Pointer to "struct path".
381+ * @buffer: Pointer to buffer to return value in.
382+ * @buflen: Sizeof @buffer.
383+ *
384+ * Returns the buffer.
385+ */
386+static char *ccs_get_socket_name(struct path *path, char * const buffer,
387+ const int buflen)
388+{
389+ struct inode *inode = path->dentry->d_inode;
390+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
391+ struct sock *sk = sock ? sock->sk : NULL;
392+ if (sk) {
393+ snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
394+ "protocol=%u]", sk->sk_family, sk->sk_type,
395+ sk->sk_protocol);
396+ } else {
397+ snprintf(buffer, buflen, "socket:[unknown]");
398+ }
399+ return buffer;
400+}
401+
402+/**
403+ * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root.
404+ *
405+ * @path: Pointer to "struct path".
406+ *
407+ * Returns the realpath of the given @path on success, NULL otherwise.
408+ *
409+ * This function uses kzalloc(), so caller must kfree() if this function
410+ * didn't return NULL.
411+ */
412+char *ccs_realpath(struct path *path)
413+{
414+ char *buf = NULL;
415+ char *name = NULL;
416+ unsigned int buf_len = PAGE_SIZE / 2;
417+ struct dentry *dentry = path->dentry;
418+ struct super_block *sb;
419+ if (!dentry)
420+ return NULL;
421+ sb = dentry->d_sb;
422+ while (1) {
423+ char *pos;
424+ struct inode *inode;
425+ buf_len <<= 1;
426+ kfree(buf);
427+ buf = kmalloc(buf_len, GFP_NOFS);
428+ if (!buf)
429+ break;
430+ /* To make sure that pos is '\0' terminated. */
431+ buf[buf_len - 1] = '\0';
432+ /* Get better name for socket. */
433+ if (sb->s_magic == SOCKFS_MAGIC) {
434+ pos = ccs_get_socket_name(path, buf, buf_len - 1);
435+ goto encode;
436+ }
437+ /* For "pipe:[\$]". */
438+ if (dentry->d_op && dentry->d_op->d_dname) {
439+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
440+ goto encode;
441+ }
442+ inode = sb->s_root->d_inode;
443+ /*
444+ * Use local name for "filesystems without rename() operation"
445+ * or "path without vfsmount" or "absolute name is unavailable"
446+ * cases.
447+ */
448+ if (!path->mnt || (inode->i_op && !inode->i_op->rename))
449+ pos = ERR_PTR(-EINVAL);
450+ else {
451+ /* Get absolute name for the rest. */
452+ ccs_realpath_lock();
453+ pos = ccs_get_absolute_path(path, buf, buf_len - 1);
454+ ccs_realpath_unlock();
455+ }
456+ if (pos == ERR_PTR(-EINVAL))
457+ pos = ccs_get_local_path(path->dentry, buf,
458+ buf_len - 1);
459+encode:
460+ if (IS_ERR(pos))
461+ continue;
462+ name = ccs_encode(pos);
463+ break;
464+ }
465+ kfree(buf);
466+ if (!name)
467+ ccs_warn_oom(__func__);
468+ return name;
469+}
470+
471+/**
472+ * ccs_encode2 - Encode binary string to ascii string.
473+ *
474+ * @str: String in binary format. Maybe NULL.
475+ * @str_len: Size of @str in byte.
476+ *
477+ * Returns pointer to @str in ascii format on success, NULL otherwise.
478+ *
479+ * This function uses kzalloc(), so caller must kfree() if this function
480+ * didn't return NULL.
481+ */
482+char *ccs_encode2(const char *str, int str_len)
483+{
484+ int i;
485+ int len;
486+ const char *p = str;
487+ char *cp;
488+ char *cp0;
489+ if (!p)
490+ return NULL;
491+ len = str_len;
492+ for (i = 0; i < str_len; i++) {
493+ const unsigned char c = p[i];
494+ if (!(c > ' ' && c < 127 && c != '\\'))
495+ len += 3;
496+ }
497+ len++;
498+ cp = kzalloc(len, GFP_NOFS);
499+ if (!cp)
500+ return NULL;
501+ cp0 = cp;
502+ p = str;
503+ for (i = 0; i < str_len; i++) {
504+ const unsigned char c = p[i];
505+ if (c > ' ' && c < 127 && c != '\\') {
506+ *cp++ = c;
507+ } else {
508+ *cp++ = '\\';
509+ *cp++ = (c >> 6) + '0';
510+ *cp++ = ((c >> 3) & 7) + '0';
511+ *cp++ = (c & 7) + '0';
512+ }
513+ }
514+ return cp0;
515+}
516+
517+/**
518+ * ccs_encode - Encode binary string to ascii string.
519+ *
520+ * @str: String in binary format. Maybe NULL.
521+ *
522+ * Returns pointer to @str in ascii format on success, NULL otherwise.
523+ *
524+ * This function uses kzalloc(), so caller must kfree() if this function
525+ * didn't return NULL.
526+ */
527+char *ccs_encode(const char *str)
528+{
529+ return str ? ccs_encode2(str, strlen(str)) : NULL;
530+}
531+
532+/**
533+ * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
534+ *
535+ * @filename: The string to evaluate. Maybe NULL.
536+ *
537+ * Returns the initial length without a pattern in @filename.
538+ */
539+static int ccs_const_part_length(const char *filename)
540+{
541+ char c;
542+ int len = 0;
543+ if (!filename)
544+ return 0;
545+ while (1) {
546+ c = *filename++;
547+ if (!c)
548+ break;
549+ if (c != '\\') {
550+ len++;
551+ continue;
552+ }
553+ c = *filename++;
554+ switch (c) {
555+ case '0': /* "\ooo" */
556+ case '1':
557+ case '2':
558+ case '3':
559+ c = *filename++;
560+ if (c < '0' || c > '7')
561+ break;
562+ c = *filename++;
563+ if (c < '0' || c > '7')
564+ break;
565+ len += 4;
566+ continue;
567+ }
568+ break;
569+ }
570+ return len;
571+}
572+
573+/**
574+ * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
575+ *
576+ * @ptr: Pointer to "struct ccs_path_info" to fill in.
577+ *
578+ * Returns nothing.
579+ *
580+ * The caller sets "struct ccs_path_info"->name.
581+ */
582+void ccs_fill_path_info(struct ccs_path_info *ptr)
583+{
584+ const char *name = ptr->name;
585+ const int len = strlen(name);
586+ ptr->total_len = len;
587+ ptr->const_len = ccs_const_part_length(name);
588+ ptr->hash = full_name_hash(name, len);
589+}
590+
591+/**
592+ * ccs_get_exe - Get ccs_realpath() of current process.
593+ *
594+ * Returns the ccs_realpath() of current process on success, NULL otherwise.
595+ *
596+ * This function uses kzalloc(), so the caller must kfree()
597+ * if this function didn't return NULL.
598+ */
599+char *ccs_get_exe(void)
600+{
601+ struct mm_struct *mm;
602+ struct vm_area_struct *vma;
603+ bool done = false;
604+ char *cp = NULL;
605+ if (current->flags & PF_KTHREAD)
606+ return kstrdup("<kernel>", GFP_NOFS);
607+ mm = current->mm;
608+ if (!mm)
609+ goto task_has_no_mm;
610+ down_read(&mm->mmap_sem);
611+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
612+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
613+ cp = ccs_realpath(&vma->vm_file->f_path);
614+ done = true;
615+ break;
616+ }
617+ }
618+ up_read(&mm->mmap_sem);
619+ if (done)
620+ return cp;
621+task_has_no_mm:
622+ /* I'don't know. */
623+ return kstrdup("<unknown>", GFP_NOFS);
624+}
625+
626+/**
627+ * ccs_get_exename - Get ccs_realpath() of current process.
628+ *
629+ * @buf: Pointer to "struct ccs_path_info".
630+ *
631+ * Returns true on success, false otherwise.
632+ *
633+ * This function uses kzalloc(), so the caller must kfree()
634+ * if this function returned true.
635+ */
636+bool ccs_get_exename(struct ccs_path_info *buf)
637+{
638+ buf->name = ccs_get_exe();
639+ if (buf->name) {
640+ ccs_fill_path_info(buf);
641+ return true;
642+ }
643+ return false;
644+}
--- trunk/caitsith-patch/security/caitsith/internal.h (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/internal.h (revision 2)
@@ -0,0 +1,1162 @@
1+/*
2+ * security/caitsith/internal.h
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#ifndef _SECURITY_CCSECURITY_INTERNAL_H
10+#define _SECURITY_CCSECURITY_INTERNAL_H
11+
12+#include <linux/version.h>
13+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
14+#error This module supports only 2.6.27 and later kernels.
15+#endif
16+#include <linux/types.h>
17+#include <linux/kernel.h>
18+#include <linux/string.h>
19+#include <linux/mm.h>
20+#include <linux/utime.h>
21+#include <linux/file.h>
22+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38)
23+#include <linux/smp_lock.h>
24+#endif
25+#include <linux/module.h>
26+#include <linux/init.h>
27+#include <linux/slab.h>
28+#include <linux/highmem.h>
29+#include <linux/poll.h>
30+#include <linux/binfmts.h>
31+#include <linux/delay.h>
32+#include <linux/sched.h>
33+#include <linux/dcache.h>
34+#include <linux/mount.h>
35+#include <linux/net.h>
36+#include <linux/inet.h>
37+#include <linux/in.h>
38+#include <linux/in6.h>
39+#include <linux/un.h>
40+#include <linux/ptrace.h>
41+#include <linux/namei.h>
42+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
43+#include <linux/fs_struct.h>
44+#endif
45+#include <linux/proc_fs.h>
46+#include <linux/hash.h>
47+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
48+#include <linux/sysctl.h>
49+#endif
50+#include <linux/kthread.h>
51+#include <stdarg.h>
52+#include <asm/uaccess.h>
53+#include <net/sock.h>
54+#include <net/af_unix.h>
55+#include <net/ip.h>
56+#include <net/ipv6.h>
57+#include <net/udp.h>
58+
59+#ifndef __printf
60+#define __printf(a,b) __attribute__((format(printf,a,b)))
61+#endif
62+#ifndef __packed
63+#define __packed __attribute__((__packed__))
64+#endif
65+#ifndef bool
66+#define bool _Bool
67+#endif
68+#ifndef false
69+#define false 0
70+#endif
71+#ifndef true
72+#define true 1
73+#endif
74+
75+#ifndef __user
76+#define __user
77+#endif
78+
79+#ifndef current_uid
80+#define current_uid() (current->uid)
81+#endif
82+#ifndef current_gid
83+#define current_gid() (current->gid)
84+#endif
85+#ifndef current_euid
86+#define current_euid() (current->euid)
87+#endif
88+#ifndef current_egid
89+#define current_egid() (current->egid)
90+#endif
91+#ifndef current_suid
92+#define current_suid() (current->suid)
93+#endif
94+#ifndef current_sgid
95+#define current_sgid() (current->sgid)
96+#endif
97+#ifndef current_fsuid
98+#define current_fsuid() (current->fsuid)
99+#endif
100+#ifndef current_fsgid
101+#define current_fsgid() (current->fsgid)
102+#endif
103+
104+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
105+
106+/**
107+ * __list_del_entry - Deletes entry from list without re-initialization.
108+ *
109+ * @entry: Pointer to "struct list_head".
110+ *
111+ * Returns nothing.
112+ *
113+ * This is for compatibility with older kernels.
114+ */
115+static inline void __list_del_entry(struct list_head *entry)
116+{
117+ __list_del(entry->prev, entry->next);
118+}
119+
120+#endif
121+
122+#ifndef list_for_each_entry_safe
123+
124+/**
125+ * list_for_each_entry_safe - Iterate over list of given type safe against removal of list entry.
126+ *
127+ * @pos: The "type *" to use as a loop cursor.
128+ * @n: Another "type *" to use as temporary storage.
129+ * @head: Pointer to "struct list_head".
130+ * @member: The name of the list_struct within the struct.
131+ *
132+ * This is for compatibility with older kernels.
133+ */
134+#define list_for_each_entry_safe(pos, n, head, member) \
135+ for (pos = list_entry((head)->next, typeof(*pos), member), \
136+ n = list_entry(pos->member.next, typeof(*pos), member); \
137+ &pos->member != (head); \
138+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
139+
140+#endif
141+
142+#ifndef srcu_dereference
143+
144+/**
145+ * srcu_dereference - Fetch SRCU-protected pointer with checking.
146+ *
147+ * @p: The pointer to read, prior to dereferencing.
148+ * @ss: Pointer to "struct srcu_struct".
149+ *
150+ * Returns @p.
151+ *
152+ * This is for compatibility with older kernels.
153+ */
154+#define srcu_dereference(p, ss) rcu_dereference(p)
155+
156+#endif
157+
158+#ifndef list_for_each_entry_srcu
159+
160+/**
161+ * list_for_each_entry_srcu - Iterate over rcu list of given type.
162+ *
163+ * @pos: The type * to use as a loop cursor.
164+ * @head: The head for your list.
165+ * @member: The name of the list_struct within the struct.
166+ * @ss: Pointer to "struct srcu_struct".
167+ *
168+ * As of 2.6.36, this macro is not provided because only TOMOYO wants it.
169+ */
170+#define list_for_each_entry_srcu(pos, head, member, ss) \
171+ for (pos = list_entry(srcu_dereference((head)->next, ss), \
172+ typeof(*pos), member); \
173+ prefetch(pos->member.next), &pos->member != (head); \
174+ pos = list_entry(srcu_dereference(pos->member.next, ss), \
175+ typeof(*pos), member))
176+
177+#endif
178+
179+/*
180+ * TOMOYO specific part start.
181+ */
182+
183+#include <linux/ccsecurity.h>
184+
185+/* Enumeration definition for internal use. */
186+
187+/* Index numbers for "struct ccs_condition". */
188+enum ccs_conditions_index {
189+ /* 0 */
190+ CCS_SELF_UID, /* current_uid() */
191+ CCS_SELF_EUID, /* current_euid() */
192+ CCS_SELF_SUID, /* current_suid() */
193+ CCS_SELF_FSUID, /* current_fsuid() */
194+ CCS_SELF_GID, /* current_gid() */
195+ CCS_SELF_EGID, /* current_egid() */
196+ CCS_SELF_SGID, /* current_sgid() */
197+ CCS_SELF_FSGID, /* current_fsgid() */
198+ CCS_SELF_PID, /* sys_getpid() */
199+ CCS_SELF_PPID, /* sys_getppid() */
200+ /* 10 */
201+ CCS_TASK_TYPE, /* ((u8) task->ccs_flags) &
202+ CCS_TASK_IS_EXECUTE_HANDLER */
203+ CCS_SELF_DOMAIN,
204+ CCS_SELF_EXE,
205+ CCS_EXEC_ARGC, /* "struct linux_binprm *"->argc */
206+ CCS_EXEC_ENVC, /* "struct linux_binprm *"->envc */
207+ CCS_OBJ_IS_SOCKET, /* S_IFSOCK */
208+ CCS_OBJ_IS_SYMLINK, /* S_IFLNK */
209+ CCS_OBJ_IS_FILE, /* S_IFREG */
210+ CCS_OBJ_IS_BLOCK_DEV, /* S_IFBLK */
211+ CCS_OBJ_IS_DIRECTORY, /* S_IFDIR */
212+ /* 20 */
213+ CCS_OBJ_IS_CHAR_DEV, /* S_IFCHR */
214+ CCS_OBJ_IS_FIFO, /* S_IFIFO */
215+ CCS_MODE_SETUID, /* S_ISUID */
216+ CCS_MODE_SETGID, /* S_ISGID */
217+ CCS_MODE_STICKY, /* S_ISVTX */
218+ CCS_MODE_OWNER_READ, /* S_IRUSR */
219+ CCS_MODE_OWNER_WRITE, /* S_IWUSR */
220+ CCS_MODE_OWNER_EXECUTE, /* S_IXUSR */
221+ CCS_MODE_GROUP_READ, /* S_IRGRP */
222+ CCS_MODE_GROUP_WRITE, /* S_IWGRP */
223+ /* 30 */
224+ CCS_MODE_GROUP_EXECUTE, /* S_IXGRP */
225+ CCS_MODE_OTHERS_READ, /* S_IROTH */
226+ CCS_MODE_OTHERS_WRITE, /* S_IWOTH */
227+ CCS_MODE_OTHERS_EXECUTE, /* S_IXOTH */
228+ CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
229+ CCS_HANDLER_PATH,
230+ CCS_TRANSIT_DOMAIN,
231+ CCS_MAX_CONDITION_KEYWORD,
232+ CCS_COND_SARG0,
233+ CCS_COND_SARG1,
234+ /* 40 */
235+ CCS_COND_SARG2,
236+ CCS_COND_SARG3,
237+ CCS_COND_NARG0,
238+ CCS_COND_NARG1,
239+ CCS_COND_NARG2,
240+ CCS_COND_IPARG,
241+ CCS_COND_DOMAIN,
242+ CCS_IMM_GROUP,
243+ CCS_IMM_NAME_ENTRY,
244+ CCS_IMM_NUMBER_ENTRY1,
245+ /* 50 */
246+ CCS_IMM_NUMBER_ENTRY2,
247+#ifdef CONFIG_CCSECURITY_NETWORK
248+ CCS_IMM_IPV4ADDR_ENTRY1,
249+ CCS_IMM_IPV4ADDR_ENTRY2,
250+ CCS_IMM_IPV6ADDR_ENTRY1,
251+ CCS_IMM_IPV6ADDR_ENTRY2,
252+#endif
253+ CCS_ARGV_ENTRY,
254+ CCS_ENVP_ENTRY,
255+ CCS_PATH_ATTRIBUTE_START = 192,
256+ CCS_PATH_ATTRIBUTE_END = 255
257+} __packed;
258+
259+enum ccs_path_attribute_index {
260+ CCS_PATH_ATTRIBUTE_UID,
261+ CCS_PATH_ATTRIBUTE_GID,
262+ CCS_PATH_ATTRIBUTE_INO,
263+ CCS_PATH_ATTRIBUTE_TYPE,
264+ CCS_PATH_ATTRIBUTE_MAJOR,
265+ CCS_PATH_ATTRIBUTE_MINOR,
266+ CCS_PATH_ATTRIBUTE_PERM,
267+ CCS_PATH_ATTRIBUTE_DEV_MAJOR,
268+ CCS_PATH_ATTRIBUTE_DEV_MINOR,
269+ CCS_PATH_ATTRIBUTE_FSMAGIC,
270+ CCS_MAX_PATH_ATTRIBUTE
271+} __packed;
272+
273+/* Index numbers for group entries. */
274+enum ccs_group_id {
275+ CCS_STRING_GROUP,
276+ CCS_NUMBER_GROUP,
277+#ifdef CONFIG_CCSECURITY_NETWORK
278+ CCS_IP_GROUP,
279+#endif
280+ CCS_MAX_GROUP
281+} __packed;
282+
283+/* Index numbers for functionality. */
284+enum ccs_mac_index {
285+ CCS_MAC_EXECUTE,
286+ CCS_MAC_READ,
287+ CCS_MAC_WRITE,
288+ CCS_MAC_APPEND,
289+ CCS_MAC_CREATE,
290+ CCS_MAC_UNLINK,
291+#ifdef CONFIG_CCSECURITY_GETATTR
292+ CCS_MAC_GETATTR,
293+#endif
294+ CCS_MAC_MKDIR,
295+ CCS_MAC_RMDIR,
296+ CCS_MAC_MKFIFO,
297+ CCS_MAC_MKSOCK,
298+ CCS_MAC_TRUNCATE,
299+ CCS_MAC_SYMLINK,
300+ CCS_MAC_MKBLOCK,
301+ CCS_MAC_MKCHAR,
302+ CCS_MAC_LINK,
303+ CCS_MAC_RENAME,
304+ CCS_MAC_CHMOD,
305+ CCS_MAC_CHOWN,
306+ CCS_MAC_CHGRP,
307+ CCS_MAC_IOCTL,
308+ CCS_MAC_CHROOT,
309+ CCS_MAC_MOUNT,
310+ CCS_MAC_UMOUNT,
311+ CCS_MAC_PIVOT_ROOT,
312+#ifdef CONFIG_CCSECURITY_NETWORK
313+ CCS_MAC_INET_STREAM_BIND,
314+ CCS_MAC_INET_STREAM_LISTEN,
315+ CCS_MAC_INET_STREAM_CONNECT,
316+ CCS_MAC_INET_STREAM_ACCEPT,
317+ CCS_MAC_INET_DGRAM_BIND,
318+ CCS_MAC_INET_DGRAM_SEND,
319+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
320+ CCS_MAC_INET_DGRAM_RECV,
321+#endif
322+ CCS_MAC_INET_RAW_BIND,
323+ CCS_MAC_INET_RAW_SEND,
324+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
325+ CCS_MAC_INET_RAW_RECV,
326+#endif
327+ CCS_MAC_UNIX_STREAM_BIND,
328+ CCS_MAC_UNIX_STREAM_LISTEN,
329+ CCS_MAC_UNIX_STREAM_CONNECT,
330+ CCS_MAC_UNIX_STREAM_ACCEPT,
331+ CCS_MAC_UNIX_DGRAM_BIND,
332+ CCS_MAC_UNIX_DGRAM_SEND,
333+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
334+ CCS_MAC_UNIX_DGRAM_RECV,
335+#endif
336+ CCS_MAC_UNIX_SEQPACKET_BIND,
337+ CCS_MAC_UNIX_SEQPACKET_LISTEN,
338+ CCS_MAC_UNIX_SEQPACKET_CONNECT,
339+ CCS_MAC_UNIX_SEQPACKET_ACCEPT,
340+#endif
341+#ifdef CONFIG_CCSECURITY_ENVIRON
342+ CCS_MAC_ENVIRON,
343+#endif
344+#ifdef CONFIG_CCSECURITY_PTRACE
345+ CCS_MAC_PTRACE,
346+#endif
347+#ifdef CONFIG_CCSECURITY_SIGNAL
348+ CCS_MAC_SIGNAL,
349+#endif
350+ CCS_MAC_MODIFY_POLICY,
351+#ifdef CONFIG_CCSECURITY_CAPABILITY
352+ CCS_MAC_USE_NETLINK_SOCKET,
353+ CCS_MAC_USE_PACKET_SOCKET,
354+ CCS_MAC_USE_REBOOT,
355+ CCS_MAC_USE_VHANGUP,
356+ CCS_MAC_SET_TIME,
357+ CCS_MAC_SET_PRIORITY,
358+ CCS_MAC_SET_HOSTNAME,
359+ CCS_MAC_USE_KERNEL_MODULE,
360+ CCS_MAC_USE_NEW_KERNEL,
361+#endif
362+#ifdef CONFIG_CCSECURITY_AUTO_DOMAIN_TRANSITION
363+ CCS_MAC_AUTO_DOMAIN_TRANSITION,
364+#endif
365+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
366+ CCS_MAC_MANUAL_DOMAIN_TRANSITION,
367+#endif
368+ CCS_MAX_MAC_INDEX
369+} __packed;
370+
371+/* Index numbers for statistic information. */
372+enum ccs_memory_stat_type {
373+ CCS_MEMORY_POLICY,
374+ CCS_MEMORY_AUDIT,
375+ CCS_MEMORY_QUERY,
376+ CCS_MAX_MEMORY_STAT
377+} __packed;
378+
379+enum ccs_matching_result {
380+ CCS_MATCHING_UNMATCHED,
381+ CCS_MATCHING_ALLOWED,
382+ CCS_MATCHING_DENIED,
383+ CCS_MAX_MATCHING
384+} __packed;
385+
386+/* Index numbers for stat(). */
387+enum ccs_path_stat_index {
388+ /* Do not change this order. */
389+ CCS_PATH1,
390+ CCS_PATH1_PARENT,
391+ CCS_PATH2,
392+ CCS_PATH2_PARENT,
393+ CCS_MAX_PATH_STAT
394+} __packed;
395+
396+/* Index numbers for entry type. */
397+enum ccs_policy_id {
398+ CCS_ID_GROUP,
399+#ifdef CONFIG_CCSECURITY_NETWORK
400+ CCS_ID_IP_GROUP,
401+#endif
402+ CCS_ID_STRING_GROUP,
403+ CCS_ID_NUMBER_GROUP,
404+ CCS_ID_CONDITION,
405+ CCS_ID_NAME,
406+ CCS_ID_ACL,
407+ CCS_ID_DOMAIN,
408+ CCS_MAX_POLICY
409+} __packed;
410+
411+/* Index numbers for statistic information. */
412+enum ccs_policy_stat_type {
413+ CCS_STAT_POLICY_UPDATES,
414+ CCS_STAT_REQUEST_DENIED,
415+ CCS_MAX_POLICY_STAT
416+} __packed;
417+
418+/* Index numbers for /proc/ccs/ interfaces. */
419+enum ccs_proc_interface_index {
420+ CCS_POLICY,
421+ CCS_PROCESS_STATUS,
422+ CCS_AUDIT,
423+ CCS_VERSION,
424+ CCS_QUERY,
425+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
426+ CCS_EXECUTE_HANDLER,
427+#endif
428+} __packed;
429+
430+/* Index numbers for special mount operations. */
431+enum ccs_special_mount {
432+ CCS_MOUNT_BIND, /* mount --bind /source /dest */
433+ CCS_MOUNT_MOVE, /* mount --move /old /new */
434+ CCS_MOUNT_REMOUNT, /* mount -o remount /dir */
435+ CCS_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
436+ CCS_MOUNT_MAKE_PRIVATE, /* mount --make-private /dir */
437+ CCS_MOUNT_MAKE_SLAVE, /* mount --make-slave /dir */
438+ CCS_MOUNT_MAKE_SHARED, /* mount --make-shared /dir */
439+ CCS_MAX_SPECIAL_MOUNT
440+} __packed;
441+
442+/* Index numbers for type of numeric values. */
443+enum ccs_value_type {
444+ CCS_VALUE_TYPE_INVALID,
445+ CCS_VALUE_TYPE_DECIMAL,
446+ CCS_VALUE_TYPE_OCTAL,
447+ CCS_VALUE_TYPE_HEXADECIMAL,
448+} __packed;
449+
450+/* Index numbers for type of IP addresses. */
451+enum ccs_ipaddr_type {
452+ CCS_ADDRESS_TYPE_INVALID,
453+ CCS_ADDRESS_TYPE_IPV4,
454+ CCS_ADDRESS_TYPE_IPV4_RANGE,
455+ CCS_ADDRESS_TYPE_IPV6,
456+ CCS_ADDRESS_TYPE_IPV6_RANGE,
457+} __packed;
458+
459+/* Constants definition for internal use. */
460+
461+/*
462+ * TOMOYO uses this hash only when appending a string into the string table.
463+ * Frequency of appending strings is very low. So we don't need large (e.g.
464+ * 64k) hash size. 256 will be sufficient.
465+ */
466+#define CCS_HASH_BITS 8
467+#define CCS_MAX_HASH (1u << CCS_HASH_BITS)
468+
469+/*
470+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
471+ * Therefore, we don't need SOCK_MAX.
472+ */
473+#define CCS_SOCK_MAX 6
474+
475+/* Size of temporary buffer for execve() operation. */
476+#define CCS_EXEC_TMPSIZE 4096
477+
478+/* Patterns for auditing logs quota. */
479+#define CCS_MAX_LOG_QUOTA 256
480+
481+/* Garbage collector is trying to kfree() this element. */
482+#define CCS_GC_IN_PROGRESS -1
483+
484+/* Current thread is doing open(3) ? */
485+#define CCS_OPEN_FOR_IOCTL_ONLY 2
486+/* Current thread is doing do_execve() ? */
487+#define CCS_TASK_IS_IN_EXECVE 4
488+/* Current thread is running as an execute handler program? */
489+#define CCS_TASK_IS_EXECUTE_HANDLER 8
490+/* Current thread is allowed to modify policy via /proc/ccs/ interface? */
491+#define CCS_TASK_IS_MANAGER 16
492+
493+/*
494+ * Retry this request. Returned by ccs_supervisor() if policy violation has
495+ * occurred in enforcing mode and the userspace daemon decided to retry.
496+ *
497+ * We must choose a positive value in order to distinguish "granted" (which is
498+ * 0) and "rejected" (which is a negative value) and "retry".
499+ */
500+#define CCS_RETRY_REQUEST 1
501+
502+/* Size of read buffer for /proc/ccs/ interface. */
503+#define CCS_MAX_IO_READ_QUEUE 64
504+
505+/* Structure definition for internal use. */
506+
507+/* Common header for holding ACL entries. */
508+struct ccs_acl_head {
509+ struct list_head list;
510+ s8 is_deleted; /* true or false or CCS_GC_IN_PROGRESS */
511+} __packed;
512+
513+/* Common header for shared entries. */
514+struct ccs_shared_acl_head {
515+ struct list_head list;
516+ atomic_t users;
517+} __packed;
518+
519+/* Common header for individual entries. */
520+struct ccs_acl_info {
521+ struct list_head list;
522+ struct list_head acl_info_list;
523+ struct ccs_condition *cond; /* Maybe NULL. */
524+ bool is_deleted;
525+ bool is_deny;
526+ u16 priority;
527+ u8 audit;
528+};
529+
530+/* Structure for "string_group"/"number_group"/"ip_group" directive. */
531+struct ccs_group {
532+ struct ccs_shared_acl_head head;
533+ /* Name of group (without leading "@"). */
534+ const struct ccs_path_info *group_name;
535+ /*
536+ * List of "struct ccs_string_group" or "struct ccs_number_group" or
537+ * "struct ccs_ip_group".
538+ */
539+ struct list_head member_list;
540+};
541+
542+/* Structure for "string_group" directive. */
543+struct ccs_string_group {
544+ struct ccs_acl_head head;
545+ const struct ccs_path_info *member_name;
546+};
547+
548+/* Structure for "number_group" directive. */
549+struct ccs_number_group {
550+ struct ccs_acl_head head;
551+ u8 radix;
552+ unsigned long value[2];
553+};
554+
555+/* Structure for "ip_group" directive. */
556+struct ccs_ip_group {
557+ struct ccs_acl_head head;
558+ bool is_ipv6;
559+ /* Structure for holding an IP address. */
560+ struct in6_addr ip[2]; /* Big endian. */
561+};
562+
563+/* Subset of "struct stat". Used by conditional ACL and audit logs. */
564+struct ccs_mini_stat {
565+ uid_t uid;
566+ gid_t gid;
567+ ino_t ino;
568+ umode_t mode;
569+ dev_t dev;
570+ dev_t rdev;
571+ unsigned long fsmagic;
572+};
573+
574+/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
575+struct ccs_page_dump {
576+ struct page *page; /* Previously dumped page. */
577+ char *data; /* Contents of "page". Size is PAGE_SIZE. */
578+};
579+
580+/* Structure for entries which follows "struct ccs_condition". */
581+union ccs_condition_element {
582+ struct {
583+ enum ccs_conditions_index left;
584+ enum ccs_conditions_index right;
585+ bool is_not;
586+ u8 radix;
587+ };
588+ struct ccs_group *group;
589+ const struct ccs_path_info *path;
590+ u32 ip; /* Repeat 4 times if IPv6 address. */
591+ unsigned long value;
592+};
593+
594+/* Structure for optional arguments. */
595+struct ccs_condition {
596+ struct ccs_shared_acl_head head;
597+ u32 size; /* Memory size allocated for this entry. */
598+ /* union ccs_condition_element condition[]; */
599+};
600+
601+/* Structure for holding a token. */
602+struct ccs_path_info {
603+ const char *name;
604+ u32 hash; /* = full_name_hash(name, strlen(name)) */
605+ u32 total_len; /* = strlen(name) */
606+ u32 const_len; /* = ccs_const_part_length(name) */
607+};
608+
609+/* Structure for request info. */
610+struct ccs_request_info {
611+ /* For holding parameters. */
612+ struct ccs_request_param {
613+ const struct ccs_path_info *s[4];
614+ unsigned long i[3];
615+#ifdef CONFIG_CCSECURITY_NETWORK
616+ const u8 *ip; /* Big endian. */
617+ bool is_ipv6;
618+#endif
619+ } param;
620+ /* For holding pathnames and attributes. */
621+ struct {
622+ /*
623+ * True if ccs_get_attributes() was already called, false
624+ * otherwise.
625+ */
626+ bool validate_done;
627+ /* True if @stat[] is valid. */
628+ bool stat_valid[CCS_MAX_PATH_STAT];
629+ /* Pointer to file objects. */
630+ struct path path[2];
631+ /*
632+ * Information on @path[0], @path[0]'s parent directory,
633+ * @path[1] and @path[1]'s parent directory.
634+ */
635+ struct ccs_mini_stat stat[CCS_MAX_PATH_STAT];
636+ /*
637+ * Name of @path[0] and @path[1].
638+ * Cleared by ccs_crear_request_info().
639+ */
640+ struct ccs_path_info pathname[2];
641+ } obj;
642+ struct {
643+ struct linux_binprm *bprm;
644+ struct ccs_domain_info *previous_domain;
645+ /* For execute_handler. */
646+ char *handler; /* kstrdup(handler_path->name, GFP_NOFS) */
647+ /* For dumping argv[] and envp[]. */
648+ struct ccs_page_dump dump;
649+ /* For temporary use. Size is CCS_EXEC_TMPSIZE bytes. */
650+ char *tmp;
651+ };
652+ /*
653+ * Name of current thread's executable.
654+ * Cleared by ccs_crear_request_info().
655+ */
656+ struct ccs_path_info exename;
657+ /*
658+ * Matching "struct ccs_acl_info" is copied. Used for ccs-queryd.
659+ * Valid until ccs_read_unlock().
660+ */
661+ struct ccs_acl_info *matched_acl;
662+ /*
663+ * Matching handler and domain transition are copied.
664+ * Valid until ccs_read_unlock().
665+ */
666+ const struct ccs_path_info *handler_path;
667+ const struct ccs_path_info *transition;
668+ const struct ccs_path_info *handler_path_candidate;
669+ const struct ccs_path_info *transition_candidate;
670+ /*
671+ * For holding operation index used for this request.
672+ * One of values in "enum ccs_mac_index".
673+ */
674+ enum ccs_mac_index type;
675+ /* For holding matching result. */
676+ enum ccs_matching_result result;
677+ /*
678+ * For counting number of retries made for this request.
679+ * This counter is incremented whenever ccs_supervisor() returned
680+ * CCS_RETRY_REQUEST.
681+ */
682+ u8 retry;
683+ /* For holding max audit log count for this matching entry. */
684+ u8 audit;
685+ /*
686+ * Set to true if condition could not be checked due to out of memory.
687+ * This flag is used for returning out of memory flag back to
688+ * ccs_check_acl_list(). Thus, this flag will not be set if out of
689+ * memory occurred before ccs_check_acl_list() is called.
690+ */
691+ bool failed_by_oom;
692+};
693+
694+/* Structure for domain information. */
695+struct ccs_domain_info {
696+ struct list_head list;
697+ /* Name of this domain. Never NULL. */
698+ const struct ccs_path_info *domainname;
699+};
700+
701+/* Structure for holding string data. */
702+struct ccs_name {
703+ struct ccs_shared_acl_head head;
704+ int size; /* Memory size allocated for this entry. */
705+ struct ccs_path_info entry;
706+};
707+
708+/* Structure for reading/writing policy via /proc/ccs/ interfaces. */
709+struct ccs_io_buffer {
710+ /* Exclusive lock for this structure. */
711+ struct mutex io_sem;
712+ char __user *read_user_buf;
713+ size_t read_user_buf_avail;
714+ struct {
715+ struct list_head *group;
716+ struct list_head *acl;
717+ struct list_head *subacl;
718+ const union ccs_condition_element *cond;
719+ size_t avail;
720+ unsigned int step;
721+ unsigned int query_index;
722+ u16 index;
723+ u8 cond_step;
724+ u8 w_pos;
725+ enum ccs_mac_index acl_index;
726+ bool eof;
727+ bool print_this_acl_only;
728+ bool version_done;
729+ bool stat_done;
730+ bool quota_done;
731+ bool group_done;
732+ const char *w[CCS_MAX_IO_READ_QUEUE];
733+ } r;
734+ struct {
735+ char *data;
736+ struct ccs_acl_info *acl;
737+ size_t avail;
738+ enum ccs_mac_index acl_index;
739+ bool is_delete;
740+ bool is_deny;
741+ u16 priority;
742+ } w;
743+ /* Buffer for reading. */
744+ char *read_buf;
745+ /* Size of read buffer. */
746+ size_t readbuf_size;
747+ /* Buffer for writing. */
748+ char *write_buf;
749+ /* Size of write buffer. */
750+ size_t writebuf_size;
751+ /* Type of interface. */
752+ enum ccs_proc_interface_index type;
753+ /* Users counter protected by ccs_io_buffer_list_lock. */
754+ u8 users;
755+ /* List for telling GC not to kfree() elements. */
756+ struct list_head list;
757+};
758+
759+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
760+struct ccs_time {
761+ u16 year;
762+ u8 month;
763+ u8 day;
764+ u8 hour;
765+ u8 min;
766+ u8 sec;
767+};
768+
769+/* Prototype definition for "struct ccsecurity_operations". */
770+
771+void __init ccs_permission_init(void);
772+void __init ccs_mm_init(void);
773+
774+/* Prototype definition for internal use. */
775+
776+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
777+ struct ccs_page_dump *dump);
778+bool ccs_get_exename(struct ccs_path_info *buf);
779+bool ccs_manager(void);
780+bool ccs_transit_domain(const char *domainname);
781+char *ccs_encode(const char *str);
782+char *ccs_encode2(const char *str, int str_len);
783+char *ccs_realpath(struct path *path);
784+char *ccs_get_exe(void);
785+int ccs_audit_log(struct ccs_request_info *r);
786+int ccs_check_acl(struct ccs_request_info *r, const bool clear);
787+void ccs_del_condition(struct list_head *element);
788+void ccs_fill_path_info(struct ccs_path_info *ptr);
789+void ccs_get_attributes(struct ccs_request_info *r);
790+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
791+void ccs_populate_patharg(struct ccs_request_info *r, const bool first);
792+void ccs_transition_failed(const char *domainname);
793+void ccs_warn_oom(const char *function);
794+
795+/* Variable definition for internal use. */
796+
797+extern bool ccs_policy_loaded;
798+extern struct ccs_domain_info ccs_kernel_domain;
799+extern struct ccs_path_info ccs_null_name;
800+extern struct list_head ccs_acl_list[CCS_MAX_MAC_INDEX];
801+extern struct list_head ccs_condition_list;
802+extern struct list_head ccs_domain_list;
803+extern struct list_head ccs_group_list[CCS_MAX_GROUP];
804+extern struct list_head ccs_name_list[CCS_MAX_HASH];
805+extern struct mutex ccs_policy_lock;
806+extern struct srcu_struct ccs_ss;
807+extern unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
808+
809+/* Inlined functions for internal use. */
810+
811+/**
812+ * ccs_pathcmp - strcmp() for "struct ccs_path_info" structure.
813+ *
814+ * @a: Pointer to "struct ccs_path_info".
815+ * @b: Pointer to "struct ccs_path_info".
816+ *
817+ * Returns true if @a != @b, false otherwise.
818+ */
819+static inline bool ccs_pathcmp(const struct ccs_path_info *a,
820+ const struct ccs_path_info *b)
821+{
822+ return a->hash != b->hash || strcmp(a->name, b->name);
823+}
824+
825+/**
826+ * ccs_read_lock - Take lock for protecting policy.
827+ *
828+ * Returns index number for ccs_read_unlock().
829+ */
830+static inline int ccs_read_lock(void)
831+{
832+ return srcu_read_lock(&ccs_ss);
833+}
834+
835+/**
836+ * ccs_read_unlock - Release lock for protecting policy.
837+ *
838+ * @idx: Index number returned by ccs_read_lock().
839+ *
840+ * Returns nothing.
841+ */
842+static inline void ccs_read_unlock(const int idx)
843+{
844+ srcu_read_unlock(&ccs_ss, idx);
845+}
846+
847+/**
848+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
849+ *
850+ * Returns nothing.
851+ */
852+static inline void ccs_tasklist_lock(void)
853+{
854+ rcu_read_lock();
855+}
856+
857+/**
858+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
859+ *
860+ * Returns nothing.
861+ */
862+static inline void ccs_tasklist_unlock(void)
863+{
864+ rcu_read_unlock();
865+}
866+
867+/**
868+ * ccs_sys_getppid - Copy of getppid().
869+ *
870+ * Returns parent process's PID.
871+ *
872+ * Alpha does not have getppid() defined. To be able to build this module on
873+ * Alpha, I have to copy getppid() from kernel/timer.c.
874+ */
875+static inline pid_t ccs_sys_getppid(void)
876+{
877+ pid_t pid;
878+ rcu_read_lock();
879+ pid = task_tgid_vnr(rcu_dereference(current->real_parent));
880+ rcu_read_unlock();
881+ return pid;
882+}
883+
884+/**
885+ * ccs_sys_getpid - Copy of getpid().
886+ *
887+ * Returns current thread's PID.
888+ *
889+ * Alpha does not have getpid() defined. To be able to build this module on
890+ * Alpha, I have to copy getpid() from kernel/timer.c.
891+ */
892+static inline pid_t ccs_sys_getpid(void)
893+{
894+ return task_tgid_vnr(current);
895+}
896+
897+#if defined(CONFIG_SLOB)
898+
899+/**
900+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
901+ *
902+ * @size: Size to be rounded up.
903+ *
904+ * Returns @size.
905+ *
906+ * Since SLOB does not round up, this function simply returns @size.
907+ */
908+static inline int ccs_round2(size_t size)
909+{
910+ return size;
911+}
912+
913+#else
914+
915+/**
916+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
917+ *
918+ * @size: Size to be rounded up.
919+ *
920+ * Returns rounded size.
921+ *
922+ * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
923+ * (e.g.) 128 bytes.
924+ */
925+static inline int ccs_round2(size_t size)
926+{
927+#if PAGE_SIZE == 4096
928+ size_t bsize = 32;
929+#else
930+ size_t bsize = 64;
931+#endif
932+ if (!size)
933+ return 0;
934+ while (size > bsize)
935+ bsize <<= 1;
936+ return bsize;
937+}
938+
939+#endif
940+
941+/**
942+ * ccs_put_condition - Drop reference on "struct ccs_condition".
943+ *
944+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
945+ *
946+ * Returns nothing.
947+ */
948+static inline void ccs_put_condition(struct ccs_condition *cond)
949+{
950+ if (cond)
951+ atomic_dec(&cond->head.users);
952+}
953+
954+/**
955+ * ccs_put_group - Drop reference on "struct ccs_group".
956+ *
957+ * @group: Pointer to "struct ccs_group". Maybe NULL.
958+ *
959+ * Returns nothing.
960+ */
961+static inline void ccs_put_group(struct ccs_group *group)
962+{
963+ if (group)
964+ atomic_dec(&group->head.users);
965+}
966+
967+/**
968+ * ccs_put_name - Drop reference on "struct ccs_name".
969+ *
970+ * @name: Pointer to "struct ccs_path_info". Maybe NULL.
971+ *
972+ * Returns nothing.
973+ */
974+static inline void ccs_put_name(const struct ccs_path_info *name)
975+{
976+ if (name)
977+ atomic_dec(&container_of(name, struct ccs_name, entry)->
978+ head.users);
979+}
980+
981+/* For importing variables and functions. */
982+extern const struct ccsecurity_exports ccsecurity_exports;
983+
984+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
985+
986+/*
987+ * Structure for holding "struct ccs_domain_info *" and "u32 ccs_flags" for
988+ * each "struct task_struct".
989+ *
990+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
991+ * are maintained outside that "struct task_struct". Therefore, ccs_security
992+ * != task_struct . This keeps KABI for distributor's prebuilt kernels but
993+ * entails slow access.
994+ *
995+ * Memory for this structure is allocated when current thread tries to access
996+ * it. Therefore, if memory allocation failed, current thread will be killed by
997+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
998+ */
999+struct ccs_security {
1000+ struct list_head list;
1001+ const struct task_struct *task;
1002+ struct ccs_domain_info *ccs_domain_info;
1003+ u32 ccs_flags;
1004+ struct rcu_head rcu;
1005+};
1006+
1007+#define CCS_TASK_SECURITY_HASH_BITS 12
1008+#define CCS_MAX_TASK_SECURITY_HASH (1u << CCS_TASK_SECURITY_HASH_BITS)
1009+extern struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
1010+
1011+struct ccs_security *ccs_find_task_security(const struct task_struct *task);
1012+
1013+/**
1014+ * ccs_current_security - Get "struct ccs_security" for current thread.
1015+ *
1016+ * Returns pointer to "struct ccs_security" for current thread.
1017+ */
1018+static inline struct ccs_security *ccs_current_security(void)
1019+{
1020+ return ccs_find_task_security(current);
1021+}
1022+
1023+/**
1024+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
1025+ *
1026+ * @task: Pointer to "struct task_struct".
1027+ *
1028+ * Returns pointer to "struct ccs_security" for specified thread.
1029+ */
1030+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
1031+{
1032+ struct ccs_domain_info *domain;
1033+ rcu_read_lock();
1034+ domain = ccs_find_task_security(task)->ccs_domain_info;
1035+ rcu_read_unlock();
1036+ return domain;
1037+}
1038+
1039+/**
1040+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
1041+ *
1042+ * Returns pointer to "struct ccs_domain_info" for current thread.
1043+ */
1044+static inline struct ccs_domain_info *ccs_current_domain(void)
1045+{
1046+ return ccs_find_task_security(current)->ccs_domain_info;
1047+}
1048+
1049+/**
1050+ * ccs_task_flags - Get flags for specified thread.
1051+ *
1052+ * @task: Pointer to "struct task_struct".
1053+ *
1054+ * Returns flags for specified thread.
1055+ */
1056+static inline u32 ccs_task_flags(struct task_struct *task)
1057+{
1058+ u32 ccs_flags;
1059+ rcu_read_lock();
1060+ ccs_flags = ccs_find_task_security(task)->ccs_flags;
1061+ rcu_read_unlock();
1062+ return ccs_flags;
1063+}
1064+
1065+/**
1066+ * ccs_current_flags - Get flags for current thread.
1067+ *
1068+ * Returns flags for current thread.
1069+ */
1070+static inline u32 ccs_current_flags(void)
1071+{
1072+ return ccs_find_task_security(current)->ccs_flags;
1073+}
1074+
1075+#else
1076+
1077+/*
1078+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
1079+ * are maintained inside that "struct task_struct". Therefore, ccs_security ==
1080+ * task_struct . This allows fast access but breaks KABI checks for
1081+ * distributor's prebuilt kernels due to changes in "struct task_struct".
1082+ */
1083+#define ccs_security task_struct
1084+
1085+/**
1086+ * ccs_find_task_security - Find "struct ccs_security" for given task.
1087+ *
1088+ * @task: Pointer to "struct task_struct".
1089+ *
1090+ * Returns pointer to "struct ccs_security".
1091+ */
1092+static inline struct ccs_security *ccs_find_task_security(struct task_struct *
1093+ task)
1094+{
1095+ return task;
1096+}
1097+
1098+/**
1099+ * ccs_current_security - Get "struct ccs_security" for current thread.
1100+ *
1101+ * Returns pointer to "struct ccs_security" for current thread.
1102+ */
1103+static inline struct ccs_security *ccs_current_security(void)
1104+{
1105+ return ccs_find_task_security(current);
1106+}
1107+
1108+/**
1109+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
1110+ *
1111+ * @task: Pointer to "struct task_struct".
1112+ *
1113+ * Returns pointer to "struct ccs_security" for specified thread.
1114+ */
1115+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
1116+{
1117+ struct ccs_domain_info *domain = task->ccs_domain_info;
1118+ return domain ? domain : &ccs_kernel_domain;
1119+}
1120+
1121+/**
1122+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
1123+ *
1124+ * Returns pointer to "struct ccs_domain_info" for current thread.
1125+ *
1126+ * If current thread does not belong to a domain (which is true for initial
1127+ * init_task in order to hide ccs_kernel_domain from this module),
1128+ * current thread enters into ccs_kernel_domain.
1129+ */
1130+static inline struct ccs_domain_info *ccs_current_domain(void)
1131+{
1132+ struct task_struct *task = current;
1133+ if (!task->ccs_domain_info)
1134+ task->ccs_domain_info = &ccs_kernel_domain;
1135+ return task->ccs_domain_info;
1136+}
1137+
1138+/**
1139+ * ccs_task_flags - Get flags for specified thread.
1140+ *
1141+ * @task: Pointer to "struct task_struct".
1142+ *
1143+ * Returns flags for specified thread.
1144+ */
1145+static inline u32 ccs_task_flags(struct task_struct *task)
1146+{
1147+ return ccs_find_task_security(task)->ccs_flags;
1148+}
1149+
1150+/**
1151+ * ccs_current_flags - Get flags for current thread.
1152+ *
1153+ * Returns flags for current thread.
1154+ */
1155+static inline u32 ccs_current_flags(void)
1156+{
1157+ return ccs_find_task_security(current)->ccs_flags;
1158+}
1159+
1160+#endif
1161+
1162+#endif
--- trunk/caitsith-patch/security/caitsith/policy_io.c (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/policy_io.c (revision 2)
@@ -0,0 +1,4401 @@
1+/*
2+ * security/caitsith/policy_io.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/***** SECTION1: Constants definition *****/
12+
13+/* Define this to enable debug mode. */
14+/* #define DEBUG_CONDITION */
15+
16+#ifdef DEBUG_CONDITION
17+#define dprintk printk
18+#else
19+#define dprintk(...) do { } while (0)
20+#endif
21+
22+/* String table for operation. */
23+static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX] = {
24+ [CCS_MAC_EXECUTE] = "execute",
25+ [CCS_MAC_READ] = "read",
26+ [CCS_MAC_WRITE] = "write",
27+ [CCS_MAC_APPEND] = "append",
28+ [CCS_MAC_CREATE] = "create",
29+ [CCS_MAC_UNLINK] = "unlink",
30+#ifdef CONFIG_CCSECURITY_GETATTR
31+ [CCS_MAC_GETATTR] = "getattr",
32+#endif
33+ [CCS_MAC_MKDIR] = "mkdir",
34+ [CCS_MAC_RMDIR] = "rmdir",
35+ [CCS_MAC_MKFIFO] = "mkfifo",
36+ [CCS_MAC_MKSOCK] = "mksock",
37+ [CCS_MAC_TRUNCATE] = "truncate",
38+ [CCS_MAC_SYMLINK] = "symlink",
39+ [CCS_MAC_MKBLOCK] = "mkblock",
40+ [CCS_MAC_MKCHAR] = "mkchar",
41+ [CCS_MAC_LINK] = "link",
42+ [CCS_MAC_RENAME] = "rename",
43+ [CCS_MAC_CHMOD] = "chmod",
44+ [CCS_MAC_CHOWN] = "chown",
45+ [CCS_MAC_CHGRP] = "chgrp",
46+ [CCS_MAC_IOCTL] = "ioctl",
47+ [CCS_MAC_CHROOT] = "chroot",
48+ [CCS_MAC_MOUNT] = "mount",
49+ [CCS_MAC_UMOUNT] = "unmount",
50+ [CCS_MAC_PIVOT_ROOT] = "pivot_root",
51+#ifdef CONFIG_CCSECURITY_NETWORK
52+ [CCS_MAC_INET_STREAM_BIND] = "inet_stream_bind",
53+ [CCS_MAC_INET_STREAM_LISTEN] = "inet_stream_listen",
54+ [CCS_MAC_INET_STREAM_CONNECT] = "inet_stream_connect",
55+ [CCS_MAC_INET_STREAM_ACCEPT] = "inet_stream_accept",
56+ [CCS_MAC_INET_DGRAM_BIND] = "inet_dgram_bind",
57+ [CCS_MAC_INET_DGRAM_SEND] = "inet_dgram_send",
58+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
59+ [CCS_MAC_INET_DGRAM_RECV] = "inet_dgram_recv",
60+#endif
61+ [CCS_MAC_INET_RAW_BIND] = "inet_raw_bind",
62+ [CCS_MAC_INET_RAW_SEND] = "inet_raw_send",
63+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
64+ [CCS_MAC_INET_RAW_RECV] = "inet_raw_recv",
65+#endif
66+ [CCS_MAC_UNIX_STREAM_BIND] = "unix_stream_bind",
67+ [CCS_MAC_UNIX_STREAM_LISTEN] = "unix_stream_listen",
68+ [CCS_MAC_UNIX_STREAM_CONNECT] = "unix_stream_connect",
69+ [CCS_MAC_UNIX_STREAM_ACCEPT] = "unix_stream_accept",
70+ [CCS_MAC_UNIX_DGRAM_BIND] = "unix_dgram_bind",
71+ [CCS_MAC_UNIX_DGRAM_SEND] = "unix_dgram_send",
72+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
73+ [CCS_MAC_UNIX_DGRAM_RECV] = "unix_dgram_recv",
74+#endif
75+ [CCS_MAC_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
76+ [CCS_MAC_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
77+ [CCS_MAC_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
78+ [CCS_MAC_UNIX_SEQPACKET_ACCEPT] = "unix_seqpacket_accept",
79+#endif
80+#ifdef CONFIG_CCSECURITY_ENVIRON
81+ [CCS_MAC_ENVIRON] = "environ",
82+#endif
83+#ifdef CONFIG_CCSECURITY_PTRACE
84+ [CCS_MAC_PTRACE] = "ptrace",
85+#endif
86+#ifdef CONFIG_CCSECURITY_SIGNAL
87+ [CCS_MAC_SIGNAL] = "signal",
88+#endif
89+ [CCS_MAC_MODIFY_POLICY] = "modify_policy",
90+#ifdef CONFIG_CCSECURITY_CAPABILITY
91+ [CCS_MAC_USE_NETLINK_SOCKET] = "use_netlink_socket",
92+ [CCS_MAC_USE_PACKET_SOCKET] = "use_packet_socket",
93+ [CCS_MAC_USE_REBOOT] = "use_reboot",
94+ [CCS_MAC_USE_VHANGUP] = "use_vhangup",
95+ [CCS_MAC_SET_TIME] = "set_time",
96+ [CCS_MAC_SET_PRIORITY] = "set_priority",
97+ [CCS_MAC_SET_HOSTNAME] = "set_hostname",
98+ [CCS_MAC_USE_KERNEL_MODULE] = "use_kernel_module",
99+ [CCS_MAC_USE_NEW_KERNEL] = "use_new_kernel",
100+#endif
101+#ifdef CONFIG_CCSECURITY_AUTO_DOMAIN_TRANSITION
102+ [CCS_MAC_AUTO_DOMAIN_TRANSITION] = "auto_domain_transition",
103+#endif
104+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
105+ [CCS_MAC_MANUAL_DOMAIN_TRANSITION] = "manual_domain_transition",
106+#endif
107+};
108+
109+/* String table for conditions. */
110+static const char *const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
111+ [CCS_SELF_UID] = "uid",
112+ [CCS_SELF_EUID] = "euid",
113+ [CCS_SELF_SUID] = "suid",
114+ [CCS_SELF_FSUID] = "fsuid",
115+ [CCS_SELF_GID] = "gid",
116+ [CCS_SELF_EGID] = "egid",
117+ [CCS_SELF_SGID] = "sgid",
118+ [CCS_SELF_FSGID] = "fsgid",
119+ [CCS_SELF_PID] = "pid",
120+ [CCS_SELF_PPID] = "ppid",
121+ [CCS_TASK_TYPE] = "type",
122+ [CCS_SELF_DOMAIN] = "domain",
123+ [CCS_SELF_EXE] = "exe",
124+ [CCS_EXEC_ARGC] = "argc",
125+ [CCS_EXEC_ENVC] = "envc",
126+ [CCS_OBJ_IS_SOCKET] = "socket",
127+ [CCS_OBJ_IS_SYMLINK] = "symlink",
128+ [CCS_OBJ_IS_FILE] = "file",
129+ [CCS_OBJ_IS_BLOCK_DEV] = "block",
130+ [CCS_OBJ_IS_DIRECTORY] = "directory",
131+ [CCS_OBJ_IS_CHAR_DEV] = "char",
132+ [CCS_OBJ_IS_FIFO] = "fifo",
133+ [CCS_MODE_SETUID] = "setuid",
134+ [CCS_MODE_SETGID] = "setgid",
135+ [CCS_MODE_STICKY] = "sticky",
136+ [CCS_MODE_OWNER_READ] = "owner_read",
137+ [CCS_MODE_OWNER_WRITE] = "owner_write",
138+ [CCS_MODE_OWNER_EXECUTE] = "owner_execute",
139+ [CCS_MODE_GROUP_READ] = "group_read",
140+ [CCS_MODE_GROUP_WRITE] = "group_write",
141+ [CCS_MODE_GROUP_EXECUTE] = "group_execute",
142+ [CCS_MODE_OTHERS_READ] = "others_read",
143+ [CCS_MODE_OTHERS_WRITE] = "others_write",
144+ [CCS_MODE_OTHERS_EXECUTE] = "others_execute",
145+ [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
146+ [CCS_HANDLER_PATH] = "handler",
147+ [CCS_TRANSIT_DOMAIN] = "transition",
148+};
149+
150+/* String table for file attributes. */
151+static const char *const ccs_path_attribute[CCS_MAX_PATH_ATTRIBUTE] = {
152+ [CCS_PATH_ATTRIBUTE_UID] = "uid",
153+ [CCS_PATH_ATTRIBUTE_GID] = "gid",
154+ [CCS_PATH_ATTRIBUTE_INO] = "ino",
155+ [CCS_PATH_ATTRIBUTE_MAJOR] = "major",
156+ [CCS_PATH_ATTRIBUTE_MINOR] = "minor",
157+ [CCS_PATH_ATTRIBUTE_PERM] = "perm",
158+ [CCS_PATH_ATTRIBUTE_TYPE] = "type",
159+ [CCS_PATH_ATTRIBUTE_DEV_MAJOR] = "dev_major",
160+ [CCS_PATH_ATTRIBUTE_DEV_MINOR] = "dev_minor",
161+ [CCS_PATH_ATTRIBUTE_FSMAGIC] = "fsmagic",
162+};
163+
164+/* String table for grouping keywords. */
165+static const char * const ccs_group_name[CCS_MAX_GROUP] = {
166+ [CCS_STRING_GROUP] = "string_group",
167+ [CCS_NUMBER_GROUP] = "number_group",
168+#ifdef CONFIG_CCSECURITY_NETWORK
169+ [CCS_IP_GROUP] = "ip_group",
170+#endif
171+};
172+
173+/* String table for stat info. */
174+static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
175+ [CCS_MEMORY_POLICY] = "policy",
176+ [CCS_MEMORY_AUDIT] = "audit",
177+ [CCS_MEMORY_QUERY] = "query",
178+};
179+
180+/***** SECTION2: Structure definition *****/
181+
182+struct iattr;
183+
184+/* Structure for query. */
185+struct ccs_query {
186+ struct list_head list;
187+ struct ccs_acl_info *acl;
188+ char *query;
189+ size_t query_len;
190+ unsigned int serial;
191+ u8 timer;
192+ u8 answer;
193+ u8 retry;
194+};
195+
196+/* Structure for audit log. */
197+struct ccs_log {
198+ struct list_head list;
199+ char *log;
200+ int size;
201+ enum ccs_matching_result result;
202+};
203+
204+/* Structure for holding single condition component. */
205+struct ccs_cond_tmp {
206+ u8 left;
207+ u8 right;
208+ bool is_not;
209+ u8 radix;
210+ struct ccs_group *group;
211+ const struct ccs_path_info *path;
212+ struct in6_addr ipv6[2];
213+ unsigned long value[2];
214+ unsigned long argv;
215+ const struct ccs_path_info *envp;
216+};
217+
218+/***** SECTION3: Prototype definition section *****/
219+
220+static bool ccs_correct_domain(const unsigned char *domainname);
221+static bool ccs_correct_word(const char *string);
222+static bool ccs_flush(struct ccs_io_buffer *head);
223+static bool ccs_print_condition(struct ccs_io_buffer *head,
224+ const struct ccs_condition *cond);
225+static bool ccs_memory_ok(const void *ptr, const unsigned int size);
226+static bool ccs_read_acl(struct ccs_io_buffer *head,
227+ const struct ccs_acl_info *acl);
228+static bool ccs_read_group(struct ccs_io_buffer *head);
229+static bool ccs_select_acl(struct ccs_io_buffer *head, const char *data);
230+static bool ccs_set_lf(struct ccs_io_buffer *head);
231+static bool ccs_str_starts(char **src, const char *find);
232+static char *ccs_init_log(struct ccs_request_info *r);
233+static char *ccs_print_bprm(struct linux_binprm *bprm,
234+ struct ccs_page_dump *dump);
235+static char *ccs_print_trailer(struct ccs_request_info *r);
236+static char *ccs_read_token(struct ccs_io_buffer *head);
237+static const char *ccs_yesno(const unsigned int value);
238+static const struct ccs_path_info *ccs_get_dqword(char *start);
239+static const struct ccs_path_info *ccs_get_name(const char *name);
240+static int __init ccs_init_module(void);
241+static int ccs_open(struct inode *inode, struct file *file);
242+static int ccs_parse_policy(struct ccs_io_buffer *head, char *line);
243+static int ccs_release(struct inode *inode, struct file *file);
244+static int ccs_supervisor(struct ccs_request_info *r);
245+static int ccs_update_group(struct ccs_io_buffer *head,
246+ const enum ccs_group_id type);
247+static int ccs_write_answer(struct ccs_io_buffer *head);
248+static int ccs_write_audit_quota(char *data);
249+static int ccs_write_memory_quota(char *data);
250+static int ccs_write_pid(struct ccs_io_buffer *head);
251+static int ccs_write_policy(struct ccs_io_buffer *head);
252+static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
253+ loff_t *ppos);
254+static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
255+ loff_t *ppos);
256+static ssize_t ccs_write(struct file *file, const char __user *buf,
257+ size_t count, loff_t *ppos);
258+static struct ccs_condition *ccs_get_condition(struct ccs_io_buffer *head);
259+static struct ccs_domain_info *ccs_find_domain(const char *domainname);
260+static struct ccs_acl_info *ccs_find_acl_by_qid(unsigned int serial);
261+static struct ccs_group *ccs_get_group(struct ccs_io_buffer *head,
262+ const enum ccs_group_id idx);
263+static enum ccs_value_type ccs_parse_ulong(unsigned long *result, char **str);
264+static unsigned int ccs_poll(struct file *file, poll_table *wait);
265+static void __init ccs_create_entry(const char *name, const umode_t mode,
266+ struct proc_dir_entry *parent,
267+ const u8 key);
268+static void __init ccs_load_builtin_policy(void);
269+static void __init ccs_policy_io_init(void);
270+static void __init ccs_proc_init(void);
271+static void ccs_check_profile(void);
272+static void ccs_convert_time(time_t time, struct ccs_time *stamp);
273+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
274+ __printf(2, 3);
275+static void ccs_normalize_line(unsigned char *buffer);
276+static void ccs_read_log(struct ccs_io_buffer *head);
277+static void ccs_read_pid(struct ccs_io_buffer *head);
278+static void ccs_read_policy(struct ccs_io_buffer *head);
279+static void ccs_read_query(struct ccs_io_buffer *head);
280+static void *ccs_commit_ok(void *data, const unsigned int size);
281+static bool ccs_read_quota(struct ccs_io_buffer *head);
282+static void ccs_read_stat(struct ccs_io_buffer *head);
283+static void ccs_read_version(struct ccs_io_buffer *head);
284+static void ccs_set_space(struct ccs_io_buffer *head);
285+static void ccs_set_string(struct ccs_io_buffer *head, const char *string);
286+static void ccs_update_stat(const u8 index);
287+static void ccs_write_log(struct ccs_request_info *r);
288+
289+#ifdef CONFIG_CCSECURITY_NETWORK
290+static enum ccs_ipaddr_type ccs_parse_ipaddr(char *address,
291+ struct in6_addr ipv6[2]);
292+static void ccs_print_ipv4(struct ccs_io_buffer *head, const u32 *ip);
293+static void ccs_print_ipv6(struct ccs_io_buffer *head,
294+ const struct in6_addr *ip);
295+static void ccs_print_ip(struct ccs_io_buffer *head,
296+ struct ccs_ip_group *member);
297+#endif
298+
299+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
300+static ssize_t ccs_write_self(struct file *file, const char __user *buf,
301+ size_t count, loff_t *ppos);
302+#endif
303+
304+/***** SECTION4: Standalone functions section *****/
305+
306+/**
307+ * ccs_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
308+ *
309+ * @time: Seconds since 1970/01/01 00:00:00.
310+ * @stamp: Pointer to "struct ccs_time".
311+ *
312+ * Returns nothing.
313+ *
314+ * This function does not handle Y2038 problem.
315+ */
316+static void ccs_convert_time(time_t time, struct ccs_time *stamp)
317+{
318+ static const u16 ccs_eom[2][12] = {
319+ { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
320+ { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
321+ };
322+ u16 y;
323+ u8 m;
324+ bool r;
325+ stamp->sec = time % 60;
326+ time /= 60;
327+ stamp->min = time % 60;
328+ time /= 60;
329+ stamp->hour = time % 24;
330+ time /= 24;
331+ for (y = 1970; ; y++) {
332+ const unsigned short days = (y & 3) ? 365 : 366;
333+ if (time < days)
334+ break;
335+ time -= days;
336+ }
337+ r = (y & 3) == 0;
338+ for (m = 0; m < 11 && time >= ccs_eom[r][m]; m++);
339+ if (m)
340+ time -= ccs_eom[r][m - 1];
341+ stamp->year = y;
342+ stamp->month = ++m;
343+ stamp->day = ++time;
344+}
345+
346+#ifdef CONFIG_CCSECURITY_NETWORK
347+
348+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
349+
350+/*
351+ * Routines for printing IPv4 or IPv6 address.
352+ * These are copied from include/linux/kernel.h include/net/ipv6.h
353+ * include/net/addrconf.h lib/hexdump.c lib/vsprintf.c and simplified.
354+ */
355+static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
356+{
357+ return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
358+}
359+
360+static char *ip4_string(char *p, const u8 *addr)
361+{
362+ /*
363+ * Since this function is called outside vsnprintf(), I can use
364+ * sprintf() here.
365+ */
366+ return p +
367+ sprintf(p, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
368+}
369+
370+static char *ip6_compressed_string(char *p, const char *addr)
371+{
372+ int i, j, range;
373+ unsigned char zerolength[8];
374+ int longest = 1;
375+ int colonpos = -1;
376+ u16 word;
377+ u8 hi, lo;
378+ bool needcolon = false;
379+ bool useIPv4;
380+ struct in6_addr in6;
381+
382+ memcpy(&in6, addr, sizeof(struct in6_addr));
383+
384+ useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
385+
386+ memset(zerolength, 0, sizeof(zerolength));
387+
388+ if (useIPv4)
389+ range = 6;
390+ else
391+ range = 8;
392+
393+ /* find position of longest 0 run */
394+ for (i = 0; i < range; i++) {
395+ for (j = i; j < range; j++) {
396+ if (in6.s6_addr16[j] != 0)
397+ break;
398+ zerolength[i]++;
399+ }
400+ }
401+ for (i = 0; i < range; i++) {
402+ if (zerolength[i] > longest) {
403+ longest = zerolength[i];
404+ colonpos = i;
405+ }
406+ }
407+ if (longest == 1) /* don't compress a single 0 */
408+ colonpos = -1;
409+
410+ /* emit address */
411+ for (i = 0; i < range; i++) {
412+ if (i == colonpos) {
413+ if (needcolon || i == 0)
414+ *p++ = ':';
415+ *p++ = ':';
416+ needcolon = false;
417+ i += longest - 1;
418+ continue;
419+ }
420+ if (needcolon) {
421+ *p++ = ':';
422+ needcolon = false;
423+ }
424+ /* hex u16 without leading 0s */
425+ word = ntohs(in6.s6_addr16[i]);
426+ hi = word >> 8;
427+ lo = word & 0xff;
428+ if (hi) {
429+ if (hi > 0x0f)
430+ p = pack_hex_byte(p, hi);
431+ else
432+ *p++ = hex_asc_lo(hi);
433+ p = pack_hex_byte(p, lo);
434+ } else if (lo > 0x0f)
435+ p = pack_hex_byte(p, lo);
436+ else
437+ *p++ = hex_asc_lo(lo);
438+ needcolon = true;
439+ }
440+
441+ if (useIPv4) {
442+ if (needcolon)
443+ *p++ = ':';
444+ p = ip4_string(p, &in6.s6_addr[12]);
445+ }
446+ *p = '\0';
447+
448+ return p;
449+}
450+#endif
451+
452+/**
453+ * ccs_print_ipv4 - Print an IPv4 address.
454+ *
455+ * @head: Pointer to "struct ccs_io_buffer".
456+ * @ip: Pointer to "u32" in network byte order.
457+ *
458+ * Returns nothing.
459+ */
460+static void ccs_print_ipv4(struct ccs_io_buffer *head, const u32 *ip)
461+{
462+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
463+ ccs_io_printf(head, "%pI4", ip);
464+#else
465+ char addr[sizeof("255.255.255.255")];
466+ ip4_string(addr, (const u8 *) ip);
467+ ccs_io_printf(head, "%s", addr);
468+#endif
469+}
470+
471+/**
472+ * ccs_print_ipv6 - Print an IPv6 address.
473+ *
474+ * @head: Pointer to "struct ccs_io_buffer".
475+ * @ip: Pointer to "struct in6_addr".
476+ *
477+ * Returns nothing.
478+ */
479+static void ccs_print_ipv6(struct ccs_io_buffer *head,
480+ const struct in6_addr *ip)
481+{
482+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
483+ ccs_io_printf(head, "%pI6c", ip);
484+#else
485+ char addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:"
486+ "255.255.255.255")];
487+ ip6_compressed_string(addr, (const u8 *) ip);
488+ ccs_io_printf(head, "%s", addr);
489+#endif
490+}
491+
492+/**
493+ * ccs_print_ip - Print an IP address.
494+ *
495+ * @head: Pointer to "struct ccs_io_buffer".
496+ * @member: Pointer to "struct ccs_ip_group".
497+ *
498+ * Returns nothing.
499+ */
500+static void ccs_print_ip(struct ccs_io_buffer *head,
501+ struct ccs_ip_group *member)
502+{
503+ u8 i;
504+ for (i = 0; i < 2; i++) {
505+ if (member->is_ipv6)
506+ ccs_print_ipv6(head, &member->ip[i]);
507+ else
508+ ccs_print_ipv4(head, (const u32 *) &member->ip[i]);
509+ if (i)
510+ break;
511+ if (!memcmp(&member->ip[0], &member->ip[1], 16))
512+ break;
513+ ccs_set_string(head, "-");
514+ }
515+}
516+
517+#endif
518+
519+/**
520+ * ccs_get_sarg - Get attribute name of CCS_SARG argument.
521+ *
522+ * @type: One of values in "enum ccs_mac_index".
523+ * @index: Index to return.
524+ *
525+ * Returns attribute name.
526+ */
527+static const char *ccs_get_sarg(const enum ccs_mac_index type, const u8 index)
528+{
529+ switch (type) {
530+ case CCS_MAC_LINK:
531+ case CCS_MAC_RENAME:
532+ if (index == 0)
533+ return "old_path";
534+ if (index == 1)
535+ return "new_path";
536+ break;
537+ case CCS_MAC_MOUNT:
538+ if (index == 0)
539+ return "source";
540+ if (index == 1)
541+ return "target";
542+ if (index == 2)
543+ return "fstype";
544+ if (index == 3)
545+ return "data";
546+ break;
547+ case CCS_MAC_PIVOT_ROOT:
548+ if (index == 0)
549+ return "new_root";
550+ if (index == 1)
551+ return "put_old";
552+ break;
553+#ifdef CONFIG_CCSECURITY_ENVIRON
554+ case CCS_MAC_ENVIRON:
555+ if (index == 2)
556+ return "name";
557+ if (index == 3)
558+ return "value";
559+ /* fall through */
560+#endif
561+ case CCS_MAC_EXECUTE:
562+ if (index == 0)
563+ return "path";
564+ if (index == 1)
565+ return "exec";
566+ break;
567+ case CCS_MAC_SYMLINK:
568+ if (index == 0)
569+ return "path";
570+ if (index == 1)
571+ return "target";
572+ break;
573+ case CCS_MAC_READ:
574+ case CCS_MAC_WRITE:
575+ case CCS_MAC_APPEND:
576+ case CCS_MAC_UNLINK:
577+#ifdef CONFIG_CCSECURITY_GETATTR
578+ case CCS_MAC_GETATTR:
579+#endif
580+ case CCS_MAC_RMDIR:
581+ case CCS_MAC_TRUNCATE:
582+ case CCS_MAC_CHROOT:
583+ case CCS_MAC_CHMOD:
584+ case CCS_MAC_CHOWN:
585+ case CCS_MAC_CHGRP:
586+ case CCS_MAC_IOCTL:
587+ case CCS_MAC_MKDIR:
588+ case CCS_MAC_CREATE:
589+ case CCS_MAC_MKFIFO:
590+ case CCS_MAC_MKSOCK:
591+ case CCS_MAC_MKBLOCK:
592+ case CCS_MAC_MKCHAR:
593+ case CCS_MAC_UMOUNT:
594+ if (index == 0)
595+ return "path";
596+ break;
597+ case CCS_MAC_MODIFY_POLICY:
598+#ifdef CONFIG_CCSECURITY_CAPABILITY
599+ case CCS_MAC_USE_NETLINK_SOCKET:
600+ case CCS_MAC_USE_PACKET_SOCKET:
601+ case CCS_MAC_USE_REBOOT:
602+ case CCS_MAC_USE_VHANGUP:
603+ case CCS_MAC_SET_TIME:
604+ case CCS_MAC_SET_PRIORITY:
605+ case CCS_MAC_SET_HOSTNAME:
606+ case CCS_MAC_USE_KERNEL_MODULE:
607+ case CCS_MAC_USE_NEW_KERNEL:
608+#endif
609+ break;
610+#ifdef CONFIG_CCSECURITY_NETWORK
611+ case CCS_MAC_INET_STREAM_BIND:
612+ case CCS_MAC_INET_STREAM_LISTEN:
613+ case CCS_MAC_INET_STREAM_CONNECT:
614+ case CCS_MAC_INET_STREAM_ACCEPT:
615+ case CCS_MAC_INET_DGRAM_BIND:
616+ case CCS_MAC_INET_DGRAM_SEND:
617+ case CCS_MAC_INET_DGRAM_RECV:
618+ case CCS_MAC_INET_RAW_BIND:
619+ case CCS_MAC_INET_RAW_SEND:
620+ case CCS_MAC_INET_RAW_RECV:
621+ if (index == 0)
622+ return "ip";
623+ break;
624+ case CCS_MAC_UNIX_STREAM_BIND:
625+ case CCS_MAC_UNIX_STREAM_LISTEN:
626+ case CCS_MAC_UNIX_STREAM_CONNECT:
627+ case CCS_MAC_UNIX_STREAM_ACCEPT:
628+ case CCS_MAC_UNIX_DGRAM_BIND:
629+ case CCS_MAC_UNIX_DGRAM_SEND:
630+ case CCS_MAC_UNIX_DGRAM_RECV:
631+ case CCS_MAC_UNIX_SEQPACKET_BIND:
632+ case CCS_MAC_UNIX_SEQPACKET_LISTEN:
633+ case CCS_MAC_UNIX_SEQPACKET_CONNECT:
634+ case CCS_MAC_UNIX_SEQPACKET_ACCEPT:
635+ if (index == 0)
636+ return "addr";
637+ break;
638+#endif
639+#ifdef CONFIG_CCSECURITY_PTRACE
640+ case CCS_MAC_PTRACE:
641+ if (index == 0)
642+ return "domain";
643+ break;
644+#endif
645+ default:
646+ break;
647+ }
648+ return "unknown"; /* This should not happen. */
649+}
650+
651+/**
652+ * ccs_get_narg - Get attribute name of CCS_NARG argument.
653+ *
654+ * @type: One of values in "enum ccs_mac_index".
655+ * @index: Index to return.
656+ *
657+ * Returns attribute name.
658+ */
659+static const char *ccs_get_narg(const enum ccs_mac_index type, const u8 index)
660+{
661+ switch (type) {
662+ case CCS_MAC_MOUNT:
663+ case CCS_MAC_UMOUNT:
664+ if (index == 0)
665+ return "flags";
666+ break;
667+ case CCS_MAC_CHMOD:
668+ if (index == 0)
669+ return "perm";
670+ break;
671+ case CCS_MAC_CHOWN:
672+ if (index == 0)
673+ return "uid";
674+ break;
675+ case CCS_MAC_CHGRP:
676+ if (index == 0)
677+ return "gid";
678+ break;
679+ case CCS_MAC_IOCTL:
680+ if (index == 0)
681+ return "cmd";
682+ break;
683+ case CCS_MAC_MKDIR:
684+ case CCS_MAC_CREATE:
685+ case CCS_MAC_MKFIFO:
686+ case CCS_MAC_MKSOCK:
687+ if (index == 0)
688+ return "perm";
689+ break;
690+ case CCS_MAC_MKBLOCK:
691+ case CCS_MAC_MKCHAR:
692+ if (index == 0)
693+ return "perm";
694+ if (index == 1)
695+ return "dev_major";
696+ if (index == 2)
697+ return "dev_minor";
698+ break;
699+#ifdef CONFIG_CCSECURITY_NETWORK
700+ case CCS_MAC_INET_STREAM_BIND:
701+ case CCS_MAC_INET_STREAM_LISTEN:
702+ case CCS_MAC_INET_STREAM_CONNECT:
703+ case CCS_MAC_INET_STREAM_ACCEPT:
704+ case CCS_MAC_INET_DGRAM_BIND:
705+ case CCS_MAC_INET_DGRAM_SEND:
706+ case CCS_MAC_INET_DGRAM_RECV:
707+ if (index == 0)
708+ return "port";
709+ break;
710+ case CCS_MAC_INET_RAW_BIND:
711+ case CCS_MAC_INET_RAW_SEND:
712+ case CCS_MAC_INET_RAW_RECV:
713+ if (index == 0)
714+ return "proto";
715+ break;
716+#endif
717+#ifdef CONFIG_CCSECURITY_PTRACE
718+ case CCS_MAC_PTRACE:
719+ if (index == 0)
720+ return "cmd";
721+ break;
722+#endif
723+#ifdef CONFIG_CCSECURITY_SIGNAL
724+ case CCS_MAC_SIGNAL:
725+ if (index == 0)
726+ return "cmd";
727+ break;
728+#endif
729+ default:
730+ break;
731+ }
732+ return "unknown"; /* This should not happen. */
733+}
734+
735+/***** SECTION5: Variables definition section *****/
736+
737+/* Lock for protecting policy. */
738+DEFINE_MUTEX(ccs_policy_lock);
739+
740+/* Has /sbin/init started? */
741+bool ccs_policy_loaded;
742+
743+/* List of "struct ccs_group". */
744+struct list_head ccs_group_list[CCS_MAX_GROUP];
745+/* Policy version. Currently only 20120401 is defined. */
746+static unsigned int ccs_policy_version = 20120401;
747+
748+/* List of "struct ccs_condition". */
749+LIST_HEAD(ccs_condition_list);
750+
751+/* Wait queue for kernel -> userspace notification. */
752+static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
753+/* Wait queue for userspace -> kernel notification. */
754+static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
755+
756+/* The list for "struct ccs_query". */
757+static LIST_HEAD(ccs_query_list);
758+
759+/* Lock for manipulating ccs_query_list. */
760+static DEFINE_SPINLOCK(ccs_query_list_lock);
761+
762+/* Number of "struct file" referring /proc/ccs/query interface. */
763+static atomic_t ccs_query_observers = ATOMIC_INIT(0);
764+
765+/* Wait queue for /proc/ccs/audit. */
766+static DECLARE_WAIT_QUEUE_HEAD(ccs_log_wait);
767+
768+/* The list for "struct ccs_log". */
769+static LIST_HEAD(ccs_log);
770+
771+/* Lock for "struct list_head ccs_log". */
772+static DEFINE_SPINLOCK(ccs_log_lock);
773+
774+/* Length of "stuct list_head ccs_log". */
775+static unsigned int ccs_log_count[CCS_MAX_MATCHING];
776+/* Quota for audit logs. */
777+static unsigned int ccs_log_quota[CCS_MAX_LOG_QUOTA][CCS_MAX_MATCHING];
778+
779+/* Memoy currently used by policy/audit log/query. */
780+unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
781+
782+/* Memory quota for "policy"/"audit log"/"query". */
783+static unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
784+
785+/* The list for "struct ccs_name". */
786+struct list_head ccs_name_list[CCS_MAX_HASH];
787+
788+/* Timestamp counter for last updated. */
789+static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
790+
791+/* Counter for number of updates. */
792+static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
793+
794+/* Operations for /proc/ccs/self_domain interface. */
795+static const struct file_operations ccs_self_operations = {
796+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
797+ .write = ccs_write_self,
798+#endif
799+ .read = ccs_read_self,
800+};
801+
802+/* Operations for /proc/ccs/ interface. */
803+static const struct file_operations ccs_operations = {
804+ .open = ccs_open,
805+ .release = ccs_release,
806+ .poll = ccs_poll,
807+ .read = ccs_read,
808+ .write = ccs_write,
809+};
810+
811+/***** SECTION6: Dependent functions section *****/
812+
813+/**
814+ * list_for_each_cookie - iterate over a list with cookie.
815+ *
816+ * @pos: Pointer to "struct list_head".
817+ * @head: Pointer to "struct list_head".
818+ */
819+#define list_for_each_cookie(pos, head) \
820+ for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
821+ pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
822+
823+/**
824+ * ccs_warn_oom - Print out of memory warning message.
825+ *
826+ * @function: Function's name.
827+ *
828+ * Returns nothing.
829+ */
830+void ccs_warn_oom(const char *function)
831+{
832+ /* Reduce error messages. */
833+ static pid_t ccs_last_pid;
834+ const pid_t pid = current->pid;
835+ if (ccs_last_pid != pid) {
836+ printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
837+ function);
838+ ccs_last_pid = pid;
839+ }
840+ if (!ccs_policy_loaded)
841+ panic("MAC Initialization failed.\n");
842+}
843+
844+/**
845+ * ccs_memory_ok - Check memory quota.
846+ *
847+ * @ptr: Pointer to allocated memory. Maybe NULL.
848+ * @size: Size in byte. Not used if @ptr is NULL.
849+ *
850+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
851+ *
852+ * Caller holds ccs_policy_lock mutex.
853+ */
854+static bool ccs_memory_ok(const void *ptr, const unsigned int size)
855+{
856+ if (ptr) {
857+ const size_t s = ccs_round2(size);
858+ ccs_memory_used[CCS_MEMORY_POLICY] += s;
859+ if (!ccs_memory_quota[CCS_MEMORY_POLICY] ||
860+ ccs_memory_used[CCS_MEMORY_POLICY] <=
861+ ccs_memory_quota[CCS_MEMORY_POLICY])
862+ return true;
863+ ccs_memory_used[CCS_MEMORY_POLICY] -= s;
864+ }
865+ ccs_warn_oom(__func__);
866+ return false;
867+}
868+
869+/**
870+ * ccs_get_name - Allocate memory for string data.
871+ *
872+ * @name: The string to store into the permernent memory. Maybe NULL.
873+ *
874+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
875+ */
876+static const struct ccs_path_info *ccs_get_name(const char *name)
877+{
878+ struct ccs_name *ptr;
879+ unsigned int hash;
880+ int len;
881+ int allocated_len;
882+ struct list_head *head;
883+
884+ if (!name)
885+ return NULL;
886+ len = strlen(name) + 1;
887+ hash = full_name_hash((const unsigned char *) name, len - 1);
888+ head = &ccs_name_list[hash_long(hash, CCS_HASH_BITS)];
889+ if (mutex_lock_interruptible(&ccs_policy_lock))
890+ return NULL;
891+ list_for_each_entry(ptr, head, head.list) {
892+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
893+ atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
894+ continue;
895+ atomic_inc(&ptr->head.users);
896+ goto out;
897+ }
898+ allocated_len = sizeof(*ptr) + len;
899+ ptr = kzalloc(allocated_len, GFP_NOFS);
900+ if (ccs_memory_ok(ptr, allocated_len)) {
901+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
902+ memmove((char *) ptr->entry.name, name, len);
903+ atomic_set(&ptr->head.users, 1);
904+ ccs_fill_path_info(&ptr->entry);
905+ ptr->size = allocated_len;
906+ list_add_tail(&ptr->head.list, head);
907+ } else {
908+ kfree(ptr);
909+ ptr = NULL;
910+ }
911+out:
912+ mutex_unlock(&ccs_policy_lock);
913+ return ptr ? &ptr->entry : NULL;
914+}
915+
916+/**
917+ * ccs_read_token - Read a word from a line.
918+ *
919+ * @head: Pointer to "struct ccs_io_buffer".
920+ *
921+ * Returns a word on success, "" otherwise.
922+ *
923+ * To allow the caller to skip NULL check, this function returns "" rather than
924+ * NULL if there is no more words to read.
925+ */
926+static char *ccs_read_token(struct ccs_io_buffer *head)
927+{
928+ char *pos = head->w.data;
929+ char *del = strchr(pos, ' ');
930+ if (del)
931+ *del++ = '\0';
932+ else
933+ del = pos + strlen(pos);
934+ head->w.data = del;
935+ return pos;
936+}
937+
938+/**
939+ * ccs_correct_word - Check whether the given string follows the naming rules.
940+ *
941+ * @string: The string to check.
942+ *
943+ * Returns true if @string follows the naming rules, false otherwise.
944+ */
945+static bool ccs_correct_word(const char *string)
946+{
947+ const char *const start = string;
948+ u8 in_repetition = 0;
949+ if (!*string)
950+ goto out;
951+ while (*string) {
952+ unsigned char c = *string++;
953+ if (in_repetition && c == '/')
954+ goto out;
955+ if (c <= ' ' || c >= 127)
956+ goto out;
957+ if (c != '\\')
958+ continue;
959+ c = *string++;
960+ if (c >= '0' && c <= '3') {
961+ unsigned char d;
962+ unsigned char e;
963+ d = *string++;
964+ if (d < '0' || d > '7')
965+ goto out;
966+ e = *string++;
967+ if (e < '0' || e > '7')
968+ goto out;
969+ c = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
970+ if (c <= ' ' || c >= 127 || c == '\\')
971+ continue;
972+ goto out;
973+ }
974+ switch (c) {
975+ case '$': /* "\$" */
976+ case '+': /* "\+" */
977+ case '?': /* "\?" */
978+ case '*': /* "\*" */
979+ case '@': /* "\@" */
980+ case 'x': /* "\x" */
981+ case 'X': /* "\X" */
982+ case 'a': /* "\a" */
983+ case 'A': /* "\A" */
984+ case '-': /* "\-" */
985+ continue;
986+ case '{': /* "/\{" */
987+ if (string - 3 < start || *(string - 3) != '/')
988+ goto out;
989+ in_repetition = 1;
990+ continue;
991+ case '}': /* "\}/" */
992+ if (in_repetition != 1 || *string++ != '/')
993+ goto out;
994+ in_repetition = 0;
995+ continue;
996+ case '(': /* "/\(" */
997+ if (string - 3 < start || *(string - 3) != '/')
998+ goto out;
999+ in_repetition = 2;
1000+ continue;
1001+ case ')': /* "\)/" */
1002+ if (in_repetition != 2 || *string++ != '/')
1003+ goto out;
1004+ in_repetition = 0;
1005+ continue;
1006+ }
1007+ goto out;
1008+ }
1009+ if (in_repetition)
1010+ goto out;
1011+ return true;
1012+out:
1013+ return false;
1014+}
1015+
1016+/**
1017+ * ccs_commit_ok - Allocate memory and check memory quota.
1018+ *
1019+ * @data: Data to copy from.
1020+ * @size: Size in byte.
1021+ *
1022+ * Returns pointer to allocated memory on success, NULL otherwise.
1023+ * @data is zero-cleared on success.
1024+ *
1025+ * Caller holds ccs_policy_lock mutex.
1026+ */
1027+static void *ccs_commit_ok(void *data, const unsigned int size)
1028+{
1029+ void *ptr = kmalloc(size, GFP_NOFS);
1030+ if (ccs_memory_ok(ptr, size)) {
1031+ memmove(ptr, data, size);
1032+ memset(data, 0, size);
1033+ return ptr;
1034+ }
1035+ kfree(ptr);
1036+ return NULL;
1037+}
1038+
1039+/**
1040+ * ccs_get_group - Allocate memory for "struct ccs_string_group"/"struct ccs_number_group"/"struct ccs_ip_group".
1041+ *
1042+ * @head: Pointer to "struct ccs_io_buffer".
1043+ * @idx: Index number.
1044+ *
1045+ * Returns pointer to "struct ccs_group" on success, NULL otherwise.
1046+ */
1047+static struct ccs_group *ccs_get_group(struct ccs_io_buffer *head,
1048+ const enum ccs_group_id idx)
1049+{
1050+ struct ccs_group e = { };
1051+ struct ccs_group *group = NULL;
1052+ struct list_head *list;
1053+ const char *group_name = ccs_read_token(head);
1054+ bool found = false;
1055+ if (!ccs_correct_word(group_name) || idx >= CCS_MAX_GROUP)
1056+ return NULL;
1057+ e.group_name = ccs_get_name(group_name);
1058+ if (!e.group_name)
1059+ return NULL;
1060+ if (mutex_lock_interruptible(&ccs_policy_lock))
1061+ goto out;
1062+ list = &ccs_group_list[idx];
1063+ list_for_each_entry(group, list, head.list) {
1064+ if (e.group_name != group->group_name ||
1065+ atomic_read(&group->head.users) == CCS_GC_IN_PROGRESS)
1066+ continue;
1067+ atomic_inc(&group->head.users);
1068+ found = true;
1069+ break;
1070+ }
1071+ if (!found) {
1072+ struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
1073+ if (entry) {
1074+ INIT_LIST_HEAD(&entry->member_list);
1075+ atomic_set(&entry->head.users, 1);
1076+ list_add_tail_rcu(&entry->head.list, list);
1077+ group = entry;
1078+ found = true;
1079+ }
1080+ }
1081+ mutex_unlock(&ccs_policy_lock);
1082+out:
1083+ ccs_put_name(e.group_name);
1084+ return found ? group : NULL;
1085+}
1086+
1087+/**
1088+ * ccs_parse_ulong - Parse an "unsigned long" value.
1089+ *
1090+ * @result: Pointer to "unsigned long".
1091+ * @str: Pointer to string to parse.
1092+ *
1093+ * Returns one of values in "enum ccs_value_type".
1094+ *
1095+ * The @src is updated to point the first character after the value
1096+ * on success.
1097+ */
1098+static enum ccs_value_type ccs_parse_ulong(unsigned long *result, char **str)
1099+{
1100+ const char *cp = *str;
1101+ char *ep;
1102+ int base = 10;
1103+ if (*cp == '0') {
1104+ char c = *(cp + 1);
1105+ if (c == 'x' || c == 'X') {
1106+ base = 16;
1107+ cp += 2;
1108+ } else if (c >= '0' && c <= '7') {
1109+ base = 8;
1110+ cp++;
1111+ }
1112+ }
1113+ *result = simple_strtoul(cp, &ep, base);
1114+ if (cp == ep)
1115+ return CCS_VALUE_TYPE_INVALID;
1116+ *str = ep;
1117+ switch (base) {
1118+ case 16:
1119+ return CCS_VALUE_TYPE_HEXADECIMAL;
1120+ case 8:
1121+ return CCS_VALUE_TYPE_OCTAL;
1122+ default:
1123+ return CCS_VALUE_TYPE_DECIMAL;
1124+ }
1125+}
1126+
1127+/**
1128+ * ccs_get_dqword - ccs_get_name() for a quoted string.
1129+ *
1130+ * @start: String to parse.
1131+ *
1132+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
1133+ */
1134+static const struct ccs_path_info *ccs_get_dqword(char *start)
1135+{
1136+ char *cp = start + strlen(start) - 1;
1137+ if (cp == start || *start++ != '"' || *cp != '"')
1138+ return NULL;
1139+ *cp = '\0';
1140+ if (*start && !ccs_correct_word(start))
1141+ return NULL;
1142+ return ccs_get_name(start);
1143+}
1144+
1145+/**
1146+ * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
1147+ *
1148+ * @a: Pointer to "struct ccs_condition".
1149+ * @b: Pointer to "struct ccs_condition".
1150+ *
1151+ * Returns true if @a == @b, false otherwise.
1152+ */
1153+static inline bool ccs_same_condition(const struct ccs_condition *a,
1154+ const struct ccs_condition *b)
1155+{
1156+ return a->size == b->size &&
1157+ !memcmp(a + 1, b + 1, a->size - sizeof(*a));
1158+}
1159+
1160+/**
1161+ * ccs_commit_condition - Commit "struct ccs_condition".
1162+ *
1163+ * @entry: Pointer to "struct ccs_condition".
1164+ *
1165+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1166+ *
1167+ * This function merges duplicated entries. This function returns NULL if
1168+ * @entry is not duplicated but memory quota for policy has exceeded.
1169+ */
1170+static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
1171+{
1172+ struct ccs_condition *ptr;
1173+ bool found = false;
1174+ if (mutex_lock_interruptible(&ccs_policy_lock)) {
1175+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
1176+ ptr = NULL;
1177+ found = true;
1178+ goto out;
1179+ }
1180+ list_for_each_entry(ptr, &ccs_condition_list, head.list) {
1181+ if (!ccs_same_condition(ptr, entry) ||
1182+ atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
1183+ continue;
1184+ /* Same entry found. Share this entry. */
1185+ atomic_inc(&ptr->head.users);
1186+ found = true;
1187+ break;
1188+ }
1189+ if (!found) {
1190+ if (ccs_memory_ok(entry, entry->size)) {
1191+ atomic_set(&entry->head.users, 1);
1192+ list_add(&entry->head.list, &ccs_condition_list);
1193+ } else {
1194+ found = true;
1195+ ptr = NULL;
1196+ }
1197+ }
1198+ mutex_unlock(&ccs_policy_lock);
1199+out:
1200+ if (found) {
1201+ ccs_del_condition(&entry->head.list);
1202+ kfree(entry);
1203+ entry = ptr;
1204+ }
1205+ return entry;
1206+}
1207+
1208+/**
1209+ * ccs_correct_domain - Check whether the given domainname follows the naming rules.
1210+ *
1211+ * @domainname: The domainname to check.
1212+ *
1213+ * Returns true if @domainname follows the naming rules, false otherwise.
1214+ */
1215+static bool ccs_correct_domain(const unsigned char *domainname)
1216+{
1217+ if (!ccs_correct_word(domainname))
1218+ return false;
1219+ while (*domainname) {
1220+ if (*domainname++ != '\\')
1221+ continue;
1222+ if (*domainname < '0' || *domainname++ > '3')
1223+ return false;
1224+ }
1225+ return true;
1226+}
1227+
1228+/**
1229+ * ccs_normalize_line - Format string.
1230+ *
1231+ * @buffer: The line to normalize.
1232+ *
1233+ * Returns nothing.
1234+ *
1235+ * Leading and trailing whitespaces are removed.
1236+ * Multiple whitespaces are packed into single space.
1237+ */
1238+static void ccs_normalize_line(unsigned char *buffer)
1239+{
1240+ unsigned char *sp = buffer;
1241+ unsigned char *dp = buffer;
1242+ bool first = true;
1243+ while (*sp && (*sp <= ' ' || *sp >= 127))
1244+ sp++;
1245+ while (*sp) {
1246+ if (!first)
1247+ *dp++ = ' ';
1248+ first = false;
1249+ while (*sp > ' ' && *sp < 127)
1250+ *dp++ = *sp++;
1251+ while (*sp && (*sp <= ' ' || *sp >= 127))
1252+ sp++;
1253+ }
1254+ *dp = '\0';
1255+}
1256+
1257+/**
1258+ * ccs_parse_values - Parse an numeric argument.
1259+ *
1260+ * @value: Values to parse.
1261+ * @v: Pointer to "unsigned long".
1262+ *
1263+ * Returns "enum ccs_value_type" if @value is a single value, bitwise-OR-ed
1264+ * value if @value is value range.
1265+ */
1266+static u8 ccs_parse_values(char *value, unsigned long v[2])
1267+{
1268+ enum ccs_value_type radix1 = ccs_parse_ulong(&v[0], &value);
1269+ enum ccs_value_type radix2;
1270+ if (radix1 == CCS_VALUE_TYPE_INVALID)
1271+ return CCS_VALUE_TYPE_INVALID;
1272+ if (!*value) {
1273+ v[1] = v[0];
1274+ return radix1;
1275+ }
1276+ if (*value++ != '-')
1277+ return CCS_VALUE_TYPE_INVALID;
1278+ radix2 = ccs_parse_ulong(&v[1], &value);
1279+ if (radix2 == CCS_VALUE_TYPE_INVALID || *value || v[0] > v[1])
1280+ return CCS_VALUE_TYPE_INVALID;
1281+ return radix1 | (radix2 << 2);
1282+}
1283+
1284+#ifdef CONFIG_CCSECURITY_NETWORK
1285+
1286+/**
1287+ * ccs_parse_ipaddr - Parse an IP address.
1288+ *
1289+ * @address: Address to parse.
1290+ * @ipv6: Pointer to "struct in6_addr".
1291+ *
1292+ * Returns one of values in "enum ccs_ipaddr_type".
1293+ */
1294+/* Index numbers for type of IP addresses. */
1295+static enum ccs_ipaddr_type ccs_parse_ipaddr(char *address,
1296+ struct in6_addr ipv6[2])
1297+{
1298+ const char *end;
1299+ if (!strchr(address, ':') &&
1300+ in4_pton(address, -1, ipv6[0].s6_addr, '-', &end) > 0) {
1301+ if (!*end) {
1302+ ipv6[0].s6_addr32[0] = ipv6[0].s6_addr32[0];
1303+ ipv6[1].s6_addr32[0] = ipv6[0].s6_addr32[0];
1304+ return CCS_ADDRESS_TYPE_IPV4;
1305+ }
1306+ if (*end++ != '-' ||
1307+ in4_pton(end, -1, ipv6[1].s6_addr, '\0', &end) <= 0 ||
1308+ *end || memcmp(&ipv6[0], &ipv6[1], 4) >= 0)
1309+ return CCS_ADDRESS_TYPE_INVALID;
1310+ return CCS_ADDRESS_TYPE_IPV4_RANGE;
1311+ }
1312+ if (in6_pton(address, -1, ipv6[0].s6_addr, '-', &end) > 0) {
1313+ if (!*end) {
1314+ ipv6[1] = ipv6[0];
1315+ return CCS_ADDRESS_TYPE_IPV6;
1316+ }
1317+ if (*end++ != '-' ||
1318+ in6_pton(end, -1, ipv6[1].s6_addr, '\0', &end) <= 0 ||
1319+ *end || memcmp(&ipv6[0], &ipv6[1], 16) >= 0)
1320+ return CCS_ADDRESS_TYPE_INVALID;
1321+ return CCS_ADDRESS_TYPE_IPV6_RANGE;
1322+ }
1323+ return CCS_ADDRESS_TYPE_INVALID;
1324+}
1325+
1326+#endif
1327+
1328+/**
1329+ * ccs_parse_task_cond - Find index for variable's name.
1330+ *
1331+ * @word: Keyword to search.
1332+ *
1333+ * Returns one of "ccs_conditions_index" value.
1334+ */
1335+static enum ccs_conditions_index ccs_parse_task_cond(const char *word)
1336+{
1337+ if (!strncmp(word, "task.", 5)) {
1338+ word += 5;
1339+ if (!strcmp(word, "uid"))
1340+ return CCS_SELF_UID;
1341+ if (!strcmp(word, "euid"))
1342+ return CCS_SELF_EUID;
1343+ if (!strcmp(word, "suid"))
1344+ return CCS_SELF_SUID;
1345+ if (!strcmp(word, "fsuid"))
1346+ return CCS_SELF_FSUID;
1347+ if (!strcmp(word, "gid"))
1348+ return CCS_SELF_GID;
1349+ if (!strcmp(word, "egid"))
1350+ return CCS_SELF_EGID;
1351+ if (!strcmp(word, "sgid"))
1352+ return CCS_SELF_SGID;
1353+ if (!strcmp(word, "fsgid"))
1354+ return CCS_SELF_FSGID;
1355+ if (!strcmp(word, "pid"))
1356+ return CCS_SELF_PID;
1357+ if (!strcmp(word, "ppid"))
1358+ return CCS_SELF_PPID;
1359+ if (!strcmp(word, "type"))
1360+ return CCS_TASK_TYPE;
1361+ if (!strcmp(word, "domain"))
1362+ return CCS_SELF_DOMAIN;
1363+ if (!strcmp(word, "exe"))
1364+ return CCS_SELF_EXE;
1365+ }
1366+ return CCS_MAX_CONDITION_KEYWORD;
1367+}
1368+
1369+/**
1370+ * ccs_parse_syscall_arg - Find index for variable's name.
1371+ *
1372+ * @word: Keyword to search.
1373+ * @type: One of values in "enum ccs_mac_index".
1374+ *
1375+ * Returns one of "ccs_conditions_index" value.
1376+ */
1377+static enum ccs_conditions_index ccs_parse_syscall_arg
1378+(const char *word, const enum ccs_mac_index type)
1379+{
1380+ switch (type) {
1381+ case CCS_MAC_READ:
1382+ case CCS_MAC_WRITE:
1383+ case CCS_MAC_APPEND:
1384+ case CCS_MAC_UNLINK:
1385+#ifdef CONFIG_CCSECURITY_GETATTR
1386+ case CCS_MAC_GETATTR:
1387+#endif
1388+ case CCS_MAC_RMDIR:
1389+ case CCS_MAC_TRUNCATE:
1390+ case CCS_MAC_CHROOT:
1391+ case CCS_MAC_CHOWN:
1392+ case CCS_MAC_CHGRP:
1393+ case CCS_MAC_IOCTL:
1394+ case CCS_MAC_EXECUTE:
1395+ case CCS_MAC_SYMLINK:
1396+ if (!strcmp(word, "path"))
1397+ return CCS_COND_SARG0;
1398+ if (type == CCS_MAC_CHOWN && !strcmp(word, "uid"))
1399+ return CCS_COND_NARG0;
1400+ if (type == CCS_MAC_CHGRP && !strcmp(word, "gid"))
1401+ return CCS_COND_NARG0;
1402+ if (type == CCS_MAC_IOCTL && !strcmp(word, "cmd"))
1403+ return CCS_COND_NARG0;
1404+ if (type == CCS_MAC_EXECUTE && !strcmp(word, "exec"))
1405+ return CCS_COND_SARG1;
1406+ if (type == CCS_MAC_SYMLINK && !strcmp(word, "target"))
1407+ return CCS_COND_SARG1;
1408+ break;
1409+ case CCS_MAC_CHMOD:
1410+ case CCS_MAC_MKDIR:
1411+ case CCS_MAC_CREATE:
1412+ case CCS_MAC_MKFIFO:
1413+ case CCS_MAC_MKSOCK:
1414+ case CCS_MAC_MKBLOCK:
1415+ case CCS_MAC_MKCHAR:
1416+ if (!strcmp(word, "path"))
1417+ return CCS_COND_SARG0;
1418+ if (!strcmp(word, "perm"))
1419+ return CCS_COND_NARG0;
1420+ if (type == CCS_MAC_MKBLOCK || type == CCS_MAC_MKCHAR) {
1421+ if (!strcmp(word, "dev_major"))
1422+ return CCS_COND_NARG1;
1423+ if (!strcmp(word, "dev_minor"))
1424+ return CCS_COND_NARG2;
1425+ }
1426+ break;
1427+ case CCS_MAC_LINK:
1428+ case CCS_MAC_RENAME:
1429+ if (!strcmp(word, "old_path"))
1430+ return CCS_COND_SARG0;
1431+ if (!strcmp(word, "new_path"))
1432+ return CCS_COND_SARG1;
1433+ break;
1434+ case CCS_MAC_MOUNT:
1435+ if (!strcmp(word, "source"))
1436+ return CCS_COND_SARG0;
1437+ if (!strcmp(word, "target"))
1438+ return CCS_COND_SARG1;
1439+ if (!strcmp(word, "fstype"))
1440+ return CCS_COND_SARG2;
1441+ if (!strcmp(word, "data"))
1442+ return CCS_COND_SARG3;
1443+ if (!strcmp(word, "flags"))
1444+ return CCS_COND_NARG0;
1445+ break;
1446+ case CCS_MAC_UMOUNT:
1447+ if (!strcmp(word, "path"))
1448+ return CCS_COND_SARG0;
1449+ if (!strcmp(word, "flags"))
1450+ return CCS_COND_NARG0;
1451+ break;
1452+ case CCS_MAC_PIVOT_ROOT:
1453+ if (!strcmp(word, "new_root"))
1454+ return CCS_COND_SARG0;
1455+ if (!strcmp(word, "put_old"))
1456+ return CCS_COND_SARG1;
1457+ break;
1458+#ifdef CONFIG_CCSECURITY_NETWORK
1459+ case CCS_MAC_INET_STREAM_BIND:
1460+ case CCS_MAC_INET_STREAM_LISTEN:
1461+ case CCS_MAC_INET_STREAM_CONNECT:
1462+ case CCS_MAC_INET_STREAM_ACCEPT:
1463+ case CCS_MAC_INET_DGRAM_BIND:
1464+ case CCS_MAC_INET_DGRAM_SEND:
1465+ case CCS_MAC_INET_DGRAM_RECV:
1466+ if (!strcmp(word, "ip"))
1467+ return CCS_COND_IPARG;
1468+ if (!strcmp(word, "port"))
1469+ return CCS_COND_NARG0;
1470+ break;
1471+ case CCS_MAC_INET_RAW_BIND:
1472+ case CCS_MAC_INET_RAW_SEND:
1473+ case CCS_MAC_INET_RAW_RECV:
1474+ if (!strcmp(word, "ip"))
1475+ return CCS_COND_IPARG;
1476+ if (!strcmp(word, "proto"))
1477+ return CCS_COND_NARG0;
1478+ break;
1479+ case CCS_MAC_UNIX_STREAM_BIND:
1480+ case CCS_MAC_UNIX_STREAM_LISTEN:
1481+ case CCS_MAC_UNIX_STREAM_CONNECT:
1482+ case CCS_MAC_UNIX_STREAM_ACCEPT:
1483+ case CCS_MAC_UNIX_DGRAM_BIND:
1484+ case CCS_MAC_UNIX_DGRAM_SEND:
1485+ case CCS_MAC_UNIX_DGRAM_RECV:
1486+ case CCS_MAC_UNIX_SEQPACKET_BIND:
1487+ case CCS_MAC_UNIX_SEQPACKET_LISTEN:
1488+ case CCS_MAC_UNIX_SEQPACKET_CONNECT:
1489+ case CCS_MAC_UNIX_SEQPACKET_ACCEPT:
1490+ if (!strcmp(word, "addr"))
1491+ return CCS_COND_SARG0;
1492+ break;
1493+#endif
1494+#ifdef CONFIG_CCSECURITY_ENVIRON
1495+ case CCS_MAC_ENVIRON:
1496+ if (!strcmp(word, "path"))
1497+ return CCS_COND_SARG0;
1498+ if (!strcmp(word, "exec"))
1499+ return CCS_COND_SARG1;
1500+ if (!strcmp(word, "name"))
1501+ return CCS_COND_SARG2;
1502+ if (!strcmp(word, "value"))
1503+ return CCS_COND_SARG3;
1504+ break;
1505+#endif
1506+#ifdef CONFIG_CCSECURITY_PTRACE
1507+ case CCS_MAC_PTRACE:
1508+ if (!strcmp(word, "domain"))
1509+ return CCS_COND_DOMAIN;
1510+ if (!strcmp(word, "cmd"))
1511+ return CCS_COND_NARG0;
1512+ break;
1513+#endif
1514+#ifdef CONFIG_CCSECURITY_SIGNAL
1515+ case CCS_MAC_SIGNAL:
1516+ if (!strcmp(word, "sig"))
1517+ return CCS_COND_NARG0;
1518+ break;
1519+#endif
1520+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
1521+ case CCS_MAC_MANUAL_DOMAIN_TRANSITION:
1522+ if (!strcmp(word, "domain"))
1523+ return CCS_COND_DOMAIN;
1524+ break;
1525+#endif
1526+ default:
1527+ break;
1528+ }
1529+ return CCS_MAX_CONDITION_KEYWORD;
1530+}
1531+
1532+/**
1533+ * ccs_parse_path_attributes - Find index for variable's name.
1534+ *
1535+ * @word: Keyword to search.
1536+ * @type: One of values in "enum ccs_mac_index".
1537+ *
1538+ * Returns one of "ccs_conditions_index" value.
1539+ */
1540+static enum ccs_conditions_index ccs_parse_path_attribute
1541+(char *word, const enum ccs_mac_index type)
1542+{
1543+ u8 i;
1544+ enum ccs_conditions_index start;
1545+ switch (type) {
1546+ case CCS_MAC_READ:
1547+ case CCS_MAC_WRITE:
1548+ case CCS_MAC_APPEND:
1549+ case CCS_MAC_UNLINK:
1550+#ifdef CONFIG_CCSECURITY_GETATTR
1551+ case CCS_MAC_GETATTR:
1552+#endif
1553+ case CCS_MAC_RMDIR:
1554+ case CCS_MAC_TRUNCATE:
1555+ case CCS_MAC_CHROOT:
1556+ case CCS_MAC_CHMOD:
1557+ case CCS_MAC_CHOWN:
1558+ case CCS_MAC_CHGRP:
1559+ case CCS_MAC_IOCTL:
1560+ case CCS_MAC_EXECUTE:
1561+ case CCS_MAC_UMOUNT:
1562+#ifdef CONFIG_CCSECURITY_ENVIRON
1563+ case CCS_MAC_ENVIRON:
1564+#endif
1565+ if (ccs_str_starts(&word, "path"))
1566+ goto path1;
1567+#ifdef CONFIG_CCSECURITY_ENVIRON
1568+ if ((type == CCS_MAC_EXECUTE || type == CCS_MAC_ENVIRON) &&
1569+ ccs_str_starts(&word, "exec"))
1570+ goto path2;
1571+#else
1572+ if (type == CCS_MAC_EXECUTE &&
1573+ ccs_str_starts(&word, "exec"))
1574+ goto path2;
1575+#endif
1576+ break;
1577+ case CCS_MAC_MKDIR:
1578+ case CCS_MAC_CREATE:
1579+ case CCS_MAC_MKFIFO:
1580+ case CCS_MAC_MKSOCK:
1581+ case CCS_MAC_MKBLOCK:
1582+ case CCS_MAC_MKCHAR:
1583+ case CCS_MAC_SYMLINK:
1584+ if (ccs_str_starts(&word, "path"))
1585+ goto path1_parent;
1586+ break;
1587+ case CCS_MAC_LINK:
1588+ case CCS_MAC_RENAME:
1589+ if (ccs_str_starts(&word, "old_path"))
1590+ goto path1;
1591+ if (ccs_str_starts(&word, "new_path"))
1592+ goto path2_parent;
1593+ break;
1594+ case CCS_MAC_MOUNT:
1595+ if (ccs_str_starts(&word, "source"))
1596+ goto path1;
1597+ if (ccs_str_starts(&word, "target"))
1598+ goto path2;
1599+ break;
1600+ case CCS_MAC_PIVOT_ROOT:
1601+ if (ccs_str_starts(&word, "new_root"))
1602+ goto path1;
1603+ if (ccs_str_starts(&word, "put_old"))
1604+ goto path2;
1605+ break;
1606+ default:
1607+ break;
1608+ }
1609+ goto out;
1610+path1_parent:
1611+ if (strncmp(word, ".parent", 7))
1612+ goto out;
1613+path1:
1614+ start = CCS_PATH_ATTRIBUTE_START;
1615+ goto check;
1616+path2_parent:
1617+ if (strncmp(word, ".parent", 7))
1618+ goto out;
1619+path2:
1620+ start = CCS_PATH_ATTRIBUTE_START + 32;
1621+check:
1622+ if (ccs_str_starts(&word, ".parent"))
1623+ start += 16;
1624+ if (*word++ == '.')
1625+ for (i = 0; i < CCS_MAX_PATH_ATTRIBUTE; i++)
1626+ if (!strcmp(word, ccs_path_attribute[i]))
1627+ return start + i;
1628+out:
1629+ return CCS_MAX_CONDITION_KEYWORD;
1630+}
1631+
1632+/**
1633+ * ccs_find_pathtype - Find index for file's type.
1634+ *
1635+ * @word: Keyword to search.
1636+ *
1637+ * Returns one of "ccs_conditions_index" value.
1638+ */
1639+static enum ccs_conditions_index ccs_find_path_type(const char *word)
1640+{
1641+ if (!strcmp(word, "socket"))
1642+ return CCS_OBJ_IS_SOCKET;
1643+ if (!strcmp(word, "symlink"))
1644+ return CCS_OBJ_IS_SYMLINK;
1645+ if (!strcmp(word, "file"))
1646+ return CCS_OBJ_IS_FILE;
1647+ if (!strcmp(word, "block"))
1648+ return CCS_OBJ_IS_BLOCK_DEV;
1649+ if (!strcmp(word, "directory"))
1650+ return CCS_OBJ_IS_DIRECTORY;
1651+ if (!strcmp(word, "char"))
1652+ return CCS_OBJ_IS_CHAR_DEV;
1653+ if (!strcmp(word, "fifo"))
1654+ return CCS_OBJ_IS_FIFO;
1655+ return CCS_MAX_CONDITION_KEYWORD;
1656+}
1657+
1658+/**
1659+ * ccs_find_path_perm - Find index for file's DAC attribute.
1660+ *
1661+ * @word: Keyword to search.
1662+ *
1663+ * Returns one of "ccs_conditions_index" value.
1664+ */
1665+static enum ccs_conditions_index ccs_find_path_perm(const char *word)
1666+{
1667+ if (!strcmp(word, "setuid"))
1668+ return CCS_MODE_SETUID;
1669+ if (!strcmp(word, "setgid"))
1670+ return CCS_MODE_SETGID;
1671+ if (!strcmp(word, "sticky"))
1672+ return CCS_MODE_STICKY;
1673+ if (!strcmp(word, "owner_read"))
1674+ return CCS_MODE_OWNER_READ;
1675+ if (!strcmp(word, "owner_write"))
1676+ return CCS_MODE_OWNER_WRITE;
1677+ if (!strcmp(word, "owner_execute"))
1678+ return CCS_MODE_OWNER_EXECUTE;
1679+ if (!strcmp(word, "group_read"))
1680+ return CCS_MODE_GROUP_READ;
1681+ if (!strcmp(word, "group_write"))
1682+ return CCS_MODE_GROUP_WRITE;
1683+ if (!strcmp(word, "group_execute"))
1684+ return CCS_MODE_GROUP_EXECUTE;
1685+ if (!strcmp(word, "others_read"))
1686+ return CCS_MODE_OTHERS_READ;
1687+ if (!strcmp(word, "others_write"))
1688+ return CCS_MODE_OTHERS_WRITE;
1689+ if (!strcmp(word, "others_execute"))
1690+ return CCS_MODE_OTHERS_EXECUTE;
1691+ return CCS_MAX_CONDITION_KEYWORD;
1692+}
1693+
1694+/**
1695+ * ccs_parse_cond - Parse single condition.
1696+ *
1697+ * @tmp: Pointer to "struct ccs_cond_tmp".
1698+ * @head: Pointer to "struct ccs_io_buffer".
1699+ *
1700+ * Returns true on success, false otherwise.
1701+ */
1702+static bool ccs_parse_cond(struct ccs_cond_tmp *tmp,
1703+ struct ccs_io_buffer *head)
1704+{
1705+ enum ccs_group_id g;
1706+ char *left = head->w.data;
1707+ char *right;
1708+ const enum ccs_mac_index type = head->w.acl_index;
1709+ right = strchr(left, '=');
1710+ if (!right || right == left)
1711+ return false;
1712+ *right++ = '\0';
1713+ tmp->is_not = (*(right - 2) == '!');
1714+ if (tmp->is_not)
1715+ *(right - 2) = '\0';
1716+ if (!*left || !*right)
1717+ return false;
1718+ if (type == CCS_MAC_EXECUTE
1719+#ifdef CONFIG_CCSECURITY_ENVIRON
1720+ || type == CCS_MAC_ENVIRON
1721+#endif
1722+ ) {
1723+ if (ccs_str_starts(&left, "argv[")) {
1724+ tmp->left = CCS_ARGV_ENTRY;
1725+ if (ccs_parse_ulong(&tmp->argv, &left) !=
1726+ CCS_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
1727+ return false;
1728+ } else if (ccs_str_starts(&left, "envp[")) {
1729+ char *cp = left + strlen(left) - 1;
1730+ tmp->left = CCS_ENVP_ENTRY;
1731+ if (*cp != ']')
1732+ return false;
1733+ *cp = '\0';
1734+ tmp->envp = ccs_get_dqword(left);
1735+ if (!tmp->envp)
1736+ return false;
1737+ } else if (!strcmp(left, "argc"))
1738+ tmp->left = CCS_EXEC_ARGC;
1739+ else if (!strcmp(left, "envc"))
1740+ tmp->left = CCS_EXEC_ENVC;
1741+ }
1742+ if (tmp->left == CCS_MAX_CONDITION_KEYWORD)
1743+ tmp->left = ccs_parse_syscall_arg(left, type);
1744+ if (tmp->left == CCS_MAX_CONDITION_KEYWORD)
1745+ tmp->left = ccs_parse_task_cond(left);
1746+ if (tmp->left == CCS_MAX_CONDITION_KEYWORD)
1747+ tmp->left = ccs_parse_path_attribute(left, type);
1748+ if (tmp->left == CCS_MAX_CONDITION_KEYWORD) {
1749+ /*
1750+ * CCS_HANDLER_PATH and CCS_TRANSIT_DOMAIN are not for
1751+ * comparison.
1752+ */
1753+ if (tmp->is_not)
1754+ return false;
1755+ if (!strcmp(left, "handler"))
1756+ tmp->left = CCS_HANDLER_PATH;
1757+ else if (!strcmp(left, "transition"))
1758+ tmp->left = CCS_TRANSIT_DOMAIN;
1759+ else
1760+ return false;
1761+ tmp->right = CCS_IMM_NAME_ENTRY;
1762+ if (!strcmp(right, "NULL")) {
1763+ tmp->path = &ccs_null_name;
1764+ } else {
1765+ tmp->path = ccs_get_dqword(right);
1766+ if (!tmp->path ||
1767+ tmp->path->const_len != tmp->path->total_len)
1768+ return false;
1769+ }
1770+ return true;
1771+ }
1772+ switch (tmp->left) {
1773+ case CCS_COND_DOMAIN:
1774+ case CCS_SELF_DOMAIN:
1775+ case CCS_ARGV_ENTRY:
1776+ case CCS_ENVP_ENTRY:
1777+ case CCS_COND_SARG0:
1778+ case CCS_COND_SARG1:
1779+ case CCS_COND_SARG2:
1780+ case CCS_COND_SARG3:
1781+ case CCS_SELF_EXE:
1782+ g = CCS_STRING_GROUP;
1783+ break;
1784+#ifdef CONFIG_CCSECURITY_NETWORK
1785+ case CCS_COND_IPARG:
1786+ g = CCS_IP_GROUP;
1787+ break;
1788+#endif
1789+ case CCS_TASK_TYPE:
1790+ tmp->right = CCS_TASK_EXECUTE_HANDLER;
1791+ return !strcmp(right, "execute_handler");
1792+ case CCS_PATH_ATTRIBUTE_START + CCS_PATH_ATTRIBUTE_TYPE:
1793+ case CCS_PATH_ATTRIBUTE_START + 16 + CCS_PATH_ATTRIBUTE_TYPE:
1794+ case CCS_PATH_ATTRIBUTE_START + 32 + CCS_PATH_ATTRIBUTE_TYPE:
1795+ case CCS_PATH_ATTRIBUTE_START + 48 + CCS_PATH_ATTRIBUTE_TYPE:
1796+ tmp->right = ccs_find_path_type(right);
1797+ return tmp->right != CCS_MAX_CONDITION_KEYWORD;
1798+ case CCS_PATH_ATTRIBUTE_START + CCS_PATH_ATTRIBUTE_PERM:
1799+ case CCS_PATH_ATTRIBUTE_START + 16 + CCS_PATH_ATTRIBUTE_PERM:
1800+ case CCS_PATH_ATTRIBUTE_START + 32 + CCS_PATH_ATTRIBUTE_PERM:
1801+ case CCS_PATH_ATTRIBUTE_START + 48 + CCS_PATH_ATTRIBUTE_PERM:
1802+ tmp->right = ccs_find_path_perm(right);
1803+ if (tmp->right != CCS_MAX_CONDITION_KEYWORD)
1804+ return true;
1805+ /* fall through */
1806+ default:
1807+ g = CCS_NUMBER_GROUP;
1808+ }
1809+ if (*right == '@') {
1810+ tmp->right = CCS_IMM_GROUP;
1811+ head->w.data = ++right;
1812+ tmp->group = ccs_get_group(head, g);
1813+ return tmp->group != NULL;
1814+ }
1815+ if (*right == '"') {
1816+ if (g != CCS_STRING_GROUP)
1817+ return false;
1818+ tmp->right = CCS_IMM_NAME_ENTRY;
1819+ tmp->path = ccs_get_dqword(right);
1820+ return tmp->path != NULL;
1821+ }
1822+ if (tmp->left == CCS_ENVP_ENTRY) {
1823+ tmp->right = CCS_IMM_NAME_ENTRY;
1824+ tmp->path = &ccs_null_name;
1825+ return !strcmp(right, "NULL");
1826+ }
1827+ if (g == CCS_NUMBER_GROUP) {
1828+ tmp->right = ccs_parse_task_cond(right);
1829+ if (tmp->right == CCS_SELF_DOMAIN ||
1830+ tmp->right == CCS_SELF_EXE)
1831+ return false;
1832+ if (tmp->right == CCS_MAX_CONDITION_KEYWORD)
1833+ tmp->right = ccs_parse_path_attribute(right, type);
1834+ if (tmp->right != CCS_MAX_CONDITION_KEYWORD)
1835+ return true;
1836+ tmp->radix = ccs_parse_values(right, tmp->value);
1837+ if (tmp->radix == CCS_VALUE_TYPE_INVALID)
1838+ return false;
1839+ if (tmp->radix >> 2)
1840+ tmp->right = CCS_IMM_NUMBER_ENTRY2;
1841+ else
1842+ tmp->right = CCS_IMM_NUMBER_ENTRY1;
1843+ return true;
1844+ }
1845+#ifdef CONFIG_CCSECURITY_NETWORK
1846+ if (g == CCS_IP_GROUP) {
1847+ switch (ccs_parse_ipaddr(right, tmp->ipv6)) {
1848+ case CCS_ADDRESS_TYPE_IPV4:
1849+ tmp->right = CCS_IMM_IPV4ADDR_ENTRY1;
1850+ break;
1851+ case CCS_ADDRESS_TYPE_IPV4_RANGE:
1852+ tmp->right = CCS_IMM_IPV4ADDR_ENTRY2;
1853+ break;
1854+ case CCS_ADDRESS_TYPE_IPV6:
1855+ tmp->right = CCS_IMM_IPV6ADDR_ENTRY1;
1856+ break;
1857+ case CCS_ADDRESS_TYPE_IPV6_RANGE:
1858+ tmp->right = CCS_IMM_IPV6ADDR_ENTRY2;
1859+ break;
1860+ default:
1861+ return false;
1862+ }
1863+ return true;
1864+ }
1865+#endif
1866+ return false;
1867+}
1868+
1869+/**
1870+ * ccs_get_condition - Parse condition part.
1871+ *
1872+ * @head: Pointer to "struct ccs_io_buffer".
1873+ *
1874+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1875+ */
1876+struct ccs_condition *ccs_get_condition(struct ccs_io_buffer *head)
1877+{
1878+ struct ccs_condition *entry = kmalloc(PAGE_SIZE, GFP_NOFS);
1879+ union ccs_condition_element *condp;
1880+ struct ccs_cond_tmp tmp;
1881+ const enum ccs_mac_index type = head->w.acl_index;
1882+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
1883+ bool handler_path_done = head->w.is_deny ||
1884+ type != CCS_MAC_EXECUTE;
1885+#else
1886+ bool handler_path_done = true;
1887+#endif
1888+ bool transit_domain_done = head->w.is_deny ||
1889+ (type != CCS_MAC_EXECUTE
1890+#ifdef CONFIG_CCSECURITY_AUTO_DOMAIN_TRANSITION
1891+ && type != CCS_MAC_AUTO_DOMAIN_TRANSITION
1892+#endif
1893+ );
1894+ char *pos = head->w.data;
1895+ if (!entry)
1896+ return NULL;
1897+ condp = (union ccs_condition_element *) (entry + 1);
1898+ while (1) {
1899+ memset(&tmp, 0, sizeof(tmp));
1900+ tmp.left = CCS_MAX_CONDITION_KEYWORD;
1901+ tmp.right = CCS_MAX_CONDITION_KEYWORD;
1902+ while (*pos == ' ')
1903+ pos++;
1904+ if (!*pos)
1905+ break;
1906+ if ((u8 *) condp >= ((u8 *) entry) + PAGE_SIZE
1907+ - (sizeof(*condp) + sizeof(struct in6_addr) * 2))
1908+ goto out;
1909+ {
1910+ char *next = strchr(pos, ' ');
1911+ if (next)
1912+ *next++ = '\0';
1913+ else
1914+ next = "";
1915+ head->w.data = pos;
1916+ pos = next;
1917+ }
1918+ if (!ccs_parse_cond(&tmp, head))
1919+ goto out;
1920+ if (tmp.left == CCS_HANDLER_PATH) {
1921+ if (handler_path_done)
1922+ goto out;
1923+ handler_path_done = true;
1924+ }
1925+ if (tmp.left == CCS_TRANSIT_DOMAIN) {
1926+ if (transit_domain_done)
1927+ goto out;
1928+ transit_domain_done = true;
1929+ }
1930+ condp->is_not = tmp.is_not;
1931+ condp->left = tmp.left;
1932+ condp->right = tmp.right;
1933+ condp->radix = tmp.radix;
1934+ condp++;
1935+ if (tmp.left == CCS_ARGV_ENTRY) {
1936+ condp->value = tmp.argv;
1937+ condp++;
1938+ } else if (tmp.left == CCS_ENVP_ENTRY) {
1939+ condp->path = tmp.envp;
1940+ condp++;
1941+ }
1942+ if (tmp.right == CCS_IMM_GROUP) {
1943+ condp->group = tmp.group;
1944+ condp++;
1945+ } else if (tmp.right == CCS_IMM_NAME_ENTRY) {
1946+ condp->path = tmp.path;
1947+ condp++;
1948+ } else if (tmp.right == CCS_IMM_NUMBER_ENTRY1 ||
1949+ tmp.right == CCS_IMM_NUMBER_ENTRY2) {
1950+ condp->value = tmp.value[0];
1951+ condp++;
1952+ if (tmp.right == CCS_IMM_NUMBER_ENTRY2) {
1953+ condp->value = tmp.value[1];
1954+ condp++;
1955+ }
1956+#ifdef CONFIG_CCSECURITY_NETWORK
1957+ } else if (tmp.right == CCS_IMM_IPV4ADDR_ENTRY1 ||
1958+ tmp.right == CCS_IMM_IPV4ADDR_ENTRY2) {
1959+ condp->ip = * (u32 *) &tmp.ipv6[0];
1960+ condp++;
1961+ if (tmp.right == CCS_IMM_IPV4ADDR_ENTRY2) {
1962+ condp->ip = * (u32 *) &tmp.ipv6[1];
1963+ condp++;
1964+ }
1965+ } else if (tmp.right == CCS_IMM_IPV6ADDR_ENTRY1 ||
1966+ tmp.right == CCS_IMM_IPV6ADDR_ENTRY2) {
1967+ * (struct in6_addr *) condp = tmp.ipv6[0];
1968+ condp = (void *) (((u8 *) condp) +
1969+ sizeof(struct in6_addr));
1970+ if (tmp.right == CCS_IMM_IPV6ADDR_ENTRY2) {
1971+ * (struct in6_addr *) condp = tmp.ipv6[1];
1972+ condp = (void *) (((u8 *) condp) +
1973+ sizeof(struct in6_addr));
1974+ }
1975+#endif
1976+ }
1977+ }
1978+#ifdef CONFIG_CCSECURITY_AUTO_DOMAIN_TRANSITION
1979+ if (!transit_domain_done && type == CCS_MAC_AUTO_DOMAIN_TRANSITION)
1980+ goto out;
1981+#endif
1982+ entry->size = (void *) condp - (void *) entry;
1983+ return ccs_commit_condition(entry);
1984+out:
1985+ dprintk(KERN_WARNING "%u: type=%u env='%s' path='%s' group='%s'\n",
1986+ __LINE__, type, tmp.envp ? tmp.envp->name : "",
1987+ tmp.path ? tmp.path->name : "",
1988+ tmp.group ? tmp.group->group_name->name : "");
1989+ ccs_put_name(tmp.envp);
1990+ if (tmp.path != &ccs_null_name)
1991+ ccs_put_name(tmp.path);
1992+ ccs_put_group(tmp.group);
1993+ entry->size = (void *) condp - (void *) entry;
1994+ ccs_del_condition(&entry->head.list);
1995+ kfree(entry);
1996+ return NULL;
1997+}
1998+
1999+/**
2000+ * ccs_yesno - Return "yes" or "no".
2001+ *
2002+ * @value: Bool value.
2003+ *
2004+ * Returns "yes" if @value is not 0, "no" otherwise.
2005+ */
2006+static const char *ccs_yesno(const unsigned int value)
2007+{
2008+ return value ? "yes" : "no";
2009+}
2010+
2011+/**
2012+ * ccs_flush - Flush queued string to userspace's buffer.
2013+ *
2014+ * @head: Pointer to "struct ccs_io_buffer".
2015+ *
2016+ * Returns true if all data was flushed, false otherwise.
2017+ */
2018+static bool ccs_flush(struct ccs_io_buffer *head)
2019+{
2020+ while (head->r.w_pos) {
2021+ const char *w = head->r.w[0];
2022+ size_t len = strlen(w);
2023+ if (len) {
2024+ if (len > head->read_user_buf_avail)
2025+ len = head->read_user_buf_avail;
2026+ if (!len)
2027+ return false;
2028+ if (copy_to_user(head->read_user_buf, w, len))
2029+ return false;
2030+ head->read_user_buf_avail -= len;
2031+ head->read_user_buf += len;
2032+ w += len;
2033+ }
2034+ head->r.w[0] = w;
2035+ if (*w)
2036+ return false;
2037+ /* Add '\0' for audit logs and query. */
2038+ if (head->type == CCS_AUDIT || head->type == CCS_QUERY) {
2039+ if (!head->read_user_buf_avail ||
2040+ copy_to_user(head->read_user_buf, "", 1))
2041+ return false;
2042+ head->read_user_buf_avail--;
2043+ head->read_user_buf++;
2044+ }
2045+ head->r.w_pos--;
2046+ for (len = 0; len < head->r.w_pos; len++)
2047+ head->r.w[len] = head->r.w[len + 1];
2048+ }
2049+ head->r.avail = 0;
2050+ return true;
2051+}
2052+
2053+/**
2054+ * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
2055+ *
2056+ * @head: Pointer to "struct ccs_io_buffer".
2057+ * @string: String to print.
2058+ *
2059+ * Returns nothing.
2060+ *
2061+ * Note that @string has to be kept valid until @head is kfree()d.
2062+ * This means that char[] allocated on stack memory cannot be passed to
2063+ * this function. Use ccs_io_printf() for char[] allocated on stack memory.
2064+ */
2065+static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
2066+{
2067+ if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
2068+ head->r.w[head->r.w_pos++] = string;
2069+ ccs_flush(head);
2070+ } else
2071+ printk(KERN_WARNING "Too many words in a line.\n");
2072+}
2073+
2074+/**
2075+ * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
2076+ *
2077+ * @head: Pointer to "struct ccs_io_buffer".
2078+ * @fmt: The printf()'s format string, followed by parameters.
2079+ *
2080+ * Returns nothing.
2081+ */
2082+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
2083+{
2084+ va_list args;
2085+ size_t len;
2086+ size_t pos = head->r.avail;
2087+ int size = head->readbuf_size - pos;
2088+ if (size <= 0)
2089+ return;
2090+ va_start(args, fmt);
2091+ len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
2092+ va_end(args);
2093+ if (pos + len >= head->readbuf_size) {
2094+ printk(KERN_WARNING "Too many words in a line.\n");
2095+ return;
2096+ }
2097+ head->r.avail += len;
2098+ ccs_set_string(head, head->read_buf + pos);
2099+}
2100+
2101+/**
2102+ * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
2103+ *
2104+ * @head: Pointer to "struct ccs_io_buffer".
2105+ *
2106+ * Returns nothing.
2107+ */
2108+static void ccs_set_space(struct ccs_io_buffer *head)
2109+{
2110+ ccs_set_string(head, " ");
2111+}
2112+
2113+/**
2114+ * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
2115+ *
2116+ * @head: Pointer to "struct ccs_io_buffer".
2117+ *
2118+ * Returns true if all data was flushed, false otherwise.
2119+ */
2120+static bool ccs_set_lf(struct ccs_io_buffer *head)
2121+{
2122+ ccs_set_string(head, "\n");
2123+ return !head->r.w_pos;
2124+}
2125+
2126+/**
2127+ * ccs_check_profile - Check policy is loaded.
2128+ *
2129+ * Returns nothing.
2130+ */
2131+static void ccs_check_profile(void)
2132+{
2133+ ccs_policy_loaded = true;
2134+ printk(KERN_INFO "CaitSith: 0.1 2012/04/01\n");
2135+ if (ccs_policy_version == 20120401) {
2136+ printk(KERN_INFO "CaitSith module activated.\n");
2137+ return;
2138+ }
2139+ printk(KERN_ERR "Policy version %u is not supported.\n",
2140+ ccs_policy_version);
2141+ printk(KERN_ERR "Userland tools for CaitSith must be installed and "
2142+ "policy must be initialized.\n");
2143+ printk(KERN_ERR "Please see http://caitsith.sourceforge.jp/ "
2144+ "for more information.\n");
2145+ panic("STOP!");
2146+}
2147+
2148+/**
2149+ * ccs_str_starts - Check whether the given string starts with the given keyword.
2150+ *
2151+ * @src: Pointer to pointer to the string.
2152+ * @find: Pointer to the keyword.
2153+ *
2154+ * Returns true if @src starts with @find, false otherwise.
2155+ *
2156+ * The @src is updated to point the first character after the @find
2157+ * if @src starts with @find.
2158+ */
2159+static bool ccs_str_starts(char **src, const char *find)
2160+{
2161+ const int len = strlen(find);
2162+ char *tmp = *src;
2163+ if (strncmp(tmp, find, len))
2164+ return false;
2165+ tmp += len;
2166+ *src = tmp;
2167+ return true;
2168+}
2169+
2170+/**
2171+ * ccs_find_domain - Find a domain by the given name.
2172+ *
2173+ * @domainname: The domainname to find.
2174+ *
2175+ * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
2176+ *
2177+ * Caller holds ccs_read_lock().
2178+ */
2179+static struct ccs_domain_info *ccs_find_domain(const char *domainname)
2180+{
2181+ struct ccs_domain_info *domain;
2182+ struct ccs_path_info name;
2183+ name.name = domainname;
2184+ ccs_fill_path_info(&name);
2185+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2186+ if (!ccs_pathcmp(&name, domain->domainname))
2187+ return domain;
2188+ }
2189+ return NULL;
2190+}
2191+
2192+/**
2193+ * ccs_select_acl - Parse select command.
2194+ *
2195+ * @head: Pointer to "struct ccs_io_buffer".
2196+ * @data: String to parse.
2197+ *
2198+ * Returns true on success, false otherwise.
2199+ *
2200+ * Caller holds ccs_read_lock().
2201+ */
2202+static bool ccs_select_acl(struct ccs_io_buffer *head, const char *data)
2203+{
2204+ unsigned int qid;
2205+ struct ccs_acl_info *acl;
2206+ if (sscanf(data, "Q=%u", &qid) != 1)
2207+ return false;
2208+ acl = ccs_find_acl_by_qid(qid);
2209+ head->w.acl = acl;
2210+ /* Accessing read_buf is safe because head->io_sem is held. */
2211+ if (!head->read_buf)
2212+ return true; /* Do nothing if open(O_WRONLY). */
2213+ memset(&head->r, 0, sizeof(head->r));
2214+ head->r.print_this_acl_only = true;
2215+ if (acl)
2216+ head->r.acl = &acl->list;
2217+ else
2218+ head->r.eof = true;
2219+ ccs_io_printf(head, "# Q=%u\n", qid);
2220+ return true;
2221+}
2222+
2223+/**
2224+ * ccs_update_acl - Update "struct ccs_acl_info" entry.
2225+ *
2226+ * @list: Pointer to "struct list_head".
2227+ * @head: Pointer to "struct ccs_io_buffer".
2228+ * @update: True to store matching entry, false otherwise.
2229+ *
2230+ * Returns 0 on success, negative value otherwise.
2231+ *
2232+ * Caller holds ccs_read_lock().
2233+ */
2234+static int ccs_update_acl(struct list_head * const list,
2235+ struct ccs_io_buffer *head, const bool update)
2236+{
2237+ struct ccs_acl_info *ptr;
2238+ struct ccs_acl_info new_entry = { };
2239+ const bool is_delete = head->w.is_delete;
2240+ int error = is_delete ? -ENOENT : -ENOMEM;
2241+ new_entry.priority = head->w.priority;
2242+ new_entry.is_deny = head->w.is_deny;
2243+ if (head->w.data[0]) {
2244+ new_entry.cond = ccs_get_condition(head);
2245+ if (!new_entry.cond)
2246+ return -EINVAL;
2247+ }
2248+ if (mutex_lock_interruptible(&ccs_policy_lock))
2249+ goto out;
2250+ list_for_each_entry_srcu(ptr, list, list, &ccs_ss) {
2251+ if (ptr->priority > new_entry.priority)
2252+ break;
2253+ /*
2254+ * We cannot reuse deleted "struct ccs_acl_info" entry because
2255+ * somebody might be referencing children of this deleted entry
2256+ * from srcu section. We cannot delete children of this deleted
2257+ * entry until all children are no longer referenced. Thus, let
2258+ * the garbage collector wait and delete rather than trying to
2259+ * reuse this deleted entry.
2260+ */
2261+ if (ptr->is_deleted || ptr->cond != new_entry.cond ||
2262+ ptr->priority != new_entry.priority ||
2263+ ptr->is_deny != new_entry.is_deny)
2264+ continue;
2265+ ptr->is_deleted = is_delete;
2266+ if (!is_delete && update)
2267+ head->w.acl = ptr;
2268+ error = 0;
2269+ break;
2270+ }
2271+ if (error && !is_delete) {
2272+ struct ccs_acl_info *entry =
2273+ ccs_commit_ok(&new_entry, sizeof(new_entry));
2274+ if (entry) {
2275+ INIT_LIST_HEAD(&entry->acl_info_list);
2276+ list_add_tail_rcu(&entry->list, &ptr->list);
2277+ if (update)
2278+ head->w.acl = entry;
2279+ }
2280+ }
2281+ mutex_unlock(&ccs_policy_lock);
2282+out:
2283+ ccs_put_condition(new_entry.cond);
2284+ return error;
2285+}
2286+
2287+/**
2288+ * ccs_parse_entry - Update ACL entry.
2289+ *
2290+ * @head: Pointer to "struct ccs_io_buffer".
2291+ *
2292+ * Returns 0 on success, negative value otherwise.
2293+ *
2294+ * Caller holds ccs_read_lock().
2295+ */
2296+static int ccs_parse_entry(struct ccs_io_buffer *head)
2297+{
2298+ enum ccs_mac_index type;
2299+ const char *operation = ccs_read_token(head);
2300+ for (type = 0; type < CCS_MAX_MAC_INDEX; type++) {
2301+ if (strcmp(operation, ccs_mac_keywords[type]))
2302+ continue;
2303+ head->w.acl_index = type;
2304+ /*
2305+ * This is_deny is for rejecting handler= and transition=
2306+ * arguments in "acl" line. handler= and transition= arguments
2307+ * are accepted for only "allow" line.
2308+ */
2309+ head->w.is_deny = true;
2310+ return ccs_update_acl(&ccs_acl_list[type], head, true);
2311+ }
2312+ return -EINVAL;
2313+}
2314+
2315+/**
2316+ * ccs_print_number - Print number argument.
2317+ *
2318+ * @head: Pointer to "struct ccs_io_buffer".
2319+ * @radix: One of values in "enum ccs_value_type".
2320+ * @value: Value to print.
2321+ *
2322+ * Returns nothing.
2323+ */
2324+static void ccs_print_number(struct ccs_io_buffer *head,
2325+ const enum ccs_value_type radix,
2326+ const unsigned long value)
2327+{
2328+ switch (radix) {
2329+ case CCS_VALUE_TYPE_HEXADECIMAL:
2330+ ccs_io_printf(head, "0x%lX", value);
2331+ break;
2332+ case CCS_VALUE_TYPE_OCTAL:
2333+ ccs_io_printf(head, "0%lo", value);
2334+ break;
2335+ default:
2336+ ccs_io_printf(head, "%lu", value);
2337+ }
2338+}
2339+
2340+/**
2341+ * ccs_print_misc_attribute - Print misc attribute's name.
2342+ *
2343+ * @head: Pointer to "struct ccs_io_buffer".
2344+ * @type: One of values in "enum ccs_mac_index".
2345+ * @cond: One of values in "enum ccs_condition_index".
2346+ *
2347+ * Returns nothing.
2348+ */
2349+static void ccs_print_misc_attribute(struct ccs_io_buffer *head,
2350+ const enum ccs_mac_index type,
2351+ const enum ccs_conditions_index cond)
2352+{
2353+ if (cond >= CCS_PATH_ATTRIBUTE_START) {
2354+ const u8 pos = cond - CCS_PATH_ATTRIBUTE_START;
2355+ ccs_io_printf(head, "%s.%s%s", ccs_get_sarg(type, pos >= 32),
2356+ pos % 32 >= 16 ? "parent." : "",
2357+ ccs_path_attribute[pos % 16]);
2358+ return;
2359+ }
2360+ if (cond == CCS_COND_DOMAIN) {
2361+ ccs_set_string(head, "domain");
2362+ return;
2363+ }
2364+ switch (cond) {
2365+ case CCS_SELF_UID:
2366+ case CCS_SELF_EUID:
2367+ case CCS_SELF_SUID:
2368+ case CCS_SELF_FSUID:
2369+ case CCS_SELF_GID:
2370+ case CCS_SELF_EGID:
2371+ case CCS_SELF_SGID:
2372+ case CCS_SELF_FSGID:
2373+ case CCS_SELF_PID:
2374+ case CCS_SELF_PPID:
2375+ case CCS_TASK_TYPE:
2376+ case CCS_SELF_DOMAIN:
2377+ case CCS_SELF_EXE:
2378+ ccs_set_string(head, "task.");
2379+ /* fall through */
2380+ default:
2381+ if (cond < CCS_MAX_CONDITION_KEYWORD)
2382+ ccs_set_string(head, ccs_condition_keyword[cond]);
2383+ else
2384+ ccs_io_printf(head, "unknown(%u)", cond);
2385+ }
2386+}
2387+
2388+/**
2389+ * ccs_print_condition_loop - Print condition part.
2390+ *
2391+ * @head: Pointer to "struct ccs_io_buffer".
2392+ * @cond: Pointer to "struct ccs_condition".
2393+ *
2394+ * Returns true on success, false otherwise.
2395+ */
2396+static bool ccs_print_condition_loop(struct ccs_io_buffer *head,
2397+ const struct ccs_condition *cond)
2398+{
2399+ const enum ccs_mac_index type = head->r.acl_index;
2400+ const union ccs_condition_element *condp = head->r.cond;
2401+ while ((void *) condp < (void *) ((u8 *) cond) + cond->size) {
2402+ const bool is_not = condp->is_not;
2403+ const enum ccs_conditions_index left = condp->left;
2404+ const enum ccs_conditions_index right = condp->right;
2405+ const u8 radix = condp->radix;
2406+ if (!ccs_flush(head)) {
2407+ head->r.cond = condp;
2408+ return false;
2409+ }
2410+ condp++;
2411+ ccs_set_space(head);
2412+ switch (left) {
2413+ case CCS_ARGV_ENTRY:
2414+ ccs_io_printf(head, "argv[%lu]", condp->value);
2415+ condp++;
2416+ break;
2417+ case CCS_ENVP_ENTRY:
2418+ ccs_set_string(head, "envp[\"");
2419+ ccs_set_string(head, condp->path->name);
2420+ condp++;
2421+ ccs_set_string(head, "\"]");
2422+ break;
2423+ case CCS_COND_SARG0:
2424+ ccs_set_string(head, ccs_get_sarg(type, 0));
2425+ break;
2426+ case CCS_COND_SARG1:
2427+ ccs_set_string(head, ccs_get_sarg(type, 1));
2428+ break;
2429+ case CCS_COND_SARG2:
2430+ ccs_set_string(head, ccs_get_sarg(type, 2));
2431+ break;
2432+ case CCS_COND_SARG3:
2433+ ccs_set_string(head, ccs_get_sarg(type, 3));
2434+ break;
2435+ case CCS_COND_NARG0:
2436+ ccs_set_string(head, ccs_get_narg(type, 0));
2437+ break;
2438+ case CCS_COND_NARG1:
2439+ ccs_set_string(head, ccs_get_narg(type, 1));
2440+ break;
2441+ case CCS_COND_NARG2:
2442+ ccs_set_string(head, ccs_get_narg(type, 2));
2443+ break;
2444+ case CCS_COND_IPARG:
2445+ ccs_set_string(head, "ip");
2446+ break;
2447+ default:
2448+ ccs_print_misc_attribute(head, type, left);
2449+ }
2450+ ccs_set_string(head, is_not ? "!=" : "=");
2451+ switch (right) {
2452+ case CCS_IMM_GROUP:
2453+ ccs_set_string(head, "@");
2454+ ccs_set_string(head, condp->group->group_name->name);
2455+ condp++;
2456+ break;
2457+ case CCS_IMM_NAME_ENTRY:
2458+ if (condp->path != &ccs_null_name) {
2459+ ccs_set_string(head, "\"");
2460+ ccs_set_string(head, condp->path->name);
2461+ ccs_set_string(head, "\"");
2462+ } else {
2463+ ccs_set_string(head, "NULL");
2464+ }
2465+ condp++;
2466+ break;
2467+ case CCS_IMM_NUMBER_ENTRY1:
2468+ case CCS_IMM_NUMBER_ENTRY2:
2469+ ccs_print_number(head, radix & 3, condp->value);
2470+ condp++;
2471+ if (right == CCS_IMM_NUMBER_ENTRY1)
2472+ break;
2473+ ccs_set_string(head, "-");
2474+ ccs_print_number(head, (radix >> 2) & 3, condp->value);
2475+ condp++;
2476+ break;
2477+#ifdef CONFIG_CCSECURITY_NETWORK
2478+ case CCS_IMM_IPV4ADDR_ENTRY1:
2479+ case CCS_IMM_IPV4ADDR_ENTRY2:
2480+ ccs_print_ipv4(head, &condp->ip);
2481+ condp++;
2482+ if (right == CCS_IMM_IPV4ADDR_ENTRY1)
2483+ break;
2484+ ccs_set_string(head, "-");
2485+ ccs_print_ipv4(head, &condp->ip);
2486+ condp++;
2487+ break;
2488+ case CCS_IMM_IPV6ADDR_ENTRY1:
2489+ case CCS_IMM_IPV6ADDR_ENTRY2:
2490+ ccs_print_ipv6(head, (const struct in6_addr *) condp);
2491+ condp = (void *)
2492+ ((u8 *) condp) + sizeof(struct in6_addr);
2493+ if (right == CCS_IMM_IPV6ADDR_ENTRY1)
2494+ break;
2495+ ccs_set_string(head, "-");
2496+ ccs_print_ipv6(head, (const struct in6_addr *) condp);
2497+ condp = (void *)
2498+ ((u8 *) condp) + sizeof(struct in6_addr);
2499+ break;
2500+#endif
2501+ default:
2502+ ccs_print_misc_attribute(head, type, right);
2503+ }
2504+ }
2505+ head->r.cond = NULL;
2506+ return true;
2507+}
2508+
2509+/**
2510+ * ccs_print_condition - Print condition part.
2511+ *
2512+ * @head: Pointer to "struct ccs_io_buffer".
2513+ * @cond: Pointer to "struct ccs_condition".
2514+ *
2515+ * Returns true on success, false otherwise.
2516+ */
2517+static bool ccs_print_condition(struct ccs_io_buffer *head,
2518+ const struct ccs_condition *cond)
2519+{
2520+ switch (head->r.cond_step) {
2521+ case 0:
2522+ head->r.cond = (const union ccs_condition_element *)
2523+ (cond + 1);
2524+ head->r.cond_step++;
2525+ /* fall through */
2526+ case 1:
2527+ if (!ccs_print_condition_loop(head, cond))
2528+ return false;
2529+ head->r.cond_step++;
2530+ /* fall through */
2531+ case 2:
2532+ head->r.cond = NULL;
2533+ return true;
2534+ }
2535+ return false;
2536+}
2537+
2538+/**
2539+ * ccs_read_acl - Print an ACL entry.
2540+ *
2541+ * @head: Pointer to "struct ccs_io_buffer".
2542+ * @acl: Pointer to an ACL entry.
2543+ *
2544+ * Returns true on success, false otherwise.
2545+ */
2546+static bool ccs_read_acl(struct ccs_io_buffer *head,
2547+ const struct ccs_acl_info *acl)
2548+{
2549+ const enum ccs_mac_index type = head->r.acl_index;
2550+ if (head->r.cond)
2551+ goto print_cond_part;
2552+ if (acl->is_deleted)
2553+ return true;
2554+ if (!ccs_flush(head))
2555+ return false;
2556+ ccs_io_printf(head, "%u ", acl->priority);
2557+ ccs_set_string(head, "acl ");
2558+ ccs_set_string(head, ccs_mac_keywords[type]);
2559+ if (acl->cond) {
2560+ head->r.cond_step = 0;
2561+print_cond_part:
2562+ if (!ccs_print_condition(head, acl->cond))
2563+ return false;
2564+ }
2565+ ccs_set_lf(head);
2566+ return true;
2567+}
2568+
2569+/**
2570+ * ccs_write_pid - Specify PID to obtain domainname.
2571+ *
2572+ * @head: Pointer to "struct ccs_io_buffer".
2573+ *
2574+ * Returns 0.
2575+ */
2576+static int ccs_write_pid(struct ccs_io_buffer *head)
2577+{
2578+ head->r.eof = false;
2579+ return 0;
2580+}
2581+
2582+/**
2583+ * ccs_read_pid - Read information of a process.
2584+ *
2585+ * @head: Pointer to "struct ccs_io_buffer".
2586+ *
2587+ * Returns nothing.
2588+ *
2589+ * Reads the domainname which the specified PID is in or
2590+ * process information of the specified PID on success.
2591+ *
2592+ * Caller holds ccs_read_lock().
2593+ */
2594+static void ccs_read_pid(struct ccs_io_buffer *head)
2595+{
2596+ char *buf = head->write_buf;
2597+ bool task_info = false;
2598+ bool global_pid = false;
2599+ unsigned int pid;
2600+ struct task_struct *p;
2601+ struct ccs_domain_info *domain = NULL;
2602+ u32 ccs_flags = 0;
2603+ /* Accessing write_buf is safe because head->io_sem is held. */
2604+ if (!buf) {
2605+ head->r.eof = true;
2606+ return; /* Do nothing if open(O_RDONLY). */
2607+ }
2608+ if (head->r.w_pos || head->r.eof)
2609+ return;
2610+ head->r.eof = true;
2611+ if (ccs_str_starts(&buf, "info "))
2612+ task_info = true;
2613+ if (ccs_str_starts(&buf, "global-pid "))
2614+ global_pid = true;
2615+ pid = (unsigned int) simple_strtoul(buf, NULL, 10);
2616+ ccs_tasklist_lock();
2617+ if (global_pid)
2618+ p = ccsecurity_exports.find_task_by_pid_ns(pid, &init_pid_ns);
2619+ else
2620+ p = ccsecurity_exports.find_task_by_vpid(pid);
2621+ if (p) {
2622+ domain = ccs_task_domain(p);
2623+ ccs_flags = ccs_task_flags(p);
2624+ }
2625+ ccs_tasklist_unlock();
2626+ if (!domain)
2627+ return;
2628+ if (!task_info) {
2629+ ccs_io_printf(head, "%u ", pid);
2630+ ccs_set_string(head, domain->domainname->name);
2631+ } else {
2632+ ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
2633+ ccs_yesno(ccs_flags &
2634+ CCS_TASK_IS_MANAGER),
2635+ ccs_yesno(ccs_flags &
2636+ CCS_TASK_IS_EXECUTE_HANDLER));
2637+ }
2638+}
2639+
2640+/**
2641+ * ccs_update_group - Update "struct ccs_string_group"/"struct ccs_number_group"/"struct ccs_ip_group" list.
2642+ *
2643+ * @head: Pointer to "struct ccs_io_buffer".
2644+ * @type: Type of this group.
2645+ *
2646+ * Returns 0 on success, negative value otherwise.
2647+ */
2648+static int ccs_update_group(struct ccs_io_buffer *head,
2649+ const enum ccs_group_id type)
2650+{
2651+ u8 size;
2652+ const bool is_delete = head->w.is_delete;
2653+ int error = is_delete ? -ENOENT : -ENOMEM;
2654+ struct ccs_group *group = ccs_get_group(head, type);
2655+ char *word = ccs_read_token(head);
2656+ union {
2657+ struct ccs_acl_head head;
2658+ struct ccs_string_group path;
2659+ struct ccs_number_group number;
2660+ struct ccs_ip_group address;
2661+ } e = { };
2662+ if (!group)
2663+ return -ENOMEM;
2664+ if (!*word) {
2665+ error = -EINVAL;
2666+ goto out;
2667+ }
2668+ if (type == CCS_STRING_GROUP) {
2669+ if (!ccs_correct_word(word)) {
2670+ error = -EINVAL;
2671+ goto out;
2672+ }
2673+ e.path.member_name = ccs_get_name(word);
2674+ if (!e.path.member_name) {
2675+ error = -ENOMEM;
2676+ goto out;
2677+ }
2678+ size = sizeof(e.path);
2679+ } else if (type == CCS_NUMBER_GROUP) {
2680+ e.number.radix = ccs_parse_values(word, e.number.value);
2681+ if (e.number.radix == CCS_VALUE_TYPE_INVALID)
2682+ goto out;
2683+ size = sizeof(e.number);
2684+ } else {
2685+#ifdef CONFIG_CCSECURITY_NETWORK
2686+ switch (ccs_parse_ipaddr(word, e.address.ip)) {
2687+ case CCS_ADDRESS_TYPE_IPV4:
2688+ case CCS_ADDRESS_TYPE_IPV4_RANGE:
2689+ e.address.is_ipv6 = false;
2690+ break;
2691+ case CCS_ADDRESS_TYPE_IPV6:
2692+ case CCS_ADDRESS_TYPE_IPV6_RANGE:
2693+ e.address.is_ipv6 = true;
2694+ break;
2695+ default:
2696+ goto out;
2697+ }
2698+ size = sizeof(e.address);
2699+#else
2700+ goto out;
2701+#endif
2702+ }
2703+ if (mutex_lock_interruptible(&ccs_policy_lock) == 0) {
2704+ struct ccs_acl_head *entry;
2705+ list_for_each_entry_srcu(entry, &group->member_list,
2706+ list, &ccs_ss) {
2707+ if (entry->is_deleted == CCS_GC_IN_PROGRESS ||
2708+ memcmp(entry + 1, &e.head + 1,
2709+ size - sizeof(*entry)))
2710+ continue;
2711+ entry->is_deleted = is_delete;
2712+ error = 0;
2713+ break;
2714+ }
2715+ if (error && !is_delete) {
2716+ entry = ccs_commit_ok(&e, size);
2717+ if (entry) {
2718+ list_add_tail_rcu(&entry->list,
2719+ &group->member_list);
2720+ error = 0;
2721+ }
2722+ }
2723+ mutex_unlock(&ccs_policy_lock);
2724+ }
2725+ if (type == CCS_STRING_GROUP)
2726+ ccs_put_name(e.path.member_name);
2727+out:
2728+ ccs_put_group(group);
2729+ return error;
2730+}
2731+
2732+/**
2733+ * ccs_write_policy - Write policy.
2734+ *
2735+ * @head: Pointer to "struct ccs_io_buffer".
2736+ *
2737+ * Returns 0 on success, negative value otherwise.
2738+ */
2739+static int ccs_write_policy(struct ccs_io_buffer *head)
2740+{
2741+ enum ccs_group_id i;
2742+ unsigned int priority;
2743+ char *word = ccs_read_token(head);
2744+ if (sscanf(word, "%u", &priority) == 1)
2745+ word = ccs_read_token(head);
2746+ else
2747+ priority = 1000;
2748+ if (priority >= 65536 || !*word)
2749+ return -EINVAL;
2750+ head->w.priority = priority;
2751+ if (!head->w.acl)
2752+ goto no_acl_selected;
2753+ head->w.is_deny = !strcmp(word, "deny");
2754+ if (head->w.is_deny || !strcmp(word, "allow"))
2755+ return ccs_update_acl(&head->w.acl->acl_info_list, head,
2756+ false);
2757+ if (!strcmp(word, "audit")) {
2758+ head->w.acl->audit = simple_strtoul(head->w.data, NULL, 10);
2759+ return 0;
2760+ }
2761+ head->w.acl = NULL;
2762+no_acl_selected:
2763+ if (ccs_select_acl(head, word))
2764+ return 0;
2765+ if (!strcmp(word, "acl"))
2766+ return ccs_parse_entry(head);
2767+ for (i = 0; i < CCS_MAX_GROUP; i++)
2768+ if (!strcmp(word, ccs_group_name[i]))
2769+ return ccs_update_group(head, i);
2770+ if (sscanf(word, "POLICY_VERSION=%u", &ccs_policy_version) == 1)
2771+ return 0;
2772+ if (strcmp(word, "quota"))
2773+ return -EINVAL;
2774+ if (ccs_str_starts(&head->w.data, "memory "))
2775+ return ccs_write_memory_quota(head->w.data);
2776+ return ccs_write_audit_quota(head->w.data);
2777+}
2778+
2779+/**
2780+ * ccs_read_subgroup - Read "struct ccs_string_group"/"struct ccs_number_group"/"struct ccs_ip_group" list.
2781+ *
2782+ * @head: Pointer to "struct ccs_io_buffer".
2783+ * @group: Pointer to "struct ccs_group".
2784+ * @idx: One of values in "enum ccs_group_id".
2785+ *
2786+ * Returns true on success, false otherwise.
2787+ *
2788+ * Caller holds ccs_read_lock().
2789+ */
2790+static bool ccs_read_subgroup(struct ccs_io_buffer *head,
2791+ struct ccs_group *group,
2792+ const enum ccs_group_id idx)
2793+{
2794+ list_for_each_cookie(head->r.acl, &group->member_list) {
2795+ struct ccs_acl_head *ptr =
2796+ list_entry(head->r.acl, typeof(*ptr), list);
2797+ if (ptr->is_deleted)
2798+ continue;
2799+ if (!ccs_flush(head))
2800+ return false;
2801+ ccs_set_string(head, ccs_group_name[idx]);
2802+ ccs_set_space(head);
2803+ ccs_set_string(head, group->group_name->name);
2804+ ccs_set_space(head);
2805+ if (idx == CCS_STRING_GROUP) {
2806+ ccs_set_string(head, container_of
2807+ (ptr, struct ccs_string_group,
2808+ head)->member_name->name);
2809+ } else if (idx == CCS_NUMBER_GROUP) {
2810+ struct ccs_number_group *e =
2811+ container_of(ptr, typeof(*e), head);
2812+ ccs_print_number(head, e->radix & 3, e->value[0]);
2813+ if (e->radix >> 2) {
2814+ ccs_set_string(head, "-");
2815+ ccs_print_number(head, (e->radix >> 2) & 3,
2816+ e->value[1]);
2817+ }
2818+#ifdef CONFIG_CCSECURITY_NETWORK
2819+ } else if (idx == CCS_IP_GROUP) {
2820+ ccs_print_ip(head, container_of
2821+ (ptr, struct ccs_ip_group, head));
2822+#endif
2823+ }
2824+ ccs_set_lf(head);
2825+ }
2826+ head->r.acl = NULL;
2827+ return true;
2828+}
2829+
2830+/**
2831+ * ccs_read_group - Read "struct ccs_string_group"/"struct ccs_number_group"/"struct ccs_ip_group" list.
2832+ *
2833+ * @head: Pointer to "struct ccs_io_buffer".
2834+ *
2835+ * Returns true on success, false otherwise.
2836+ *
2837+ * Caller holds ccs_read_lock().
2838+ */
2839+static bool ccs_read_group(struct ccs_io_buffer *head)
2840+{
2841+ while (head->r.step < CCS_MAX_GROUP) {
2842+ const enum ccs_group_id idx = head->r.step;
2843+ struct list_head *list = &ccs_group_list[idx];
2844+ list_for_each_cookie(head->r.group, list) {
2845+ struct ccs_group *group =
2846+ list_entry(head->r.group, typeof(*group),
2847+ head.list);
2848+ if (!ccs_read_subgroup(head, group, idx))
2849+ return false;
2850+ }
2851+ head->r.group = NULL;
2852+ head->r.step++;
2853+ }
2854+ head->r.step = 0;
2855+ return true;
2856+}
2857+
2858+/**
2859+ * ccs_supervisor - Ask for the supervisor's decision.
2860+ *
2861+ * @r: Pointer to "struct ccs_request_info".
2862+ *
2863+ * Returns 0 if the supervisor decided to permit the access request,
2864+ * CCS_RETRY_REQUEST if the supervisor decided to retry the access request,
2865+ * -EPERM otherwise.
2866+ */
2867+static int ccs_supervisor(struct ccs_request_info *r)
2868+{
2869+ int error = -EPERM;
2870+ int len;
2871+ static unsigned int ccs_serial;
2872+ struct ccs_query entry = { };
2873+ bool quota_exceeded = false;
2874+ if (!r->matched_acl)
2875+ return -EPERM;
2876+ /* Get message. */
2877+ entry.query = ccs_init_log(r);
2878+ if (!entry.query)
2879+ return -EPERM;
2880+ entry.query_len = strlen(entry.query) + 1;
2881+ len = ccs_round2(entry.query_len);
2882+ entry.acl = r->matched_acl;
2883+ spin_lock(&ccs_query_list_lock);
2884+ if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
2885+ ccs_memory_used[CCS_MEMORY_QUERY] + len
2886+ >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
2887+ quota_exceeded = true;
2888+ } else {
2889+ entry.serial = ccs_serial++;
2890+ entry.retry = r->retry;
2891+ ccs_memory_used[CCS_MEMORY_QUERY] += len;
2892+ list_add_tail(&entry.list, &ccs_query_list);
2893+ }
2894+ spin_unlock(&ccs_query_list_lock);
2895+ if (quota_exceeded)
2896+ goto out;
2897+ /* Give 10 seconds for supervisor's opinion. */
2898+ while (entry.timer < 10) {
2899+ wake_up_all(&ccs_query_wait);
2900+ if (wait_event_interruptible_timeout
2901+ (ccs_answer_wait, entry.answer ||
2902+ !atomic_read(&ccs_query_observers), HZ))
2903+ break;
2904+ else
2905+ entry.timer++;
2906+ }
2907+ spin_lock(&ccs_query_list_lock);
2908+ list_del(&entry.list);
2909+ ccs_memory_used[CCS_MEMORY_QUERY] -= len;
2910+ spin_unlock(&ccs_query_list_lock);
2911+ switch (entry.answer) {
2912+ case 3: /* Asked to retry by administrator. */
2913+ error = CCS_RETRY_REQUEST;
2914+ r->retry++;
2915+ break;
2916+ case 1:
2917+ /* Granted by administrator. */
2918+ error = 0;
2919+ break;
2920+ default:
2921+ /* Timed out or rejected by administrator. */
2922+ break;
2923+ }
2924+out:
2925+ kfree(entry.query);
2926+ return error;
2927+}
2928+
2929+/**
2930+ * ccs_audit_log - Audit permission check log.
2931+ *
2932+ * @r: Pointer to "struct ccs_request_info".
2933+ *
2934+ * Returns 0 to grant the request, CCS_RETRY_REQUEST to retry the permission
2935+ * check, -EPERM otherwise.
2936+ */
2937+int ccs_audit_log(struct ccs_request_info *r)
2938+{
2939+ /* Do not reject if not yet activated. */
2940+ if (!ccs_policy_loaded)
2941+ return 0;
2942+ /* Write /proc/ccs/audit unless quota exceeded. */
2943+ if (ccs_log_count[r->result] < ccs_log_quota[r->audit][r->result])
2944+ ccs_write_log(r);
2945+ /* Nothing more to do unless denied. */
2946+ if (r->result != CCS_MATCHING_DENIED)
2947+ return 0;
2948+ /* Update policy violation counter if denied. */
2949+ ccs_update_stat(CCS_STAT_REQUEST_DENIED);
2950+ /* Nothing more to do unless ccs-queryd is running. */
2951+ if (!atomic_read(&ccs_query_observers))
2952+ return -EPERM;
2953+ /* Ask the ccs-queryd for decision. */
2954+ return ccs_supervisor(r);
2955+}
2956+
2957+/**
2958+ * ccs_find_acl_by_qid - Get ACL by query id.
2959+ *
2960+ * @serial: Query ID assigned by ccs_supervisor().
2961+ *
2962+ * Returns pointer to "struct ccs_acl_info" if found, NULL otherwise.
2963+ */
2964+static struct ccs_acl_info *ccs_find_acl_by_qid(unsigned int serial)
2965+{
2966+ struct ccs_query *ptr;
2967+ struct ccs_acl_info *acl = NULL;
2968+ spin_lock(&ccs_query_list_lock);
2969+ list_for_each_entry(ptr, &ccs_query_list, list) {
2970+ if (ptr->serial != serial)
2971+ continue;
2972+ acl = ptr->acl;
2973+ break;
2974+ }
2975+ spin_unlock(&ccs_query_list_lock);
2976+ return acl;
2977+}
2978+
2979+/**
2980+ * ccs_read_query - Read access requests which violated policy in enforcing mode.
2981+ *
2982+ * @head: Pointer to "struct ccs_io_buffer".
2983+ *
2984+ * Returns nothing.
2985+ */
2986+static void ccs_read_query(struct ccs_io_buffer *head)
2987+{
2988+ struct list_head *tmp;
2989+ unsigned int pos = 0;
2990+ size_t len = 0;
2991+ char *buf;
2992+ if (head->r.w_pos)
2993+ return;
2994+ kfree(head->read_buf);
2995+ head->read_buf = NULL;
2996+ spin_lock(&ccs_query_list_lock);
2997+ list_for_each(tmp, &ccs_query_list) {
2998+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2999+ if (pos++ != head->r.query_index)
3000+ continue;
3001+ len = ptr->query_len;
3002+ break;
3003+ }
3004+ spin_unlock(&ccs_query_list_lock);
3005+ if (!len) {
3006+ head->r.query_index = 0;
3007+ return;
3008+ }
3009+ buf = kzalloc(len + 32, GFP_NOFS);
3010+ if (!buf)
3011+ return;
3012+ pos = 0;
3013+ spin_lock(&ccs_query_list_lock);
3014+ list_for_each(tmp, &ccs_query_list) {
3015+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
3016+ if (pos++ != head->r.query_index)
3017+ continue;
3018+ /*
3019+ * Some query can be skipped because ccs_query_list
3020+ * can change, but I don't care.
3021+ */
3022+ if (len == ptr->query_len)
3023+ snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
3024+ ptr->retry, ptr->query);
3025+ break;
3026+ }
3027+ spin_unlock(&ccs_query_list_lock);
3028+ if (buf[0]) {
3029+ head->read_buf = buf;
3030+ head->r.w[head->r.w_pos++] = buf;
3031+ head->r.query_index++;
3032+ } else {
3033+ kfree(buf);
3034+ }
3035+}
3036+
3037+/**
3038+ * ccs_write_answer - Write the supervisor's decision.
3039+ *
3040+ * @head: Pointer to "struct ccs_io_buffer".
3041+ *
3042+ * Returns 0 on success, -EINVAL otherwise.
3043+ */
3044+static int ccs_write_answer(struct ccs_io_buffer *head)
3045+{
3046+ char *data = head->write_buf;
3047+ struct list_head *tmp;
3048+ unsigned int serial;
3049+ unsigned int answer;
3050+ spin_lock(&ccs_query_list_lock);
3051+ list_for_each(tmp, &ccs_query_list) {
3052+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
3053+ ptr->timer = 0;
3054+ }
3055+ spin_unlock(&ccs_query_list_lock);
3056+ if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
3057+ return -EINVAL;
3058+ spin_lock(&ccs_query_list_lock);
3059+ list_for_each(tmp, &ccs_query_list) {
3060+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
3061+ if (ptr->serial != serial)
3062+ continue;
3063+ ptr->answer = (u8) answer;
3064+ /* Remove from ccs_query_list. */
3065+ if (ptr->answer) {
3066+ list_del(&ptr->list);
3067+ INIT_LIST_HEAD(&ptr->list);
3068+ }
3069+ break;
3070+ }
3071+ spin_unlock(&ccs_query_list_lock);
3072+ wake_up_all(&ccs_answer_wait);
3073+ return 0;
3074+}
3075+
3076+/**
3077+ * ccs_read_version - Get version.
3078+ *
3079+ * @head: Pointer to "struct ccs_io_buffer".
3080+ *
3081+ * Returns nothing.
3082+ */
3083+static void ccs_read_version(struct ccs_io_buffer *head)
3084+{
3085+ if (head->r.eof)
3086+ return;
3087+ ccs_set_string(head, "1.8.3");
3088+ head->r.eof = true;
3089+}
3090+
3091+/**
3092+ * ccs_update_stat - Update statistic counters.
3093+ *
3094+ * @index: Index for policy type.
3095+ *
3096+ * Returns nothing.
3097+ */
3098+static void ccs_update_stat(const u8 index)
3099+{
3100+ struct timeval tv;
3101+ do_gettimeofday(&tv);
3102+ /*
3103+ * I don't use atomic operations because race condition is not fatal.
3104+ */
3105+ ccs_stat_updated[index]++;
3106+ ccs_stat_modified[index] = tv.tv_sec;
3107+}
3108+
3109+/**
3110+ * ccs_read_stat - Read statistic data.
3111+ *
3112+ * @head: Pointer to "struct ccs_io_buffer".
3113+ *
3114+ * Returns nothing.
3115+ */
3116+static void ccs_read_stat(struct ccs_io_buffer *head)
3117+{
3118+ u8 i;
3119+ for (i = 0; i < CCS_MAX_POLICY_STAT; i++) {
3120+ static const char * const k[CCS_MAX_POLICY_STAT] = {
3121+ [CCS_STAT_POLICY_UPDATES] = "Policy updated:",
3122+ [CCS_STAT_REQUEST_DENIED] = "Requests denied:",
3123+ };
3124+ ccs_io_printf(head, "stat %s %u", k[i], ccs_stat_updated[i]);
3125+ if (ccs_stat_modified[i]) {
3126+ struct ccs_time stamp;
3127+ ccs_convert_time(ccs_stat_modified[i], &stamp);
3128+ ccs_io_printf(head, " (Last: %04u/%02u/%02u "
3129+ "%02u:%02u:%02u)",
3130+ stamp.year, stamp.month, stamp.day,
3131+ stamp.hour, stamp.min, stamp.sec);
3132+ }
3133+ ccs_set_lf(head);
3134+ }
3135+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++)
3136+ ccs_io_printf(head, "stat Memory used by %s: %u\n",
3137+ ccs_memory_headers[i], ccs_memory_used[i]);
3138+}
3139+
3140+/**
3141+ * ccs_read_quota - Read quota data.
3142+ *
3143+ * @head: Pointer to "struct ccs_io_buffer".
3144+ *
3145+ * Returns true on success, false otherwise.
3146+ */
3147+static bool ccs_read_quota(struct ccs_io_buffer *head)
3148+{
3149+ unsigned int i;
3150+ while (head->r.step < CCS_MAX_MEMORY_STAT) {
3151+ i = head->r.step++;
3152+ if (!ccs_memory_quota[i])
3153+ continue;
3154+ ccs_io_printf(head, "quota memory %s %u\n",
3155+ ccs_memory_headers[i], ccs_memory_quota[i]);
3156+ }
3157+ while (head->r.step < CCS_MAX_GROUP + CCS_MAX_MEMORY_STAT) {
3158+ unsigned int a;
3159+ unsigned int d;
3160+ unsigned int u;
3161+ if (!ccs_flush(head))
3162+ return false;
3163+ i = head->r.step - CCS_MAX_MEMORY_STAT;
3164+ a = ccs_log_quota[i][CCS_MATCHING_ALLOWED];
3165+ d = ccs_log_quota[i][CCS_MATCHING_DENIED];
3166+ u = ccs_log_quota[i][CCS_MATCHING_UNMATCHED];
3167+ if (a || d || u)
3168+ ccs_io_printf(head, "quota audit[%u] allowed=%u"
3169+ " denied=%u unmatched=%u\n", i, a, d, u);
3170+ head->r.step++;
3171+ }
3172+ head->r.step = 0;
3173+ return true;
3174+}
3175+
3176+/**
3177+ * ccs_write_memory_quota - Set memory quota.
3178+ *
3179+ * @data: Line to parse.
3180+ *
3181+ * Returns 0 on success, -EINVAL otherwise.
3182+ */
3183+static int ccs_write_memory_quota(char *data)
3184+{
3185+ u8 i;
3186+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++)
3187+ if (ccs_str_starts(&data, ccs_memory_headers[i])) {
3188+ if (*data == ' ')
3189+ data++;
3190+ ccs_memory_quota[i] =
3191+ simple_strtoul(data, NULL, 10);
3192+ return 0;
3193+ }
3194+ return -EINVAL;
3195+}
3196+
3197+/**
3198+ * ccs_write_audit_quota - Set audit log quota.
3199+ *
3200+ * @data: Line to parse.
3201+ *
3202+ * Returns 0 on success, -EINVAL otherwise.
3203+ */
3204+static int ccs_write_audit_quota(char *data)
3205+{
3206+ unsigned int i;
3207+ if (sscanf(data, "audit[%u]", &i) != 1 || i >= CCS_MAX_LOG_QUOTA)
3208+ return -EINVAL;
3209+ data = strchr(data, ' ');
3210+ if (!data++)
3211+ return -EINVAL;
3212+ while (1) {
3213+ unsigned int logs;
3214+ char *cp = strchr(data, ' ');
3215+ if (cp)
3216+ *cp++ = '\0';
3217+ if (sscanf(data, "allowed=%u", &logs) == 1)
3218+ ccs_log_quota[i][CCS_MATCHING_ALLOWED] = logs;
3219+ else if (sscanf(data, "denied=%u", &logs) == 1)
3220+ ccs_log_quota[i][CCS_MATCHING_DENIED] = logs;
3221+ else if (sscanf(data, "unmatched=%u", &logs) == 1)
3222+ ccs_log_quota[i][CCS_MATCHING_UNMATCHED] = logs;
3223+ if (!cp)
3224+ break;
3225+ data = cp;
3226+ }
3227+ return 0;
3228+}
3229+
3230+/**
3231+ * ccs_print_bprm - Print "struct linux_binprm" for auditing.
3232+ *
3233+ * @bprm: Pointer to "struct linux_binprm".
3234+ * @dump: Pointer to "struct ccs_page_dump".
3235+ *
3236+ * Returns the contents of @bprm on success, NULL otherwise.
3237+ *
3238+ * This function uses kzalloc(), so caller must kfree() if this function
3239+ * didn't return NULL.
3240+ */
3241+static char *ccs_print_bprm(struct linux_binprm *bprm,
3242+ struct ccs_page_dump *dump)
3243+{
3244+ static const int ccs_buffer_len = 4096 * 2;
3245+ char *buffer = kzalloc(ccs_buffer_len, GFP_NOFS);
3246+ char *cp;
3247+ char *last_start;
3248+ unsigned long pos = bprm->p;
3249+ int offset = pos % PAGE_SIZE;
3250+ int argv_count = bprm->argc;
3251+ int envp_count = bprm->envc;
3252+ bool skip = false;
3253+ bool env_value = false;
3254+ if (!buffer)
3255+ return NULL;
3256+ cp = buffer + snprintf(buffer, ccs_buffer_len - 1, " argc=%d envc=%d",
3257+ argv_count, envp_count);
3258+ last_start = cp;
3259+ while (argv_count || envp_count) {
3260+ if (!ccs_dump_page(bprm, pos, dump)) {
3261+ kfree(buffer);
3262+ return NULL;
3263+ }
3264+ pos += PAGE_SIZE - offset;
3265+ /* Read. */
3266+ while (offset < PAGE_SIZE) {
3267+ const char *kaddr = dump->data;
3268+ const unsigned char c = kaddr[offset++];
3269+ int len;
3270+ /* Check for end of buffer. */
3271+ if (skip) {
3272+ if (c)
3273+ continue;
3274+ goto reset;
3275+ }
3276+ len = buffer + ccs_buffer_len - cp - 1;
3277+ if (len <= 32 && c) {
3278+ cp = last_start;
3279+ skip = true;
3280+ continue;
3281+ }
3282+ /* Print argv[$index]=" or envp[" part. */
3283+ if (cp == last_start) {
3284+ int l;
3285+ if (argv_count)
3286+ l = snprintf(cp, len, " argv[%u]=\"",
3287+ bprm->argc - argv_count);
3288+ else
3289+ l = snprintf(cp, len, " envp[\"");
3290+ cp += l;
3291+ len -= l;
3292+ }
3293+ if (c > ' ' && c < 127 && c != '\\') {
3294+ /* Print "]=" part if printing environ. */
3295+ if (c == '=' && !argv_count && !env_value) {
3296+ cp += snprintf(cp, len, "\"]=\"");
3297+ env_value = true;
3298+ } else
3299+ *cp++ = c;
3300+ continue;
3301+ }
3302+ if (c) {
3303+ *cp++ = '\\';
3304+ *cp++ = (c >> 6) + '0';
3305+ *cp++ = ((c >> 3) & 7) + '0';
3306+ *cp++ = (c & 7) + '0';
3307+ continue;
3308+ }
3309+ /* Print "]=" part if not yet printed. */
3310+ if (!argv_count && !env_value)
3311+ cp += snprintf(cp, len, "\"]=\"");
3312+ *cp++ = '"';
3313+ last_start = cp;
3314+reset:
3315+ skip = false;
3316+ env_value = false;
3317+ if (argv_count)
3318+ argv_count--;
3319+ else if (envp_count)
3320+ envp_count--;
3321+ if (!argv_count && !envp_count)
3322+ break;
3323+ }
3324+ offset = 0;
3325+ }
3326+ *cp = '\0';
3327+ return buffer;
3328+}
3329+
3330+/**
3331+ * ccs_filetype - Get string representation of file type.
3332+ *
3333+ * @mode: Mode value for stat().
3334+ *
3335+ * Returns file type string.
3336+ */
3337+static inline const char *ccs_filetype(const umode_t mode)
3338+{
3339+ switch (mode & S_IFMT) {
3340+ case S_IFREG:
3341+ case 0:
3342+ return "file";
3343+ case S_IFDIR:
3344+ return "directory";
3345+ case S_IFLNK:
3346+ return "symlink";
3347+ case S_IFIFO:
3348+ return "fifo";
3349+ case S_IFSOCK:
3350+ return "socket";
3351+ case S_IFBLK:
3352+ return "block";
3353+ case S_IFCHR:
3354+ return "char";
3355+ }
3356+ return "unknown"; /* This should not happen. */
3357+}
3358+
3359+/**
3360+ * ccs_print_trailer - Get misc info of audit log.
3361+ *
3362+ * @r: Pointer to "struct ccs_request_info".
3363+ *
3364+ * Returns string representation.
3365+ *
3366+ * This function uses kmalloc(), so caller must kfree() if this function
3367+ * didn't return NULL.
3368+ */
3369+static char *ccs_print_trailer(struct ccs_request_info *r)
3370+{
3371+ const char *handler =
3372+ ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER ? "" : "!";
3373+ const char *exe = r->exename.name;
3374+ const char *domain = ccs_current_domain()->domainname->name;
3375+ const int ccs_buffer_len = 2000 + strlen(exe) + strlen(domain);
3376+ char *buffer = kmalloc(ccs_buffer_len, GFP_NOFS);
3377+ int pos;
3378+ u8 i;
3379+ if (!buffer)
3380+ return NULL;
3381+ pos = snprintf(buffer, ccs_buffer_len - 1, " task.pid=%u task.ppid=%u"
3382+ " task.uid=%u task.gid=%u task.euid=%u task.egid=%u"
3383+ " task.suid=%u task.sgid=%u task.fsuid=%u task.fsgid=%u"
3384+ " task.type%s=execute_handler task.exe=\"%s\""
3385+ " task.domain=\"%s\"", ccs_sys_getpid(),
3386+ ccs_sys_getppid(), current_uid(), current_gid(),
3387+ current_euid(), current_egid(), current_suid(),
3388+ current_sgid(), current_fsuid(), current_fsgid(),
3389+ handler, exe, domain);
3390+ if (!r->obj.path[0].dentry && !r->obj.path[1].dentry)
3391+ goto no_obj_info;
3392+ ccs_get_attributes(r);
3393+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
3394+ char objname[32];
3395+ struct ccs_mini_stat *stat;
3396+ unsigned int dev;
3397+ umode_t mode;
3398+ if (!r->obj.stat_valid[i])
3399+ continue;
3400+ stat = &r->obj.stat[i];
3401+ dev = stat->dev;
3402+ mode = stat->mode;
3403+ memset(objname, 0, sizeof(objname));
3404+ snprintf(objname, sizeof(objname) - 1, "%s%s.",
3405+ ccs_get_sarg(r->type, (i >> 1)),
3406+ i & 1 ? ".parent" : "");
3407+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
3408+ " %suid=%u %sgid=%u %sino=%lu %smajor=%u"
3409+ " %sminor=%u %sperm=0%o %stype=%s"
3410+ " %sfsmagic=0x%lX", objname, stat->uid,
3411+ objname, stat->gid, objname, (unsigned long)
3412+ stat->ino, objname, MAJOR(dev), objname,
3413+ MINOR(dev), objname, mode & S_IALLUGO, objname,
3414+ ccs_filetype(mode), objname, stat->fsmagic);
3415+ if (S_ISCHR(mode) || S_ISBLK(mode)) {
3416+ dev = stat->rdev;
3417+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
3418+ " %sdev_major=%u %sdev_minor=%u",
3419+ objname, MAJOR(dev), objname,
3420+ MINOR(dev));
3421+ }
3422+ }
3423+no_obj_info:
3424+ if (pos < ccs_buffer_len - 1)
3425+ return buffer;
3426+ kfree(buffer);
3427+ return NULL;
3428+}
3429+
3430+/**
3431+ * ccs_print_param - Get arg info of audit log.
3432+ *
3433+ * @r: Pointer to "struct ccs_request_info".
3434+ * @buf: Buffer to write.
3435+ * @len: Size of @buf in bytes.
3436+ */
3437+static int ccs_print_param(struct ccs_request_info *r, char *buf, int len)
3438+{
3439+#ifdef CONFIG_CCSECURITY_NETWORK
3440+ /* Make sure that IP address argument is ready. */
3441+ char ip[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
3442+ switch (r->type) {
3443+ case CCS_MAC_INET_STREAM_BIND:
3444+ case CCS_MAC_INET_STREAM_LISTEN:
3445+ case CCS_MAC_INET_STREAM_CONNECT:
3446+ case CCS_MAC_INET_STREAM_ACCEPT:
3447+ case CCS_MAC_INET_DGRAM_BIND:
3448+ case CCS_MAC_INET_DGRAM_SEND:
3449+ case CCS_MAC_INET_RAW_BIND:
3450+ case CCS_MAC_INET_RAW_SEND:
3451+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3452+ case CCS_MAC_INET_DGRAM_RECV:
3453+ case CCS_MAC_INET_RAW_RECV:
3454+#endif
3455+ if (!r->param.ip)
3456+ return 0;
3457+ if (r->param.is_ipv6) {
3458+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
3459+ snprintf(ip, sizeof(ip), "%pI6c",
3460+ (const struct in6_addr *) r->param.ip);
3461+#else
3462+ ip6_compressed_string(ip, (const u8 *) r->param.ip);
3463+#endif
3464+ } else {
3465+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
3466+ snprintf(ip, sizeof(ip), "%pI4", r->param.ip);
3467+#else
3468+ ip4_string(ip, r->param.ip);
3469+#endif
3470+ }
3471+ break;
3472+ default:
3473+ break;
3474+ }
3475+#endif
3476+ /* Make sure that string arguments are ready. */
3477+ if (!r->param.s[0] && r->obj.path[0].dentry) {
3478+ ccs_populate_patharg(r, true);
3479+ if (!r->param.s[0])
3480+ return 0;
3481+ }
3482+ if (!r->param.s[1] && r->obj.path[1].dentry) {
3483+ ccs_populate_patharg(r, false);
3484+ if (!r->param.s[1])
3485+ return 0;
3486+ }
3487+ switch (r->type) {
3488+ int pos;
3489+ u8 i;
3490+ case CCS_MAC_EXECUTE:
3491+ return snprintf(buf, len, " exec=\"%s\" path=\"%s\"",
3492+ r->param.s[1]->name, r->param.s[0]->name);
3493+ case CCS_MAC_READ:
3494+ case CCS_MAC_WRITE:
3495+ case CCS_MAC_APPEND:
3496+ case CCS_MAC_UNLINK:
3497+#ifdef CONFIG_CCSECURITY_GETATTR
3498+ case CCS_MAC_GETATTR:
3499+#endif
3500+ case CCS_MAC_RMDIR:
3501+ case CCS_MAC_TRUNCATE:
3502+ case CCS_MAC_CHROOT:
3503+ return snprintf(buf, len, " path=\"%s\"", r->param.s[0]->name);
3504+ case CCS_MAC_CREATE:
3505+ case CCS_MAC_MKDIR:
3506+ case CCS_MAC_MKFIFO:
3507+ case CCS_MAC_MKSOCK:
3508+ return snprintf(buf, len, " path=\"%s\" perm=0%lo",
3509+ r->param.s[0]->name, r->param.i[0]);
3510+ case CCS_MAC_SYMLINK:
3511+ return snprintf(buf, len, " path=\"%s\" target=\"%s\"",
3512+ r->param.s[0]->name, r->param.s[1]->name);
3513+ case CCS_MAC_MKBLOCK:
3514+ case CCS_MAC_MKCHAR:
3515+ return snprintf(buf, len, " path=\"%s\" perm=0%lo "
3516+ "dev_major=%lu dev_minor=%lu",
3517+ r->param.s[0]->name, r->param.i[0],
3518+ r->param.i[1], r->param.i[2]);
3519+ case CCS_MAC_LINK:
3520+ case CCS_MAC_RENAME:
3521+ return snprintf(buf, len, " old_path=\"%s\" new_path=\"%s\"",
3522+ r->param.s[0]->name, r->param.s[1]->name);
3523+ case CCS_MAC_CHMOD:
3524+ return snprintf(buf, len, " path=\"%s\" perm=0%lo",
3525+ r->param.s[0]->name, r->param.i[0]);
3526+ case CCS_MAC_CHOWN:
3527+ return snprintf(buf, len, " path=\"%s\" uid=%lu",
3528+ r->param.s[0]->name, r->param.i[0]);
3529+ case CCS_MAC_CHGRP:
3530+ return snprintf(buf, len, " path=\"%s\" gid=%lu",
3531+ r->param.s[0]->name, r->param.i[0]);
3532+ case CCS_MAC_IOCTL:
3533+ return snprintf(buf, len, " path=\"%s\" cmd=0x%lX",
3534+ r->param.s[0]->name, r->param.i[0]);
3535+ case CCS_MAC_MOUNT:
3536+ pos = 0;
3537+ for (i = 0; i < 4; i++) {
3538+ if (i == 3)
3539+ pos += snprintf(buf + pos, pos < len ?
3540+ len - pos : 0, " flags=0x%lX",
3541+ r->param.i[0]);
3542+ if (!r->param.s[i])
3543+ continue;
3544+ pos += snprintf(buf + pos, pos < len ? len - pos : 0,
3545+ " %s=\"%s\"",
3546+ ccs_get_sarg(CCS_MAC_MOUNT, i),
3547+ r->param.s[i]->name);
3548+ }
3549+ return pos;
3550+ case CCS_MAC_UMOUNT:
3551+ return snprintf(buf, len, " path=\"%s\" flags=0x%lX",
3552+ r->param.s[0]->name, r->param.i[0]);
3553+ case CCS_MAC_PIVOT_ROOT:
3554+ return snprintf(buf, len, " new_root=\"%s\" put_old=\"%s\"",
3555+ r->param.s[0]->name, r->param.s[1]->name);
3556+#ifdef CONFIG_CCSECURITY_ENVIRON
3557+ case CCS_MAC_ENVIRON:
3558+ return snprintf(buf, len, " name=\"%s\" value=\"%s\""
3559+ " exec=\"%s\" path=\"%s\"",
3560+ r->param.s[2]->name, r->param.s[3]->name,
3561+ r->param.s[1]->name, r->param.s[0]->name);
3562+#endif
3563+#ifdef CONFIG_CCSECURITY_NETWORK
3564+ case CCS_MAC_INET_STREAM_BIND:
3565+ case CCS_MAC_INET_STREAM_LISTEN:
3566+ case CCS_MAC_INET_STREAM_CONNECT:
3567+ case CCS_MAC_INET_STREAM_ACCEPT:
3568+ case CCS_MAC_INET_DGRAM_BIND:
3569+ case CCS_MAC_INET_DGRAM_SEND:
3570+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3571+ case CCS_MAC_INET_DGRAM_RECV:
3572+#endif
3573+ return snprintf(buf, len, " ip=%s port=%lu", ip,
3574+ r->param.i[0]);
3575+ case CCS_MAC_INET_RAW_BIND:
3576+ case CCS_MAC_INET_RAW_SEND:
3577+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3578+ case CCS_MAC_INET_RAW_RECV:
3579+#endif
3580+ return snprintf(buf, len, " ip=%s proto=%lu", ip,
3581+ r->param.i[0]);
3582+ case CCS_MAC_UNIX_STREAM_BIND:
3583+ case CCS_MAC_UNIX_STREAM_LISTEN:
3584+ case CCS_MAC_UNIX_STREAM_CONNECT:
3585+ case CCS_MAC_UNIX_STREAM_ACCEPT:
3586+ case CCS_MAC_UNIX_DGRAM_BIND:
3587+ case CCS_MAC_UNIX_DGRAM_SEND:
3588+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3589+ case CCS_MAC_UNIX_DGRAM_RECV:
3590+#endif
3591+ case CCS_MAC_UNIX_SEQPACKET_BIND:
3592+ case CCS_MAC_UNIX_SEQPACKET_LISTEN:
3593+ case CCS_MAC_UNIX_SEQPACKET_CONNECT:
3594+ case CCS_MAC_UNIX_SEQPACKET_ACCEPT:
3595+ return snprintf(buf, len, " addr=\"%s\"", r->param.s[0]->name);
3596+#endif
3597+#ifdef CONFIG_CCSECURITY_PTRACE
3598+ case CCS_MAC_PTRACE:
3599+ return snprintf(buf, len, " cmd=%lu domain=\"%s\"",
3600+ r->param.i[0], r->param.s[0]->name);
3601+#endif
3602+#ifdef CONFIG_CCSECURITY_SIGNAL
3603+ case CCS_MAC_SIGNAL:
3604+ return snprintf(buf, len, " sig=%lu", r->param.i[0]);
3605+#endif
3606+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
3607+ case CCS_MAC_MANUAL_DOMAIN_TRANSITION:
3608+ return snprintf(buf, len, " domain=\"%s\"",
3609+ r->param.s[0]->name);
3610+#endif
3611+ default:
3612+ break;
3613+ }
3614+ return 0;
3615+}
3616+
3617+/**
3618+ * ccs_init_log - Allocate buffer for audit logs.
3619+ *
3620+ * @r: Pointer to "struct ccs_request_info".
3621+ *
3622+ * Returns pointer to allocated memory.
3623+ *
3624+ * This function uses kzalloc(), so caller must kfree() if this function
3625+ * didn't return NULL.
3626+ */
3627+static char *ccs_init_log(struct ccs_request_info *r)
3628+{
3629+ const pid_t gpid = task_pid_nr(current);
3630+ struct timeval tv;
3631+ struct ccs_time stamp;
3632+ static const char * const k[CCS_MAX_MATCHING] = {
3633+ [CCS_MATCHING_UNMATCHED] = "unmatched",
3634+ [CCS_MATCHING_ALLOWED] = "allowed",
3635+ [CCS_MATCHING_DENIED] = "denied",
3636+ };
3637+ char *buf;
3638+ const char *bprm_info;
3639+ const char *trailer;
3640+ int len;
3641+ if (!r->exename.name && !ccs_get_exename(&r->exename))
3642+ return NULL;
3643+ do_gettimeofday(&tv);
3644+ ccs_convert_time(tv.tv_sec, &stamp);
3645+ trailer = ccs_print_trailer(r);
3646+ if (r->bprm)
3647+ bprm_info = ccs_print_bprm(r->bprm, &r->dump);
3648+ else
3649+ bprm_info = NULL;
3650+ len = 0;
3651+ while (1) {
3652+ int pos;
3653+ buf = kzalloc(len, GFP_NOFS);
3654+ if (!buf)
3655+ break;
3656+ pos = snprintf(buf, len, "#%04u/%02u/%02u %02u:%02u:%02u# "
3657+ "global-pid=%u result=%s priority=%u / %s",
3658+ stamp.year, stamp.month, stamp.day, stamp.hour,
3659+ stamp.min, stamp.sec, gpid, k[r->result],
3660+ r->matched_acl ? r->matched_acl->priority : 0,
3661+ ccs_mac_keywords[r->type]);
3662+ pos += ccs_print_param(r, buf + pos,
3663+ pos < len ? len - pos : 0);
3664+ if (bprm_info)
3665+ pos += snprintf(buf + pos, pos < len ? len - pos : 0,
3666+ "%s", bprm_info);
3667+ if (trailer)
3668+ pos += snprintf(buf + pos, pos < len ? len - pos : 0,
3669+ "%s", trailer);
3670+ pos += snprintf(buf + pos, pos < len ? len - pos : 0,
3671+ "\n") + 1;
3672+ if (pos <= len)
3673+ break;
3674+ kfree(buf);
3675+ len = pos;
3676+ }
3677+ kfree(bprm_info);
3678+ kfree(trailer);
3679+ return buf;
3680+}
3681+
3682+/**
3683+ * ccs_write_log - Write an audit log.
3684+ *
3685+ * @r: Pointer to "struct ccs_request_info".
3686+ *
3687+ * Returns nothing.
3688+ */
3689+static void ccs_write_log(struct ccs_request_info *r)
3690+{
3691+ struct ccs_log *entry;
3692+ bool quota_exceeded = false;
3693+ int len;
3694+ char *buf = ccs_init_log(r);
3695+ if (!buf)
3696+ return;
3697+ entry = kzalloc(sizeof(*entry), GFP_NOFS);
3698+ if (!entry) {
3699+ kfree(buf);
3700+ return;
3701+ }
3702+ entry->log = buf;
3703+ len = ccs_round2(strlen(buf) + 1);
3704+ /*
3705+ * The entry->size is used for memory quota checks.
3706+ * Don't go beyond strlen(entry->log).
3707+ */
3708+ entry->size = len + ccs_round2(sizeof(*entry));
3709+ entry->result = r->result;
3710+ spin_lock(&ccs_log_lock);
3711+ if (ccs_memory_quota[CCS_MEMORY_AUDIT] &&
3712+ ccs_memory_used[CCS_MEMORY_AUDIT] + entry->size >=
3713+ ccs_memory_quota[CCS_MEMORY_AUDIT]) {
3714+ quota_exceeded = true;
3715+ } else {
3716+ ccs_memory_used[CCS_MEMORY_AUDIT] += entry->size;
3717+ list_add_tail(&entry->list, &ccs_log);
3718+ ccs_log_count[entry->result]++;
3719+ }
3720+ spin_unlock(&ccs_log_lock);
3721+ if (quota_exceeded) {
3722+ kfree(buf);
3723+ kfree(entry);
3724+ return;
3725+ }
3726+ wake_up(&ccs_log_wait);
3727+}
3728+
3729+/**
3730+ * ccs_read_log - Read an audit log.
3731+ *
3732+ * @head: Pointer to "struct ccs_io_buffer".
3733+ *
3734+ * Returns nothing.
3735+ */
3736+static void ccs_read_log(struct ccs_io_buffer *head)
3737+{
3738+ struct ccs_log *ptr = NULL;
3739+ if (head->r.w_pos)
3740+ return;
3741+ kfree(head->read_buf);
3742+ head->read_buf = NULL;
3743+ spin_lock(&ccs_log_lock);
3744+ if (!list_empty(&ccs_log)) {
3745+ ptr = list_entry(ccs_log.next, typeof(*ptr), list);
3746+ list_del(&ptr->list);
3747+ ccs_log_count[ptr->result]--;
3748+ ccs_memory_used[CCS_MEMORY_AUDIT] -= ptr->size;
3749+ }
3750+ spin_unlock(&ccs_log_lock);
3751+ if (ptr) {
3752+ head->read_buf = ptr->log;
3753+ head->r.w[head->r.w_pos++] = head->read_buf;
3754+ kfree(ptr);
3755+ }
3756+}
3757+
3758+/**
3759+ * ccs_transit_domain - Transit to other domain.
3760+ *
3761+ * @domainname: The name of domain.
3762+ *
3763+ * Returns true on success, false otherwise.
3764+ *
3765+ * Caller holds ccs_read_lock().
3766+ */
3767+bool ccs_transit_domain(const char *domainname)
3768+{
3769+ struct ccs_security *security = ccs_current_security();
3770+ struct ccs_domain_info e = { };
3771+ struct ccs_domain_info *entry = ccs_find_domain(domainname);
3772+ if (entry) {
3773+ security->ccs_domain_info = entry;
3774+ return true;
3775+ }
3776+ /* Requested domain does not exist. */
3777+ /* Don't create requested domain if domainname is invalid. */
3778+ if (!ccs_correct_domain(domainname))
3779+ return false;
3780+ e.domainname = ccs_get_name(domainname);
3781+ if (!e.domainname)
3782+ return false;
3783+ if (mutex_lock_interruptible(&ccs_policy_lock))
3784+ goto out;
3785+ entry = ccs_find_domain(domainname);
3786+ if (entry)
3787+ goto done;
3788+ entry = ccs_commit_ok(&e, sizeof(e));
3789+ if (!entry)
3790+ goto done;
3791+ list_add_tail_rcu(&entry->list, &ccs_domain_list);
3792+done:
3793+ mutex_unlock(&ccs_policy_lock);
3794+out:
3795+ ccs_put_name(e.domainname);
3796+ if (entry)
3797+ security->ccs_domain_info = entry;
3798+ return entry != NULL;
3799+}
3800+
3801+/**
3802+ * ccs_parse_policy - Parse a policy line.
3803+ *
3804+ * @head: Poiter to "struct ccs_io_buffer".
3805+ * @line: Line to parse.
3806+ *
3807+ * Returns 0 on success, negative value otherwise.
3808+ *
3809+ * Caller holds ccs_read_lock().
3810+ */
3811+static int ccs_parse_policy(struct ccs_io_buffer *head, char *line)
3812+{
3813+ /* Set current line's content. */
3814+ head->w.data = line;
3815+ head->w.is_deny = false;
3816+ head->w.priority = 0;
3817+ /* Delete request? */
3818+ head->w.is_delete = !strncmp(line, "delete ", 7);
3819+ if (head->w.is_delete)
3820+ memmove(line, line + 7, strlen(line + 7) + 1);
3821+ /* Do the update. */
3822+ switch (head->type) {
3823+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
3824+ case CCS_EXECUTE_HANDLER:
3825+#endif
3826+ case CCS_PROCESS_STATUS:
3827+ return ccs_write_pid(head);
3828+ case CCS_QUERY:
3829+ return ccs_write_answer(head);
3830+ case CCS_POLICY:
3831+ return ccs_write_policy(head);
3832+ default:
3833+ return -ENOSYS;
3834+ }
3835+}
3836+
3837+/**
3838+ * ccs_policy_io_init - Register hooks for policy I/O.
3839+ *
3840+ * Returns nothing.
3841+ */
3842+static void __init ccs_policy_io_init(void)
3843+{
3844+ ccsecurity_ops.check_profile = ccs_check_profile;
3845+}
3846+
3847+/**
3848+ * ccs_load_builtin_policy - Load built-in policy.
3849+ *
3850+ * Returns nothing.
3851+ */
3852+static void __init ccs_load_builtin_policy(void)
3853+{
3854+ /*
3855+ * This include file is manually created and contains built-in policy.
3856+ *
3857+ * static char [] __initdata ccs_builtin_policy = { ... };
3858+ */
3859+#include "builtin-policy.h"
3860+ const int idx = ccs_read_lock();
3861+ struct ccs_io_buffer head = { };
3862+ char *start = ccs_builtin_policy;
3863+ head.type = CCS_POLICY;
3864+ while (1) {
3865+ char *end = strchr(start, '\n');
3866+ if (!end)
3867+ break;
3868+ *end = '\0';
3869+ ccs_normalize_line(start);
3870+ head.write_buf = start;
3871+ ccs_parse_policy(&head, start);
3872+ start = end + 1;
3873+ }
3874+ ccs_read_unlock(idx);
3875+#ifdef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
3876+ ccs_check_profile();
3877+#endif
3878+}
3879+
3880+/**
3881+ * ccs_read_self - read() for /proc/ccs/self_domain interface.
3882+ *
3883+ * @file: Pointer to "struct file".
3884+ * @buf: Domainname which current thread belongs to.
3885+ * @count: Size of @buf.
3886+ * @ppos: Bytes read by now.
3887+ *
3888+ * Returns read size on success, negative value otherwise.
3889+ */
3890+static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
3891+ loff_t *ppos)
3892+{
3893+ const char *domain = ccs_current_domain()->domainname->name;
3894+ loff_t len = strlen(domain);
3895+ loff_t pos = *ppos;
3896+ if (pos >= len || !count)
3897+ return 0;
3898+ len -= pos;
3899+ if (count < len)
3900+ len = count;
3901+ if (copy_to_user(buf, domain + pos, len))
3902+ return -EFAULT;
3903+ *ppos += len;
3904+ return len;
3905+}
3906+
3907+/**
3908+ * ccs_read_subacl - Read sub ACL in ACL entry.
3909+ *
3910+ * @head: Pointer to "struct ccs_io_buffer".
3911+ * @list: Pointer to "struct list_head".
3912+ *
3913+ * Returns true on success, false otherwise.
3914+ *
3915+ * Caller holds ccs_read_lock().
3916+ */
3917+static bool ccs_read_subacl(struct ccs_io_buffer *head,
3918+ const struct list_head *list)
3919+{
3920+ list_for_each_cookie(head->r.subacl, list) {
3921+ struct ccs_acl_info *acl =
3922+ list_entry(head->r.subacl, typeof(*acl), list);
3923+ switch (head->r.step) {
3924+ case 3:
3925+ if (acl->is_deleted)
3926+ continue;
3927+ if (!ccs_flush(head))
3928+ return false;
3929+ ccs_io_printf(head, " %u ", acl->priority);
3930+ if (acl->is_deny)
3931+ ccs_set_string(head, "deny");
3932+ else
3933+ ccs_set_string(head, "allow");
3934+ head->r.cond_step = 0;
3935+ head->r.step++;
3936+ /* fall through */
3937+ case 4:
3938+ if (!ccs_flush(head))
3939+ return false;
3940+ if (acl->cond &&
3941+ !ccs_print_condition(head, acl->cond))
3942+ return false;
3943+ ccs_set_lf(head);
3944+ head->r.step--;
3945+ }
3946+ }
3947+ head->r.subacl = NULL;
3948+ return true;
3949+}
3950+
3951+/**
3952+ * ccs_read_policy - Read policy.
3953+ *
3954+ * @head: Pointer to "struct ccs_io_buffer".
3955+ *
3956+ * Caller holds ccs_read_lock().
3957+ */
3958+static void ccs_read_policy(struct ccs_io_buffer *head)
3959+{
3960+ if (head->r.eof)
3961+ return;
3962+ if (head->r.print_this_acl_only)
3963+ goto skip;
3964+ if (!head->r.version_done) {
3965+ ccs_io_printf(head, "POLICY_VERSION=%u\n", ccs_policy_version);
3966+ head->r.version_done = true;
3967+ }
3968+ if (!head->r.stat_done) {
3969+ ccs_read_stat(head);
3970+ head->r.stat_done = true;
3971+ }
3972+ if (!head->r.quota_done) {
3973+ if (!ccs_read_quota(head))
3974+ return;
3975+ head->r.quota_done = true;
3976+ }
3977+ if (!head->r.group_done) {
3978+ if (!ccs_read_group(head))
3979+ return;
3980+ head->r.group_done = true;
3981+ ccs_set_lf(head);
3982+ }
3983+ while (head->r.acl_index < CCS_MAX_MAC_INDEX) {
3984+ struct list_head * const list =
3985+ &ccs_acl_list[head->r.acl_index];
3986+ list_for_each_cookie(head->r.acl, list) {
3987+ struct ccs_acl_info *ptr;
3988+skip:
3989+ ptr = list_entry(head->r.acl, typeof(*ptr), list);
3990+ switch (head->r.step) {
3991+ case 0:
3992+ if (ptr->is_deleted &&
3993+ !head->r.print_this_acl_only)
3994+ continue;
3995+ head->r.step++;
3996+ /* fall through */
3997+ case 1:
3998+ if (!ccs_read_acl(head, ptr))
3999+ return;
4000+ head->r.step++;
4001+ /* fall through */
4002+ case 2:
4003+ if (!ccs_flush(head))
4004+ return;
4005+ ccs_io_printf(head, " audit %u\n",
4006+ ptr->audit);
4007+ head->r.step++;
4008+ /* fall through */
4009+ case 3:
4010+ case 4:
4011+ if (!ccs_read_subacl(head,
4012+ &ptr->acl_info_list))
4013+ return;
4014+ head->r.step = 5;
4015+ /* fall through */
4016+ case 5:
4017+ if (!ccs_flush(head))
4018+ return;
4019+ ccs_set_lf(head);
4020+ head->r.step = 0;
4021+ if (head->r.print_this_acl_only)
4022+ goto done;
4023+ }
4024+ }
4025+ head->r.acl = NULL;
4026+ head->r.acl_index++;
4027+ }
4028+done:
4029+ head->r.eof = true;
4030+}
4031+
4032+/**
4033+ * ccs_open - open() for /proc/ccs/ interface.
4034+ *
4035+ * @inode: Pointer to "struct inode".
4036+ * @file: Pointer to "struct file".
4037+ *
4038+ * Returns 0 on success, negative value otherwise.
4039+ */
4040+static int ccs_open(struct inode *inode, struct file *file)
4041+{
4042+ const u8 type = (unsigned long) PDE(inode)->data;
4043+ struct ccs_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
4044+ if (!head)
4045+ return -ENOMEM;
4046+ mutex_init(&head->io_sem);
4047+ head->type = type;
4048+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
4049+ if (type == CCS_EXECUTE_HANDLER) {
4050+ /* Allow execute_handler to read process's status. */
4051+ if (!(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
4052+ kfree(head);
4053+ return -EPERM;
4054+ }
4055+ }
4056+#endif
4057+ if ((file->f_mode & FMODE_READ) && type != CCS_AUDIT &&
4058+ type != CCS_QUERY) {
4059+ /* Don't allocate read_buf for poll() access. */
4060+ head->readbuf_size = 4096;
4061+ head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
4062+ if (!head->read_buf) {
4063+ kfree(head);
4064+ return -ENOMEM;
4065+ }
4066+ }
4067+ if (file->f_mode & FMODE_WRITE) {
4068+ head->writebuf_size = 4096;
4069+ head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS);
4070+ if (!head->write_buf) {
4071+ kfree(head->read_buf);
4072+ kfree(head);
4073+ return -ENOMEM;
4074+ }
4075+ }
4076+ /*
4077+ * If the file is /proc/ccs/query, increment the observer counter.
4078+ * The obserber counter is used by ccs_supervisor() to see if
4079+ * there is some process monitoring /proc/ccs/query.
4080+ */
4081+ if (type == CCS_QUERY)
4082+ atomic_inc(&ccs_query_observers);
4083+ file->private_data = head;
4084+ ccs_notify_gc(head, true);
4085+ return 0;
4086+}
4087+
4088+/**
4089+ * ccs_release - close() for /proc/ccs/ interface.
4090+ *
4091+ * @inode: Pointer to "struct inode".
4092+ * @file: Pointer to "struct file".
4093+ *
4094+ * Returns 0.
4095+ */
4096+static int ccs_release(struct inode *inode, struct file *file)
4097+{
4098+ struct ccs_io_buffer *head = file->private_data;
4099+ /*
4100+ * If the file is /proc/ccs/query, decrement the observer counter.
4101+ */
4102+ if (head->type == CCS_QUERY &&
4103+ atomic_dec_and_test(&ccs_query_observers))
4104+ wake_up_all(&ccs_answer_wait);
4105+ ccs_notify_gc(head, false);
4106+ return 0;
4107+}
4108+
4109+/**
4110+ * ccs_poll - poll() for /proc/ccs/ interface.
4111+ *
4112+ * @file: Pointer to "struct file".
4113+ * @wait: Pointer to "poll_table". Maybe NULL.
4114+ *
4115+ * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
4116+ * POLLOUT | POLLWRNORM otherwise.
4117+ */
4118+static unsigned int ccs_poll(struct file *file, poll_table *wait)
4119+{
4120+ struct ccs_io_buffer *head = file->private_data;
4121+ if (head->type == CCS_AUDIT) {
4122+ if (!ccs_memory_used[CCS_MEMORY_AUDIT]) {
4123+ poll_wait(file, &ccs_log_wait, wait);
4124+ if (!ccs_memory_used[CCS_MEMORY_AUDIT])
4125+ return POLLOUT | POLLWRNORM;
4126+ }
4127+ } else if (head->type == CCS_QUERY) {
4128+ if (list_empty(&ccs_query_list)) {
4129+ poll_wait(file, &ccs_query_wait, wait);
4130+ if (list_empty(&ccs_query_list))
4131+ return POLLOUT | POLLWRNORM;
4132+ }
4133+ }
4134+ return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
4135+}
4136+
4137+/**
4138+ * ccs_read - read() for /proc/ccs/ interface.
4139+ *
4140+ * @file: Pointer to "struct file".
4141+ * @buf: Pointer to buffer.
4142+ * @count: Size of @buf.
4143+ * @ppos: Unused.
4144+ *
4145+ * Returns bytes read on success, negative value otherwise.
4146+ */
4147+static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
4148+ loff_t *ppos)
4149+{
4150+ struct ccs_io_buffer *head = file->private_data;
4151+ int len;
4152+ int idx;
4153+ if (mutex_lock_interruptible(&head->io_sem))
4154+ return -EINTR;
4155+ head->read_user_buf = buf;
4156+ head->read_user_buf_avail = count;
4157+ idx = ccs_read_lock();
4158+ if (ccs_flush(head)) {
4159+ /* Call the policy handler. */
4160+ switch (head->type) {
4161+ case CCS_AUDIT:
4162+ ccs_read_log(head);
4163+ break;
4164+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
4165+ case CCS_EXECUTE_HANDLER:
4166+#endif
4167+ case CCS_PROCESS_STATUS:
4168+ ccs_read_pid(head);
4169+ break;
4170+ case CCS_VERSION:
4171+ ccs_read_version(head);
4172+ break;
4173+ case CCS_QUERY:
4174+ ccs_read_query(head);
4175+ break;
4176+ case CCS_POLICY:
4177+ ccs_read_policy(head);
4178+ break;
4179+ }
4180+ ccs_flush(head);
4181+ }
4182+ ccs_read_unlock(idx);
4183+ len = head->read_user_buf - buf;
4184+ mutex_unlock(&head->io_sem);
4185+ return len;
4186+}
4187+
4188+#ifdef CONFIG_CCSECURITY_MANUAL_DOMAIN_TRANSITION
4189+
4190+/**
4191+ * ccs_write_self - write() for /proc/ccs/self_domain interface.
4192+ *
4193+ * @file: Pointer to "struct file".
4194+ * @buf: Domainname to transit to.
4195+ * @count: Size of @buf.
4196+ * @ppos: Unused.
4197+ *
4198+ * Returns @count on success, negative value otherwise.
4199+ *
4200+ * If domain transition was permitted but the domain transition failed, this
4201+ * function returns error rather than terminating current thread with SIGKILL.
4202+ */
4203+static ssize_t ccs_write_self(struct file *file, const char __user *buf,
4204+ size_t count, loff_t *ppos)
4205+{
4206+ char *data;
4207+ int error;
4208+ if (!count || count >= CCS_EXEC_TMPSIZE - 10)
4209+ return -ENOMEM;
4210+ data = kzalloc(count + 1, GFP_NOFS);
4211+ if (!data)
4212+ return -ENOMEM;
4213+ if (copy_from_user(data, buf, count)) {
4214+ error = -EFAULT;
4215+ goto out;
4216+ }
4217+ ccs_normalize_line(data);
4218+ if (ccs_correct_domain(data)) {
4219+ const int idx = ccs_read_lock();
4220+ struct ccs_path_info name;
4221+ struct ccs_request_info r = { };
4222+ name.name = data;
4223+ ccs_fill_path_info(&name);
4224+ /* Check "manual_domain_transition" permission. */
4225+ r.type = CCS_MAC_MANUAL_DOMAIN_TRANSITION;
4226+ r.param.s[0] = &name;
4227+ ccs_check_acl(&r, true);
4228+ if (r.result != CCS_MATCHING_ALLOWED)
4229+ error = -EPERM;
4230+ else
4231+ error = ccs_transit_domain(data) ? 0 : -ENOENT;
4232+ ccs_read_unlock(idx);
4233+ } else
4234+ error = -EINVAL;
4235+out:
4236+ kfree(data);
4237+ return error ? error : count;
4238+}
4239+
4240+#endif
4241+
4242+/**
4243+ * ccs_write - write() for /proc/ccs/ interface.
4244+ *
4245+ * @file: Pointer to "struct file".
4246+ * @buf: Pointer to buffer.
4247+ * @count: Size of @buf.
4248+ * @ppos: Unused.
4249+ *
4250+ * Returns @count on success, negative value otherwise.
4251+ */
4252+static ssize_t ccs_write(struct file *file, const char __user *buf,
4253+ size_t count, loff_t *ppos)
4254+{
4255+ struct ccs_io_buffer *head = file->private_data;
4256+ int error = count;
4257+ char *cp0 = head->write_buf;
4258+ int idx;
4259+ if (mutex_lock_interruptible(&head->io_sem))
4260+ return -EINTR;
4261+ head->read_user_buf_avail = 0;
4262+ idx = ccs_read_lock();
4263+ /* Read a line and dispatch it to the policy handler. */
4264+ while (count) {
4265+ char c;
4266+ if (head->w.avail >= head->writebuf_size - 1) {
4267+ const int len = head->writebuf_size * 2;
4268+ char *cp = kzalloc(len, GFP_NOFS);
4269+ if (!cp) {
4270+ error = -ENOMEM;
4271+ break;
4272+ }
4273+ memmove(cp, cp0, head->w.avail);
4274+ kfree(cp0);
4275+ head->write_buf = cp;
4276+ cp0 = cp;
4277+ head->writebuf_size = len;
4278+ }
4279+ if (get_user(c, buf)) {
4280+ error = -EFAULT;
4281+ break;
4282+ }
4283+ buf++;
4284+ count--;
4285+ cp0[head->w.avail++] = c;
4286+ if (c != '\n')
4287+ continue;
4288+ cp0[head->w.avail - 1] = '\0';
4289+ head->w.avail = 0;
4290+ ccs_normalize_line(cp0);
4291+ /* Don't allow updating policies by non manager programs. */
4292+ if (head->type != CCS_PROCESS_STATUS && !ccs_manager()) {
4293+ error = -EPERM;
4294+ goto out;
4295+ }
4296+ switch (ccs_parse_policy(head, cp0)) {
4297+ case -EPERM:
4298+ error = -EPERM;
4299+ goto out;
4300+ case 0:
4301+ /* Update statistics. */
4302+ if (head->type == CCS_POLICY)
4303+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
4304+ break;
4305+ }
4306+ }
4307+out:
4308+ ccs_read_unlock(idx);
4309+ mutex_unlock(&head->io_sem);
4310+ return error;
4311+}
4312+
4313+/**
4314+ * ccs_create_entry - Create interface files under /proc/ccs/ directory.
4315+ *
4316+ * @name: The name of the interface file.
4317+ * @mode: The permission of the interface file.
4318+ * @parent: The parent directory.
4319+ * @key: Type of interface.
4320+ *
4321+ * Returns nothing.
4322+ */
4323+static void __init ccs_create_entry(const char *name, const umode_t mode,
4324+ struct proc_dir_entry *parent,
4325+ const u8 key)
4326+{
4327+ struct proc_dir_entry *entry = create_proc_entry(name, mode, parent);
4328+ if (entry) {
4329+ entry->proc_fops = &ccs_operations;
4330+ entry->data = ((u8 *) NULL) + key;
4331+ }
4332+}
4333+
4334+/**
4335+ * ccs_proc_init - Initialize /proc/ccs/ interface.
4336+ *
4337+ * Returns nothing.
4338+ */
4339+static void __init ccs_proc_init(void)
4340+{
4341+ struct proc_dir_entry *ccs_dir = proc_mkdir("ccs", NULL);
4342+ ccs_create_entry("query", 0600, ccs_dir, CCS_QUERY);
4343+ ccs_create_entry("audit", 0400, ccs_dir, CCS_AUDIT);
4344+ ccs_create_entry(".process_status", 0600, ccs_dir,
4345+ CCS_PROCESS_STATUS);
4346+ ccs_create_entry("version", 0400, ccs_dir, CCS_VERSION);
4347+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
4348+ ccs_create_entry(".execute_handler", 0666, ccs_dir,
4349+ CCS_EXECUTE_HANDLER);
4350+#endif
4351+ ccs_create_entry("policy", 0600, ccs_dir, CCS_POLICY);
4352+ {
4353+ struct proc_dir_entry *e = create_proc_entry("self_domain",
4354+ 0666, ccs_dir);
4355+ if (e)
4356+ e->proc_fops = &ccs_self_operations;
4357+ }
4358+}
4359+
4360+/**
4361+ * ccs_init_module - Initialize this module.
4362+ *
4363+ * Returns 0 on success, negative value otherwise.
4364+ */
4365+static int __init ccs_init_module(void)
4366+{
4367+ u16 idx;
4368+ if (ccsecurity_ops.disabled)
4369+ return -EINVAL;
4370+#ifdef DEBUG_CONDITION
4371+ for (idx = 0; idx < CCS_MAX_MAC_INDEX; idx++) {
4372+ if (ccs_mac_keywords[idx])
4373+ continue;
4374+ printk(KERN_INFO "ccs_mac_keywords[%u]==NULL\n", idx);
4375+ return -EINVAL;
4376+ }
4377+#endif
4378+ if (init_srcu_struct(&ccs_ss))
4379+ panic("Out of memory.");
4380+ for (idx = 0; idx < CCS_MAX_MAC_INDEX; idx++)
4381+ INIT_LIST_HEAD(&ccs_acl_list[idx]);
4382+ for (idx = 0; idx < CCS_MAX_GROUP; idx++)
4383+ INIT_LIST_HEAD(&ccs_group_list[idx]);
4384+ for (idx = 0; idx < CCS_MAX_HASH; idx++)
4385+ INIT_LIST_HEAD(&ccs_name_list[idx]);
4386+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
4387+ ccs_mm_init();
4388+#endif
4389+ ccs_null_name.name = "NULL";
4390+ ccs_fill_path_info(&ccs_null_name);
4391+ ccs_kernel_domain.domainname = ccs_get_name("<kernel>");
4392+ list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
4393+ ccs_policy_io_init();
4394+ ccs_permission_init();
4395+ ccs_proc_init();
4396+ ccs_load_builtin_policy();
4397+ return 0;
4398+}
4399+
4400+MODULE_LICENSE("GPL");
4401+module_init(ccs_init_module);
--- trunk/caitsith-patch/security/caitsith/memory.c (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/memory.c (revision 2)
@@ -0,0 +1,179 @@
1+/*
2+ * security/caitsith/memory.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#include "internal.h"
10+
11+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
12+
13+/***** SECTION1: Constants definition *****/
14+
15+/***** SECTION2: Structure definition *****/
16+
17+/***** SECTION3: Prototype definition section *****/
18+
19+struct ccs_security *ccs_find_task_security(const struct task_struct *task);
20+void __init ccs_mm_init(void);
21+
22+static int __ccs_alloc_task_security(const struct task_struct *task);
23+static void __ccs_free_task_security(const struct task_struct *task);
24+static void ccs_add_task_security(struct ccs_security *ptr,
25+ struct list_head *list);
26+static void ccs_rcu_free(struct rcu_head *rcu);
27+
28+/***** SECTION4: Standalone functions section *****/
29+
30+/***** SECTION5: Variables definition section *****/
31+
32+/* Dummy security context for avoiding NULL pointer dereference. */
33+static struct ccs_security ccs_oom_security = {
34+ .ccs_domain_info = &ccs_kernel_domain
35+};
36+
37+/* Dummy security context for avoiding NULL pointer dereference. */
38+static struct ccs_security ccs_default_security = {
39+ .ccs_domain_info = &ccs_kernel_domain
40+};
41+
42+/* List of "struct ccs_security". */
43+struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
44+/* Lock for protecting ccs_task_security_list[]. */
45+static DEFINE_SPINLOCK(ccs_task_security_list_lock);
46+
47+/***** SECTION6: Dependent functions section *****/
48+
49+/**
50+ * ccs_add_task_security - Add "struct ccs_security" to list.
51+ *
52+ * @ptr: Pointer to "struct ccs_security".
53+ * @list: Pointer to "struct list_head".
54+ *
55+ * Returns nothing.
56+ */
57+static void ccs_add_task_security(struct ccs_security *ptr,
58+ struct list_head *list)
59+{
60+ unsigned long flags;
61+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
62+ list_add_rcu(&ptr->list, list);
63+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
64+}
65+
66+/**
67+ * __ccs_alloc_task_security - Allocate memory for new tasks.
68+ *
69+ * @task: Pointer to "struct task_struct".
70+ *
71+ * Returns 0 on success, negative value otherwise.
72+ */
73+static int __ccs_alloc_task_security(const struct task_struct *task)
74+{
75+ struct ccs_security *old_security = ccs_current_security();
76+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
77+ GFP_KERNEL);
78+ struct list_head *list = &ccs_task_security_list
79+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
80+ if (!new_security)
81+ return -ENOMEM;
82+ *new_security = *old_security;
83+ new_security->task = task;
84+ ccs_add_task_security(new_security, list);
85+ return 0;
86+}
87+
88+/**
89+ * ccs_find_task_security - Find "struct ccs_security" for given task.
90+ *
91+ * @task: Pointer to "struct task_struct".
92+ *
93+ * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
94+ * out of memory, &ccs_default_security otherwise.
95+ *
96+ * If @task is current thread and "struct ccs_security" for current thread was
97+ * not found, I try to allocate it. But if allocation failed, current thread
98+ * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
99+ * won't work.
100+ */
101+struct ccs_security *ccs_find_task_security(const struct task_struct *task)
102+{
103+ struct ccs_security *ptr;
104+ struct list_head *list = &ccs_task_security_list
105+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
106+ /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
107+ while (!list->next);
108+ rcu_read_lock();
109+ list_for_each_entry_rcu(ptr, list, list) {
110+ if (ptr->task != task)
111+ continue;
112+ rcu_read_unlock();
113+ return ptr;
114+ }
115+ rcu_read_unlock();
116+ if (task != current)
117+ return &ccs_default_security;
118+ /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
119+ ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
120+ if (!ptr) {
121+ printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
122+ task->pid);
123+ send_sig(SIGKILL, current, 0);
124+ return &ccs_oom_security;
125+ }
126+ *ptr = ccs_default_security;
127+ ptr->task = task;
128+ ccs_add_task_security(ptr, list);
129+ return ptr;
130+}
131+
132+/**
133+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
134+ *
135+ * @rcu: Pointer to "struct rcu_head".
136+ *
137+ * Returns nothing.
138+ */
139+static void ccs_rcu_free(struct rcu_head *rcu)
140+{
141+ struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
142+ kfree(ptr);
143+}
144+
145+/**
146+ * __ccs_free_task_security - Release memory associated with "struct task_struct".
147+ *
148+ * @task: Pointer to "struct task_struct".
149+ *
150+ * Returns nothing.
151+ */
152+static void __ccs_free_task_security(const struct task_struct *task)
153+{
154+ unsigned long flags;
155+ struct ccs_security *ptr = ccs_find_task_security(task);
156+ if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
157+ return;
158+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
159+ list_del_rcu(&ptr->list);
160+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
161+ call_rcu(&ptr->rcu, ccs_rcu_free);
162+}
163+
164+/**
165+ * ccs_mm_init - Initialize mm related code.
166+ *
167+ * Returns nothing.
168+ */
169+void __init ccs_mm_init(void)
170+{
171+ int idx;
172+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++)
173+ INIT_LIST_HEAD(&ccs_task_security_list[idx]);
174+ smp_wmb(); /* Avoid out of order execution. */
175+ ccsecurity_ops.alloc_task_security = __ccs_alloc_task_security;
176+ ccsecurity_ops.free_task_security = __ccs_free_task_security;
177+}
178+
179+#endif
--- trunk/caitsith-patch/security/caitsith/permission.c (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/permission.c (revision 2)
@@ -0,0 +1,3752 @@
1+/*
2+ * security/caitsith/permission.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/***** SECTION1: Constants definition *****/
12+
13+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
14+
15+/*
16+ * may_open() receives open flags modified by open_to_namei_flags() until
17+ * 2.6.32. We stop here in case some distributions backported ACC_MODE changes,
18+ * for we can't determine whether may_open() receives open flags modified by
19+ * open_to_namei_flags() or not.
20+ */
21+#ifdef ACC_MODE
22+#error ACC_MODE already defined.
23+#endif
24+#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
25+
26+#if defined(RHEL_MAJOR) && RHEL_MAJOR == 6
27+/* RHEL6 passes unmodified flags since 2.6.32-71.14.1.el6 . */
28+#undef ACC_MODE
29+#define ACC_MODE(x) ("\004\002\006"[(x)&O_ACCMODE])
30+#endif
31+
32+#endif
33+
34+/* String table for special mount operations. */
35+static const char * const ccs_mounts[CCS_MAX_SPECIAL_MOUNT] = {
36+ [CCS_MOUNT_BIND] = "--bind",
37+ [CCS_MOUNT_MOVE] = "--move",
38+ [CCS_MOUNT_REMOUNT] = "--remount",
39+ [CCS_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
40+ [CCS_MOUNT_MAKE_PRIVATE] = "--make-private",
41+ [CCS_MOUNT_MAKE_SLAVE] = "--make-slave",
42+ [CCS_MOUNT_MAKE_SHARED] = "--make-shared",
43+};
44+
45+#ifdef CONFIG_CCSECURITY_CAPABILITY
46+
47+/*
48+ * Mapping table from "enum ccs_capability_acl_index" to "enum ccs_mac_index".
49+ */
50+static const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX] = {
51+ [CCS_USE_ROUTE_SOCKET] = CCS_MAC_USE_NETLINK_SOCKET,
52+ [CCS_USE_PACKET_SOCKET] = CCS_MAC_USE_PACKET_SOCKET,
53+ [CCS_SYS_REBOOT] = CCS_MAC_USE_REBOOT,
54+ [CCS_SYS_VHANGUP] = CCS_MAC_USE_VHANGUP,
55+ [CCS_SYS_SETTIME] = CCS_MAC_SET_TIME,
56+ [CCS_SYS_NICE] = CCS_MAC_SET_PRIORITY,
57+ [CCS_SYS_SETHOSTNAME] = CCS_MAC_SET_HOSTNAME,
58+ [CCS_USE_KERNEL_MODULE] = CCS_MAC_USE_KERNEL_MODULE,
59+ [CCS_SYS_KEXEC_LOAD] = CCS_MAC_USE_NEW_KERNEL,
60+};
61+
62+#endif
63+
64+/* Type of condition argument. */
65+enum ccs_arg_type {
66+ CCS_ARG_TYPE_NONE,
67+ CCS_ARG_TYPE_NUMBER,
68+ CCS_ARG_TYPE_NAME,
69+ CCS_ARG_TYPE_GROUP,
70+ CCS_ARG_TYPE_BITOP,
71+#ifdef CONFIG_CCSECURITY_NETWORK
72+ CCS_ARG_TYPE_IPV4ADDR,
73+ CCS_ARG_TYPE_IPV6ADDR,
74+#endif
75+} __packed;
76+
77+/***** SECTION2: Structure definition *****/
78+
79+/* Structure for holding inet domain socket's address. */
80+struct ccs_inet_addr_info {
81+ u16 port; /* In network byte order. */
82+ const u8 *address; /* In network byte order. */
83+ bool is_ipv6;
84+};
85+
86+/* Structure for holding unix domain socket's address. */
87+struct ccs_unix_addr_info {
88+ u8 *addr; /* This may not be '\0' terminated string. */
89+ unsigned int addr_len;
90+};
91+
92+/* Structure for holding socket address. */
93+struct ccs_addr_info {
94+ u8 operation;
95+ struct ccs_inet_addr_info inet;
96+ struct ccs_unix_addr_info unix0;
97+};
98+
99+/* Structure for holding single condition component. */
100+struct ccs_cond_arg {
101+ enum ccs_arg_type type;
102+ unsigned long value[2];
103+ const struct ccs_path_info *name;
104+ const struct ccs_group *group;
105+ struct in6_addr ip[2];
106+};
107+
108+/***** SECTION3: Prototype definition section *****/
109+
110+static bool ccs_alphabet_char(const char c);
111+static bool ccs_byte_range(const char *str);
112+static bool ccs_check_entry(struct ccs_request_info *r,
113+ const struct ccs_acl_info *ptr);
114+static bool ccs_condition(struct ccs_request_info *r,
115+ const struct ccs_condition *cond);
116+static bool ccs_decimal(const char c);
117+static bool ccs_file_matches_pattern(const char *filename,
118+ const char *filename_end,
119+ const char *pattern,
120+ const char *pattern_end);
121+static bool ccs_file_matches_pattern2(const char *filename,
122+ const char *filename_end,
123+ const char *pattern,
124+ const char *pattern_end);
125+static bool ccs_hexadecimal(const char c);
126+static bool ccs_number_matches_group(const unsigned long min,
127+ const unsigned long max,
128+ const struct ccs_group *group);
129+static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
130+ const struct ccs_path_info *pattern);
131+static bool ccs_path_matches_pattern2(const char *f, const char *p);
132+static bool ccs_path_matches_group(const struct ccs_path_info *pathname,
133+ const struct ccs_group *group);
134+static int __ccs_chmod_permission(struct dentry *dentry,
135+ struct vfsmount *vfsmnt, mode_t mode);
136+static int __ccs_chown_permission(struct dentry *dentry,
137+ struct vfsmount *vfsmnt, uid_t user,
138+ gid_t group);
139+static int __ccs_chroot_permission(struct path *path);
140+static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
141+ unsigned long arg);
142+static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
143+ unsigned long arg);
144+static int __ccs_link_permission(struct dentry *old_dentry,
145+ struct dentry *new_dentry,
146+ struct vfsmount *mnt);
147+static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
148+ unsigned int mode);
149+static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
150+ const unsigned int mode, unsigned int dev);
151+static int __ccs_mount_permission(char *dev_name, struct path *path,
152+ const char *type, unsigned long flags,
153+ void *data_page);
154+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
155+static int __ccs_open_exec_permission(struct dentry *dentry,
156+ struct vfsmount *mnt);
157+#endif
158+static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
159+ const int flag);
160+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
161+static int ccs_sysctl_permission(enum ccs_mac_index type,
162+ const struct ccs_path_info *filename);
163+static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
164+ void __user *newval, struct ctl_table *table);
165+#endif
166+static int __ccs_pivot_root_permission(struct path *old_path,
167+ struct path *new_path);
168+static int __ccs_rename_permission(struct dentry *old_dentry,
169+ struct dentry *new_dentry,
170+ struct vfsmount *mnt);
171+static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt);
172+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
173+ struct pt_regs *regs);
174+static int __ccs_symlink_permission(struct dentry *dentry,
175+ struct vfsmount *mnt, const char *from);
176+static int __ccs_truncate_permission(struct dentry *dentry,
177+ struct vfsmount *mnt);
178+static int __ccs_umount_permission(struct vfsmount *mnt, int flags);
179+static int __ccs_unlink_permission(struct dentry *dentry,
180+ struct vfsmount *mnt);
181+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
182+static int __ccs_uselib_permission(struct dentry *dentry,
183+ struct vfsmount *mnt);
184+#endif
185+static int ccs_execute_path(struct linux_binprm *bprm, struct path *path);
186+static int ccs_execute(struct ccs_request_info *r);
187+static int ccs_kern_path(const char *pathname, int flags, struct path *path);
188+static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
189+ struct vfsmount *mnt, const unsigned int mode,
190+ unsigned int dev);
191+static int ccs_mount_acl(const char *dev_name, struct path *dir,
192+ const char *type, unsigned long flags,
193+ const char *data);
194+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
195+static int ccs_new_open_permission(struct file *filp);
196+#endif
197+static int ccs_path2_perm(const enum ccs_mac_index operation,
198+ struct dentry *dentry1, struct vfsmount *mnt1,
199+ struct dentry *dentry2, struct vfsmount *mnt2);
200+static int ccs_path_number_perm(const enum ccs_mac_index type,
201+ struct dentry *dentry, struct vfsmount *vfsmnt,
202+ unsigned long number);
203+static int ccs_path_perm(const enum ccs_mac_index operation,
204+ struct dentry *dentry, struct vfsmount *mnt);
205+static int ccs_start_execve(struct linux_binprm *bprm,
206+ struct ccs_request_info **rp);
207+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
208+static void __ccs_clear_open_mode(void);
209+static void __ccs_save_open_mode(int mode);
210+#endif
211+static void ccs_check_auto_domain_transition(void);
212+static void ccs_clear_request_info(struct ccs_request_info *r);
213+static void ccs_finish_execve(int retval, struct ccs_request_info *r);
214+
215+#ifdef CONFIG_CCSECURITY_ENVIRON
216+static int ccs_env_perm(struct ccs_request_info *r, const char *name,
217+ const char *value);
218+static int ccs_environ(struct ccs_request_info *r);
219+#endif
220+
221+#ifdef CONFIG_CCSECURITY_CAPABILITY
222+static bool __ccs_capable(const u8 operation);
223+static bool ccs_kernel_service(void);
224+static int __ccs_socket_create_permission(int family, int type, int protocol);
225+#endif
226+
227+#ifdef CONFIG_CCSECURITY_NETWORK
228+static bool ccs_ip_matches_group(const bool is_ipv6, const u8 *address,
229+ const struct ccs_group *group);
230+static bool ccs_kernel_service(void);
231+static int __ccs_socket_bind_permission(struct socket *sock,
232+ struct sockaddr *addr, int addr_len);
233+static int __ccs_socket_connect_permission(struct socket *sock,
234+ struct sockaddr *addr,
235+ int addr_len);
236+static int __ccs_socket_listen_permission(struct socket *sock);
237+static int __ccs_socket_post_accept_permission(struct socket *sock,
238+ struct socket *newsock);
239+static int __ccs_socket_sendmsg_permission(struct socket *sock,
240+ struct msghdr *msg, int size);
241+static int ccs_check_inet_address(const struct sockaddr *addr,
242+ const unsigned int addr_len, const u16 port,
243+ struct ccs_addr_info *address);
244+static int ccs_check_unix_address(struct sockaddr *addr,
245+ const unsigned int addr_len,
246+ struct ccs_addr_info *address);
247+static int ccs_inet_entry(const struct ccs_addr_info *address);
248+static int ccs_unix_entry(const struct ccs_addr_info *address);
249+static u8 ccs_sock_family(struct sock *sk);
250+#endif
251+
252+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
253+static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
254+ struct sk_buff *skb,
255+ int flags);
256+#endif
257+
258+#ifdef CONFIG_CCSECURITY_PTRACE
259+static int __ccs_ptrace_permission(long request, long pid);
260+#endif
261+#ifdef CONFIG_CCSECURITY_SIGNAL
262+static int __ccs_signal_permission(const int sig);
263+static int ccs_signal_permission0(const int pid, const int sig);
264+static int ccs_signal_permission1(pid_t tgid, pid_t pid, int sig);
265+#endif
266+
267+#ifdef CONFIG_CCSECURITY_GETATTR
268+static int __ccs_getattr_permission(struct vfsmount *mnt,
269+ struct dentry *dentry);
270+#endif
271+
272+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
273+static int ccs_try_alt_exec(struct ccs_request_info *r);
274+static void ccs_unescape(unsigned char *dest);
275+#endif
276+
277+/***** SECTION4: Standalone functions section *****/
278+
279+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
280+
281+/**
282+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
283+ *
284+ * @arg: String to copy.
285+ * @bprm: Pointer to "struct linux_binprm".
286+ *
287+ * Returns return value of copy_strings_kernel().
288+ */
289+static inline int ccs_copy_argv(const char *arg, struct linux_binprm *bprm)
290+{
291+ const int ret = copy_strings_kernel(1, &arg, bprm);
292+ if (ret >= 0)
293+ bprm->argc++;
294+ return ret;
295+}
296+
297+#else
298+
299+/**
300+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
301+ *
302+ * @arg: String to copy.
303+ * @bprm: Pointer to "struct linux_binprm".
304+ *
305+ * Returns return value of copy_strings_kernel().
306+ */
307+static inline int ccs_copy_argv(char *arg, struct linux_binprm *bprm)
308+{
309+ const int ret = copy_strings_kernel(1, &arg, bprm);
310+ if (ret >= 0)
311+ bprm->argc++;
312+ return ret;
313+}
314+
315+#endif
316+
317+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
318+
319+/**
320+ * get_fs_root - Get reference on root directory.
321+ *
322+ * @fs: Pointer to "struct fs_struct".
323+ * @root: Pointer to "struct path".
324+ *
325+ * Returns nothing.
326+ *
327+ * This is for compatibility with older kernels.
328+ */
329+static inline void get_fs_root(struct fs_struct *fs, struct path *root)
330+{
331+ read_lock(&fs->lock);
332+ *root = fs->root;
333+ path_get(root);
334+ read_unlock(&fs->lock);
335+}
336+
337+#endif
338+
339+/**
340+ * ccs_put_filesystem - Wrapper for put_filesystem().
341+ *
342+ * @fstype: Pointer to "struct file_system_type".
343+ *
344+ * Returns nothing.
345+ *
346+ * Since put_filesystem() is not exported, I embed put_filesystem() here.
347+ */
348+static inline void ccs_put_filesystem(struct file_system_type *fstype)
349+{
350+ module_put(fstype->owner);
351+}
352+
353+/***** SECTION5: Variables definition section *****/
354+
355+/* The initial domain. */
356+struct ccs_domain_info ccs_kernel_domain;
357+
358+/* The list for "struct ccs_domain_info". */
359+LIST_HEAD(ccs_domain_list);
360+
361+/* The list for ACL policy. */
362+struct list_head ccs_acl_list[CCS_MAX_MAC_INDEX];
363+
364+/* NULL value. */
365+struct ccs_path_info ccs_null_name;
366+
367+/***** SECTION6: Dependent functions section *****/
368+
369+/**
370+ * ccs_path_matches_group - Check whether the given pathname matches members of the given pathname group.
371+ *
372+ * @pathname: The name of pathname.
373+ * @group: Pointer to "struct ccs_string_group".
374+ *
375+ * Returns true if @pathname matches pathnames in @group, false otherwise.
376+ *
377+ * Caller holds ccs_read_lock().
378+ */
379+static bool ccs_path_matches_group(const struct ccs_path_info *pathname,
380+ const struct ccs_group *group)
381+{
382+ struct ccs_string_group *member;
383+ list_for_each_entry_srcu(member, &group->member_list, head.list,
384+ &ccs_ss) {
385+ if (member->head.is_deleted)
386+ continue;
387+ if (!ccs_path_matches_pattern(pathname, member->member_name))
388+ continue;
389+ return true;
390+ }
391+ return false;
392+}
393+
394+/**
395+ * ccs_number_matches_group - Check whether the given number matches members of the given number group.
396+ *
397+ * @min: Min number.
398+ * @max: Max number.
399+ * @group: Pointer to "struct ccs_number_group".
400+ *
401+ * Returns true if @min and @max partially overlaps @group, false otherwise.
402+ *
403+ * Caller holds ccs_read_lock().
404+ */
405+static bool ccs_number_matches_group(const unsigned long min,
406+ const unsigned long max,
407+ const struct ccs_group *group)
408+{
409+ struct ccs_number_group *member;
410+ bool matched = false;
411+ list_for_each_entry_srcu(member, &group->member_list, head.list,
412+ &ccs_ss) {
413+ if (member->head.is_deleted)
414+ continue;
415+ if (min > member->value[1] || max < member->value[0])
416+ continue;
417+ matched = true;
418+ break;
419+ }
420+ return matched;
421+}
422+
423+/**
424+ * ccs_check_entry - Do permission check.
425+ *
426+ * @r: Pointer to "struct ccs_request_info".
427+ * @ptr: Pointer to "struct ccs_acl_info".
428+ *
429+ * Returns true on match, false otherwise.
430+ *
431+ * Caller holds ccs_read_lock().
432+ */
433+static bool ccs_check_entry(struct ccs_request_info *r,
434+ const struct ccs_acl_info *ptr)
435+{
436+ return !ptr->is_deleted && ccs_condition(r, ptr->cond);
437+}
438+
439+/**
440+ * ccs_check_acl_list - Do permission check.
441+ *
442+ * @r: Pointer to "struct ccs_request_info".
443+ *
444+ * Returns 0 on success, negative value otherwise.
445+ *
446+ * Caller holds ccs_read_lock().
447+ */
448+static int ccs_check_acl_list(struct ccs_request_info *r)
449+{
450+ struct ccs_acl_info *ptr;
451+ int error = 0;
452+ struct list_head * const list = &ccs_acl_list[r->type];
453+ r->matched_acl = NULL;
454+ list_for_each_entry_srcu(ptr, list, list, &ccs_ss) {
455+ struct ccs_acl_info *ptr2;
456+retry:
457+ if (!ccs_check_entry(r, ptr)) {
458+ if (unlikely(r->failed_by_oom))
459+ goto oom;
460+ continue;
461+ }
462+ r->matched_acl = ptr;
463+ r->audit = ptr->audit;
464+ r->result = CCS_MATCHING_UNMATCHED;
465+ list_for_each_entry_srcu(ptr2, &ptr->acl_info_list, list,
466+ &ccs_ss) {
467+ r->transition_candidate = NULL;
468+ r->handler_path_candidate = NULL;
469+ if (!ccs_check_entry(r, ptr2)) {
470+ if (unlikely(r->failed_by_oom))
471+ goto oom;
472+ continue;
473+ }
474+ if (ptr2->is_deny) {
475+ r->result = CCS_MATCHING_DENIED;
476+ break;
477+ }
478+ r->result = CCS_MATCHING_ALLOWED;
479+ /* Set the first matching domain transition entry. */
480+ if (r->transition_candidate && !r->transition)
481+ r->transition = r->transition_candidate;
482+ /* Set the first matching execute handler entry. */
483+ if (r->handler_path_candidate && !r->handler_path)
484+ r->handler_path = r->handler_path_candidate;
485+ break;
486+ }
487+ error = ccs_audit_log(r);
488+ /* Ignore out of memory during audit. */
489+ r->failed_by_oom = false;
490+ if (!error)
491+ continue;
492+ if (error == CCS_RETRY_REQUEST)
493+ goto retry;
494+ break;
495+ }
496+ return error;
497+oom:
498+ /*
499+ * If conditions could not be checked due to out of memory,
500+ * reject the request with -ENOMEM, for we don't know whether
501+ * there was a possibility of matching "deny" lines or not.
502+ */
503+ {
504+ static struct timeval ccs_last_tv;
505+ struct timeval tv;
506+ do_gettimeofday(&tv);
507+ if (tv.tv_sec != ccs_last_tv.tv_sec) {
508+ ccs_last_tv = tv;
509+ printk(KERN_INFO "CaitSith: Rejecting access "
510+ "request due to out of memory.\n");
511+ }
512+ }
513+ return -ENOMEM;
514+}
515+
516+/**
517+ * ccs_check_acl - Do permission check.
518+ *
519+ * @r: Pointer to "struct ccs_request_info".
520+ * @clear: True to cleanup @r before return, false otherwise.
521+ *
522+ * Returns 0 on success, negative value otherwise.
523+ */
524+int ccs_check_acl(struct ccs_request_info *r, const bool clear)
525+{
526+ int error;
527+ const int idx = ccs_read_lock();
528+ error = ccs_check_acl_list(r);
529+ ccs_read_unlock(idx);
530+ if (clear)
531+ ccs_clear_request_info(r);
532+ return error;
533+}
534+
535+/**
536+ * ccs_execute - Check permission for "execute".
537+ *
538+ * @r: Pointer to "struct ccs_request_info".
539+ *
540+ * Returns 0 on success, negative value otherwise.
541+ *
542+ * Caller holds ccs_read_lock().
543+ */
544+static int ccs_execute(struct ccs_request_info *r)
545+{
546+ int retval;
547+
548+ /* Get symlink's dentry/vfsmount. */
549+ retval = ccs_execute_path(r->bprm, &r->obj.path[1]);
550+ if (retval < 0)
551+ return retval;
552+ ccs_populate_patharg(r, false);
553+ if (!r->param.s[1])
554+ return -ENOMEM;
555+
556+ /* Check execute permission. */
557+ r->type = CCS_MAC_EXECUTE;
558+ retval = ccs_check_acl(r, false);
559+ if (retval < 0)
560+ return retval;
561+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
562+ /*
563+ * Switch to execute handler if matched. To avoid infinite execute
564+ * handler loop, don't use execute handler if the current process is
565+ * marked as execute handler.
566+ */
567+ if (r->handler_path && r->handler_path != &ccs_null_name &&
568+ !(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
569+ retval = ccs_try_alt_exec(r);
570+ if (retval < 0)
571+ return retval;
572+ }
573+#endif
574+ /*
575+ * Tell GC that I started execve().
576+ * Also, tell open_exec() to check read permission.
577+ */
578+ ccs_current_security()->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
579+ if (!r->transition || r->transition == &ccs_null_name)
580+ /* Keep current domain. */
581+ return 0;
582+ /*
583+ * Make ccs_current_security()->ccs_flags visible to GC before changing
584+ * ccs_current_security()->ccs_domain_info.
585+ */
586+ smp_wmb();
587+ /*
588+ * Transit to the specified domain.
589+ * It will be reverted if execve() failed.
590+ */
591+ if (ccs_transit_domain(r->transition->name))
592+ return 0;
593+ printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
594+ r->transition->name);
595+ return -ENOMEM;
596+}
597+
598+#ifdef CONFIG_CCSECURITY_EXECUTE_HANDLER
599+
600+/**
601+ * ccs_unescape - Unescape escaped string.
602+ *
603+ * @dest: String to unescape.
604+ *
605+ * Returns nothing.
606+ */
607+static void ccs_unescape(unsigned char *dest)
608+{
609+ unsigned char *src = dest;
610+ unsigned char c;
611+ unsigned char d;
612+ unsigned char e;
613+ while (1) {
614+ c = *src++;
615+ if (!c)
616+ break;
617+ if (c != '\\') {
618+ *dest++ = c;
619+ continue;
620+ }
621+ c = *src++;
622+ if (c < '0' || c > '3')
623+ break;
624+ d = *src++;
625+ if (d < '0' || d > '7')
626+ break;
627+ e = *src++;
628+ if (e < '0' || e > '7')
629+ break;
630+ *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
631+ }
632+ *dest = '\0';
633+}
634+
635+/**
636+ * ccs_try_alt_exec - Try to start execute handler.
637+ *
638+ * @r: Pointer to "struct ccs_request_info".
639+ *
640+ * Returns 0 on success, negative value otherwise.
641+ */
642+static int ccs_try_alt_exec(struct ccs_request_info *r)
643+{
644+ /*
645+ * Contents of modified bprm.
646+ * The envp[] in original bprm is moved to argv[] so that
647+ * the alternatively executed program won't be affected by
648+ * some dangerous environment variables like LD_PRELOAD.
649+ *
650+ * modified bprm->argc
651+ * = original bprm->argc + original bprm->envc + 7
652+ * modified bprm->envc
653+ * = 0
654+ *
655+ * modified bprm->argv[0]
656+ * = the program's name specified by *_execute_handler
657+ * modified bprm->argv[1]
658+ * = ccs_current_domain()->domainname->name
659+ * modified bprm->argv[2]
660+ * = the current process's name
661+ * modified bprm->argv[3]
662+ * = the current process's information (e.g. uid/gid).
663+ * modified bprm->argv[4]
664+ * = original bprm->filename
665+ * modified bprm->argv[5]
666+ * = original bprm->argc in string expression
667+ * modified bprm->argv[6]
668+ * = original bprm->envc in string expression
669+ * modified bprm->argv[7]
670+ * = original bprm->argv[0]
671+ * ...
672+ * modified bprm->argv[bprm->argc + 6]
673+ * = original bprm->argv[bprm->argc - 1]
674+ * modified bprm->argv[bprm->argc + 7]
675+ * = original bprm->envp[0]
676+ * ...
677+ * modified bprm->argv[bprm->envc + bprm->argc + 6]
678+ * = original bprm->envp[bprm->envc - 1]
679+ */
680+ struct linux_binprm *bprm = r->bprm;
681+ struct file *filp;
682+ int retval;
683+ const int original_argc = bprm->argc;
684+ const int original_envc = bprm->envc;
685+
686+ ccs_clear_request_info(r);
687+
688+ /* Close the requested program's dentry. */
689+ r->obj.path[0].dentry = NULL;
690+ r->obj.path[0].mnt = NULL;
691+ r->obj.validate_done = false;
692+ allow_write_access(bprm->file);
693+ fput(bprm->file);
694+ bprm->file = NULL;
695+
696+ /* Invalidate page dump cache. */
697+ r->dump.page = NULL;
698+
699+ /* Move envp[] to argv[] */
700+ bprm->argc += bprm->envc;
701+ bprm->envc = 0;
702+
703+ /* Set argv[6] */
704+ {
705+ snprintf(r->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
706+ retval = ccs_copy_argv(r->tmp, bprm);
707+ if (retval < 0)
708+ goto out;
709+ }
710+
711+ /* Set argv[5] */
712+ {
713+ snprintf(r->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
714+ retval = ccs_copy_argv(r->tmp, bprm);
715+ if (retval < 0)
716+ goto out;
717+ }
718+
719+ /* Set argv[4] */
720+ {
721+ retval = ccs_copy_argv(bprm->filename, bprm);
722+ if (retval < 0)
723+ goto out;
724+ }
725+
726+ /* Set argv[3] */
727+ {
728+ snprintf(r->tmp, CCS_EXEC_TMPSIZE - 1,
729+ "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
730+ "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
731+ current_uid(), current_gid(), current_euid(),
732+ current_egid(), current_suid(), current_sgid(),
733+ current_fsuid(), current_fsgid());
734+ retval = ccs_copy_argv(r->tmp, bprm);
735+ if (retval < 0)
736+ goto out;
737+ }
738+
739+ /* Set argv[2] */
740+ {
741+ char *exe = ccs_get_exe();
742+ if (exe) {
743+ retval = ccs_copy_argv(exe, bprm);
744+ kfree(exe);
745+ } else {
746+ retval = -ENOMEM;
747+ }
748+ if (retval < 0)
749+ goto out;
750+ }
751+
752+ /* Set argv[1] */
753+ {
754+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
755+ retval = ccs_copy_argv(ccs_current_domain()->domainname->name,
756+ bprm);
757+#else
758+ snprintf(r->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
759+ ccs_current_domain()->domainname->name);
760+ retval = ccs_copy_argv(r->tmp, bprm);
761+#endif
762+ if (retval < 0)
763+ goto out;
764+ }
765+
766+ /* Set argv[0] */
767+ {
768+ struct path root;
769+ char *cp;
770+ int root_len;
771+ int handler_len;
772+ get_fs_root(current->fs, &root);
773+ cp = ccs_realpath(&root);
774+ path_put(&root);
775+ if (!cp) {
776+ retval = -ENOMEM;
777+ goto out;
778+ }
779+ root_len = strlen(cp);
780+ retval = strncmp(r->handler_path->name, cp, root_len);
781+ root_len--;
782+ kfree(cp);
783+ if (retval) {
784+ retval = -ENOENT;
785+ goto out;
786+ }
787+ handler_len = r->handler_path->total_len + 1;
788+ /* r->handler is released by ccs_finish_execve(). */
789+ r->handler = kmalloc(handler_len, GFP_NOFS);
790+ if (!r->handler) {
791+ retval = -ENOMEM;
792+ goto out;
793+ }
794+ /* Adjust root directory for open_exec(). */
795+ memmove(r->handler, r->handler_path->name + root_len,
796+ handler_len - root_len);
797+ ccs_unescape(r->handler);
798+ retval = -ENOENT;
799+ if (*r->handler != '/')
800+ goto out;
801+ retval = ccs_copy_argv(r->handler, bprm);
802+ if (retval < 0)
803+ goto out;
804+ }
805+
806+ /*
807+ * OK, now restart the process with execute handler program's dentry.
808+ */
809+ filp = open_exec(r->handler);
810+ if (IS_ERR(filp)) {
811+ retval = PTR_ERR(filp);
812+ goto out;
813+ }
814+ r->obj.path[0].dentry = filp->f_dentry;
815+ r->obj.path[0].mnt = filp->f_vfsmnt;
816+ bprm->file = filp;
817+ bprm->filename = r->handler;
818+ bprm->interp = bprm->filename;
819+ retval = prepare_binprm(bprm);
820+ if (retval < 0)
821+ goto out;
822+ ccs_populate_patharg(r, true);
823+ if (!r->param.s[0])
824+ retval = -ENOMEM;
825+ else if (ccs_pathcmp(r->param.s[0], r->handler_path)) {
826+ /* Failed to verify execute handler. */
827+ static u8 counter = 20;
828+ if (counter) {
829+ counter--;
830+ printk(KERN_WARNING "Failed to verify: %s\n",
831+ r->handler_path->name);
832+ }
833+ retval = -EINVAL;
834+ }
835+out:
836+ return retval;
837+}
838+
839+#endif
840+
841+/**
842+ * ccs_dump_page - Dump a page to buffer.
843+ *
844+ * @bprm: Pointer to "struct linux_binprm".
845+ * @pos: Location to dump.
846+ * @dump: Poiner to "struct ccs_page_dump".
847+ *
848+ * Returns true on success, false otherwise.
849+ */
850+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
851+ struct ccs_page_dump *dump)
852+{
853+ struct page *page;
854+ /* dump->data is released by ccs_start_execve(). */
855+ if (!dump->data) {
856+ dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
857+ if (!dump->data)
858+ return false;
859+ }
860+ /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
861+#ifdef CONFIG_MMU
862+ if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
863+ return false;
864+#else
865+ page = bprm->page[pos / PAGE_SIZE];
866+#endif
867+ if (page != dump->page) {
868+ const unsigned int offset = pos % PAGE_SIZE;
869+ /*
870+ * Maybe kmap()/kunmap() should be used here.
871+ * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
872+ * So do I.
873+ */
874+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
875+ char *kaddr = kmap_atomic(page);
876+#else
877+ char *kaddr = kmap_atomic(page, KM_USER0);
878+#endif
879+ dump->page = page;
880+ memcpy(dump->data + offset, kaddr + offset,
881+ PAGE_SIZE - offset);
882+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
883+ kunmap_atomic(kaddr);
884+#else
885+ kunmap_atomic(kaddr, KM_USER0);
886+#endif
887+ }
888+ /* Same with put_arg_page(page) in fs/exec.c */
889+#ifdef CONFIG_MMU
890+ put_page(page);
891+#endif
892+ return true;
893+}
894+
895+/**
896+ * ccs_start_execve - Prepare for execve() operation.
897+ *
898+ * @bprm: Pointer to "struct linux_binprm".
899+ * @rp: Pointer to "struct ccs_request_info *".
900+ *
901+ * Returns 0 on success, negative value otherwise.
902+ */
903+static int ccs_start_execve(struct linux_binprm *bprm,
904+ struct ccs_request_info **rp)
905+{
906+ int retval;
907+ struct ccs_security *task = ccs_current_security();
908+ struct ccs_request_info *r;
909+ int idx;
910+ *rp = NULL;
911+ r = kzalloc(sizeof(*r), GFP_NOFS);
912+ if (!r)
913+ return -ENOMEM;
914+ r->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_NOFS);
915+ if (!r->tmp) {
916+ kfree(r);
917+ return -ENOMEM;
918+ }
919+ idx = ccs_read_lock();
920+ /* r->dump->data is allocated by ccs_dump_page(). */
921+ r->previous_domain = task->ccs_domain_info;
922+ /* Clear manager flag. */
923+ task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
924+ *rp = r;
925+ r->bprm = bprm;
926+ r->obj.path[0].dentry = bprm->file->f_dentry;
927+ r->obj.path[0].mnt = bprm->file->f_vfsmnt;
928+ retval = ccs_execute(r);
929+#ifdef CONFIG_CCSECURITY_ENVIRON
930+ if (!retval && bprm->envc)
931+ retval = ccs_environ(r);
932+#endif
933+ ccs_clear_request_info(r);
934+ /* Drop refcount obtained by ccs_execute_path(). */
935+ if (r->obj.path[1].dentry) {
936+ path_put(&r->obj.path[1]);
937+ r->obj.path[1].dentry = NULL;
938+ }
939+ ccs_read_unlock(idx);
940+ kfree(r->tmp);
941+ r->tmp = NULL;
942+ kfree(r->dump.data);
943+ r->dump.data = NULL;
944+ return retval;
945+}
946+
947+/**
948+ * ccs_finish_execve - Clean up execve() operation.
949+ *
950+ * @retval: Return code of an execve() operation.
951+ * @r: Pointer to "struct ccs_request_info".
952+ *
953+ * Returns nothing.
954+ */
955+static void ccs_finish_execve(int retval, struct ccs_request_info *r)
956+{
957+ struct ccs_security *task;
958+ if (!r)
959+ return;
960+ task = ccs_current_security();
961+ if (retval < 0) {
962+ task->ccs_domain_info = r->previous_domain;
963+ /*
964+ * Make task->ccs_domain_info visible to GC before changing
965+ * task->ccs_flags.
966+ */
967+ smp_wmb();
968+ } else {
969+ /* Mark the current process as execute handler. */
970+ if (r->handler)
971+ task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
972+ /* Mark the current process as normal process. */
973+ else
974+ task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
975+ }
976+ /* Tell GC that I finished execve(). */
977+ task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
978+ ccs_clear_request_info(r);
979+ kfree(r->handler);
980+ kfree(r);
981+}
982+
983+/**
984+ * __ccs_search_binary_handler - Main routine for do_execve().
985+ *
986+ * @bprm: Pointer to "struct linux_binprm".
987+ * @regs: Pointer to "struct pt_regs".
988+ *
989+ * Returns 0 on success, negative value otherwise.
990+ *
991+ * Performs permission checks for do_execve() and domain transition.
992+ * Domain transition by "struct ccs_acl_info" will be reverted
993+ * if do_execve() failed.
994+ * Garbage collector does not remove "struct ccs_domain_info" from
995+ * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
996+ * marked as CCS_TASK_IS_IN_EXECVE.
997+ */
998+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
999+ struct pt_regs *regs)
1000+{
1001+ struct ccs_request_info *r;
1002+ int retval;
1003+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1004+ if (!ccs_policy_loaded)
1005+ ccsecurity_exports.load_policy(bprm->filename);
1006+#endif
1007+ retval = ccs_start_execve(bprm, &r);
1008+ if (!retval)
1009+ retval = search_binary_handler(bprm, regs);
1010+ ccs_finish_execve(retval, r);
1011+ return retval;
1012+}
1013+
1014+/**
1015+ * ccs_permission_init - Register permission check hooks.
1016+ *
1017+ * Returns nothing.
1018+ */
1019+void __init ccs_permission_init(void)
1020+{
1021+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1022+ ccsecurity_ops.save_open_mode = __ccs_save_open_mode;
1023+ ccsecurity_ops.clear_open_mode = __ccs_clear_open_mode;
1024+ ccsecurity_ops.open_permission = __ccs_open_permission;
1025+#else
1026+ ccsecurity_ops.open_permission = ccs_new_open_permission;
1027+#endif
1028+ ccsecurity_ops.fcntl_permission = __ccs_fcntl_permission;
1029+ ccsecurity_ops.ioctl_permission = __ccs_ioctl_permission;
1030+ ccsecurity_ops.chmod_permission = __ccs_chmod_permission;
1031+ ccsecurity_ops.chown_permission = __ccs_chown_permission;
1032+#ifdef CONFIG_CCSECURITY_GETATTR
1033+ ccsecurity_ops.getattr_permission = __ccs_getattr_permission;
1034+#endif
1035+ ccsecurity_ops.pivot_root_permission = __ccs_pivot_root_permission;
1036+ ccsecurity_ops.chroot_permission = __ccs_chroot_permission;
1037+ ccsecurity_ops.umount_permission = __ccs_umount_permission;
1038+ ccsecurity_ops.mknod_permission = __ccs_mknod_permission;
1039+ ccsecurity_ops.mkdir_permission = __ccs_mkdir_permission;
1040+ ccsecurity_ops.rmdir_permission = __ccs_rmdir_permission;
1041+ ccsecurity_ops.unlink_permission = __ccs_unlink_permission;
1042+ ccsecurity_ops.symlink_permission = __ccs_symlink_permission;
1043+ ccsecurity_ops.truncate_permission = __ccs_truncate_permission;
1044+ ccsecurity_ops.rename_permission = __ccs_rename_permission;
1045+ ccsecurity_ops.link_permission = __ccs_link_permission;
1046+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1047+ ccsecurity_ops.open_exec_permission = __ccs_open_exec_permission;
1048+ ccsecurity_ops.uselib_permission = __ccs_uselib_permission;
1049+#endif
1050+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
1051+ ccsecurity_ops.parse_table = __ccs_parse_table;
1052+#endif
1053+ ccsecurity_ops.mount_permission = __ccs_mount_permission;
1054+#ifdef CONFIG_CCSECURITY_CAPABILITY
1055+ ccsecurity_ops.capable = __ccs_capable;
1056+ ccsecurity_ops.socket_create_permission =
1057+ __ccs_socket_create_permission;
1058+#endif
1059+#ifdef CONFIG_CCSECURITY_NETWORK
1060+ ccsecurity_ops.socket_listen_permission =
1061+ __ccs_socket_listen_permission;
1062+ ccsecurity_ops.socket_connect_permission =
1063+ __ccs_socket_connect_permission;
1064+ ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission;
1065+ ccsecurity_ops.socket_post_accept_permission =
1066+ __ccs_socket_post_accept_permission;
1067+ ccsecurity_ops.socket_sendmsg_permission =
1068+ __ccs_socket_sendmsg_permission;
1069+#endif
1070+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
1071+ ccsecurity_ops.socket_post_recvmsg_permission =
1072+ __ccs_socket_post_recvmsg_permission;
1073+#endif
1074+#ifdef CONFIG_CCSECURITY_PTRACE
1075+ ccsecurity_ops.ptrace_permission = __ccs_ptrace_permission;
1076+#endif
1077+#ifdef CONFIG_CCSECURITY_SIGNAL
1078+ ccsecurity_ops.kill_permission = ccs_signal_permission0;
1079+ ccsecurity_ops.tgkill_permission = ccs_signal_permission1;
1080+ ccsecurity_ops.tkill_permission = ccs_signal_permission0;
1081+ ccsecurity_ops.sigqueue_permission = ccs_signal_permission0;
1082+ ccsecurity_ops.tgsigqueue_permission = ccs_signal_permission1;
1083+#endif
1084+ ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1085+}
1086+
1087+/**
1088+ * ccs_kern_path - Wrapper for kern_path().
1089+ *
1090+ * @pathname: Pathname to resolve. Maybe NULL.
1091+ * @flags: Lookup flags.
1092+ * @path: Pointer to "struct path".
1093+ *
1094+ * Returns 0 on success, negative value otherwise.
1095+ */
1096+static int ccs_kern_path(const char *pathname, int flags, struct path *path)
1097+{
1098+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
1099+ if (!pathname || kern_path(pathname, flags, path))
1100+ return -ENOENT;
1101+#else
1102+ struct nameidata nd;
1103+ if (!pathname || path_lookup(pathname, flags, &nd))
1104+ return -ENOENT;
1105+ *path = nd.path;
1106+#endif
1107+ return 0;
1108+}
1109+
1110+/**
1111+ * ccs_execute_path - Get dentry/vfsmount of a program.
1112+ *
1113+ * @bprm: Pointer to "struct linux_binprm".
1114+ * @path: Pointer to "struct path".
1115+ *
1116+ * Returns 0 on success, negative value otherwise.
1117+ */
1118+static int ccs_execute_path(struct linux_binprm *bprm, struct path *path)
1119+{
1120+ /*
1121+ * Follow symlinks if the requested pathname is on procfs, for
1122+ * /proc/\$/exe is meaningless.
1123+ */
1124+ const unsigned int follow =
1125+ (bprm->file->f_dentry->d_sb->s_magic == PROC_SUPER_MAGIC) ?
1126+ LOOKUP_FOLLOW : 0;
1127+ if (ccs_kern_path(bprm->filename, follow, path))
1128+ return -ENOENT;
1129+ return 0;
1130+}
1131+
1132+/**
1133+ * ccs_mount_acl - Check permission for mount() operation.
1134+ *
1135+ * @dev_name: Name of device file or mount source. Maybe NULL.
1136+ * @dir: Pointer to "struct path".
1137+ * @type: Name of filesystem type. Maybe NULL.
1138+ * @flags: Mount options.
1139+ * @data: Mount options not in @flags. Maybe NULL.
1140+ *
1141+ * Returns 0 on success, negative value otherwise.
1142+ */
1143+static int ccs_mount_acl(const char *dev_name, struct path *dir,
1144+ const char *type, unsigned long flags,
1145+ const char *data)
1146+{
1147+ struct ccs_request_info r = { };
1148+ struct ccs_path_info rtype = { };
1149+ struct ccs_path_info rdata = { };
1150+ bool check_dev = false;
1151+ bool check_data = false;
1152+ int error;
1153+
1154+ /* Compare fstype in order to determine type of dev_name argument. */
1155+ if (type == ccs_mounts[CCS_MOUNT_REMOUNT]) {
1156+ /* do_remount() case. */
1157+ if (data && !(dir->mnt->mnt_sb->s_type->fs_flags &
1158+ FS_BINARY_MOUNTDATA))
1159+ check_data = true;
1160+ } else if (type == ccs_mounts[CCS_MOUNT_BIND]) {
1161+ /* do_loopback() case. */
1162+ check_dev = true;
1163+ } else if (type == ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE] ||
1164+ type == ccs_mounts[CCS_MOUNT_MAKE_PRIVATE] ||
1165+ type == ccs_mounts[CCS_MOUNT_MAKE_SLAVE] ||
1166+ type == ccs_mounts[CCS_MOUNT_MAKE_SHARED]) {
1167+ /* do_change_type() case. */
1168+ } else if (type == ccs_mounts[CCS_MOUNT_MOVE]) {
1169+ /* do_move_mount() case. */
1170+ check_dev = true;
1171+ } else {
1172+ /* do_new_mount() case. */
1173+ struct file_system_type *fstype;
1174+ if (!type)
1175+ return -EINVAL;
1176+ fstype = get_fs_type(type);
1177+ if (!fstype)
1178+ return -ENODEV;
1179+ if (fstype->fs_flags & FS_REQUIRES_DEV)
1180+ check_dev = true;
1181+ if (data && !(fstype->fs_flags & FS_BINARY_MOUNTDATA))
1182+ check_data = true;
1183+ ccs_put_filesystem(fstype);
1184+ }
1185+ /* Start filling arguments. */
1186+ r.type = CCS_MAC_MOUNT;
1187+ /* Remember mount options. */
1188+ r.param.i[0] = flags;
1189+ /*
1190+ * Remember mount point.
1191+ * r.param.s[1] is calculated from r.obj.path[1] as needed.
1192+ */
1193+ r.obj.path[1] = *dir;
1194+ /* Remember fstype. */
1195+ rtype.name = ccs_encode(type);
1196+ if (!rtype.name)
1197+ return -ENOMEM;
1198+ ccs_fill_path_info(&rtype);
1199+ r.param.s[2] = &rtype;
1200+ if (check_data) {
1201+ /* Remember data argument. */
1202+ rdata.name = ccs_encode(data);
1203+ if (!rdata.name) {
1204+ error = -ENOMEM;
1205+ goto out;
1206+ }
1207+ ccs_fill_path_info(&rdata);
1208+ r.param.s[3] = &rdata;
1209+ }
1210+ if (check_dev) {
1211+ /*
1212+ * Remember device file or mount source.
1213+ * r.param.s[0] is calculated from r.obj.path[0] as needed.
1214+ */
1215+ if (ccs_kern_path(dev_name, LOOKUP_FOLLOW, &r.obj.path[0])) {
1216+ error = -ENOENT;
1217+ goto out;
1218+ }
1219+ }
1220+ error = ccs_check_acl(&r, false);
1221+ /* Drop refcount obtained by ccs_kern_path(). */
1222+ if (check_dev)
1223+ path_put(&r.obj.path[0]);
1224+out:
1225+ kfree(rtype.name);
1226+ kfree(rdata.name);
1227+ ccs_clear_request_info(&r);
1228+ return error;
1229+}
1230+
1231+/**
1232+ * __ccs_mount_permission - Check permission for mount() operation.
1233+ *
1234+ * @dev_name: Name of device file. Maybe NULL.
1235+ * @path: Pointer to "struct path".
1236+ * @type: Name of filesystem type. Maybe NULL.
1237+ * @flags: Mount options.
1238+ * @data_page: Mount options not in @flags. Maybe NULL.
1239+ *
1240+ * Returns 0 on success, negative value otherwise.
1241+ */
1242+static int __ccs_mount_permission(char *dev_name, struct path *path,
1243+ const char *type, unsigned long flags,
1244+ void *data_page)
1245+{
1246+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1247+ flags &= ~MS_MGC_MSK;
1248+ if (flags & MS_REMOUNT) {
1249+ type = ccs_mounts[CCS_MOUNT_REMOUNT];
1250+ flags &= ~MS_REMOUNT;
1251+ } else if (flags & MS_BIND) {
1252+ type = ccs_mounts[CCS_MOUNT_BIND];
1253+ flags &= ~MS_BIND;
1254+ } else if (flags & MS_SHARED) {
1255+ if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1256+ return -EINVAL;
1257+ type = ccs_mounts[CCS_MOUNT_MAKE_SHARED];
1258+ flags &= ~MS_SHARED;
1259+ } else if (flags & MS_PRIVATE) {
1260+ if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
1261+ return -EINVAL;
1262+ type = ccs_mounts[CCS_MOUNT_MAKE_PRIVATE];
1263+ flags &= ~MS_PRIVATE;
1264+ } else if (flags & MS_SLAVE) {
1265+ if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
1266+ return -EINVAL;
1267+ type = ccs_mounts[CCS_MOUNT_MAKE_SLAVE];
1268+ flags &= ~MS_SLAVE;
1269+ } else if (flags & MS_UNBINDABLE) {
1270+ if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
1271+ return -EINVAL;
1272+ type = ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE];
1273+ flags &= ~MS_UNBINDABLE;
1274+ } else if (flags & MS_MOVE) {
1275+ type = ccs_mounts[CCS_MOUNT_MOVE];
1276+ flags &= ~MS_MOVE;
1277+ }
1278+ /*
1279+ * do_mount() terminates data_page with '\0' if data_page != NULL.
1280+ * Therefore, it is safe to pass data_page argument to ccs_mount_acl()
1281+ * as "const char *" rather than "void *".
1282+ */
1283+ ccs_check_auto_domain_transition();
1284+ return ccs_mount_acl(dev_name, path, type, flags, data_page);
1285+}
1286+
1287+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1288+
1289+/**
1290+ * __ccs_save_open_mode - Remember original flags passed to sys_open().
1291+ *
1292+ * @mode: Flags passed to sys_open().
1293+ *
1294+ * Returns nothing.
1295+ *
1296+ * TOMOYO does not check "file write" if open(path, O_TRUNC | O_RDONLY) was
1297+ * requested because write() is not permitted. Instead, TOMOYO checks
1298+ * "file truncate" if O_TRUNC is passed.
1299+ *
1300+ * TOMOYO does not check "file read" and "file write" if open(path, 3) was
1301+ * requested because read()/write() are not permitted. Instead, TOMOYO checks
1302+ * "file ioctl" when ioctl() is requested.
1303+ */
1304+static void __ccs_save_open_mode(int mode)
1305+{
1306+ if ((mode & 3) == 3)
1307+ ccs_current_security()->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
1308+}
1309+
1310+/**
1311+ * __ccs_clear_open_mode - Forget original flags passed to sys_open().
1312+ *
1313+ * Returns nothing.
1314+ */
1315+static void __ccs_clear_open_mode(void)
1316+{
1317+ ccs_current_security()->ccs_flags &= ~CCS_OPEN_FOR_IOCTL_ONLY;
1318+}
1319+
1320+#endif
1321+
1322+/**
1323+ * __ccs_open_permission - Check permission for "read" and "write".
1324+ *
1325+ * @dentry: Pointer to "struct dentry".
1326+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1327+ * @flag: Flags for open().
1328+ *
1329+ * Returns 0 on success, negative value otherwise.
1330+ */
1331+static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
1332+ const int flag)
1333+{
1334+ struct ccs_request_info r = { };
1335+ const u32 ccs_flags = ccs_current_flags();
1336+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
1337+ const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
1338+#else
1339+ const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
1340+ ACC_MODE(flag);
1341+#endif
1342+ int error = 0;
1343+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
1344+ if (current->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
1345+ return 0;
1346+#endif
1347+#ifndef CONFIG_CCSECURITY_GETATTR
1348+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
1349+ return 0;
1350+#endif
1351+ r.obj.path[0].dentry = dentry;
1352+ r.obj.path[0].mnt = mnt;
1353+ if (!(ccs_flags & CCS_TASK_IS_IN_EXECVE))
1354+ ccs_check_auto_domain_transition();
1355+ if (acc_mode & MAY_READ) {
1356+ r.type = CCS_MAC_READ;
1357+ error = ccs_check_acl(&r, false);
1358+ }
1359+ if (!error && (acc_mode & MAY_WRITE)) {
1360+ r.type = (flag & O_APPEND) ? CCS_MAC_APPEND :
1361+ CCS_MAC_WRITE;
1362+ error = ccs_check_acl(&r, false);
1363+ }
1364+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1365+ if (!error && (flag & O_TRUNC)) {
1366+ r.type = CCS_MAC_TRUNCATE;
1367+ error = ccs_check_acl(&r, false);
1368+ }
1369+#endif
1370+ ccs_clear_request_info(&r);
1371+ return error;
1372+}
1373+
1374+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
1375+
1376+/**
1377+ * ccs_new_open_permission - Check permission for "read" and "write".
1378+ *
1379+ * @filp: Pointer to "struct file".
1380+ *
1381+ * Returns 0 on success, negative value otherwise.
1382+ */
1383+static int ccs_new_open_permission(struct file *filp)
1384+{
1385+ return __ccs_open_permission(filp->f_path.dentry, filp->f_path.mnt,
1386+ filp->f_flags);
1387+}
1388+
1389+#endif
1390+
1391+/**
1392+ * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "append", "getattr" and "chroot".
1393+ *
1394+ * @operation: One of values in "enum ccs_mac_index".
1395+ * @dentry: Pointer to "struct dentry".
1396+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1397+ *
1398+ * Returns 0 on success, negative value otherwise.
1399+ */
1400+static int ccs_path_perm(const enum ccs_mac_index operation,
1401+ struct dentry *dentry, struct vfsmount *mnt)
1402+{
1403+ struct ccs_request_info r = { };
1404+ ccs_check_auto_domain_transition();
1405+ r.type = operation;
1406+ r.obj.path[0].dentry = dentry;
1407+ r.obj.path[0].mnt = mnt;
1408+ return ccs_check_acl(&r, true);
1409+}
1410+
1411+/**
1412+ * ccs_mkdev_perm - Check permission for "mkblock" and "mkchar".
1413+ *
1414+ * @operation: Type of operation. (CCS_MAC_MKCHAR or CCS_MAC_MKBLOCK)
1415+ * @dentry: Pointer to "struct dentry".
1416+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1417+ * @mode: Create mode.
1418+ * @dev: Device number.
1419+ *
1420+ * Returns 0 on success, negative value otherwise.
1421+ */
1422+static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
1423+ struct vfsmount *mnt, const unsigned int mode,
1424+ unsigned int dev)
1425+{
1426+ struct ccs_request_info r = { };
1427+ ccs_check_auto_domain_transition();
1428+ r.obj.path[0].dentry = dentry;
1429+ r.obj.path[0].mnt = mnt;
1430+ dev = new_decode_dev(dev);
1431+ r.type = operation;
1432+ r.param.i[0] = mode;
1433+ r.param.i[1] = MAJOR(dev);
1434+ r.param.i[2] = MINOR(dev);
1435+ return ccs_check_acl(&r, true);
1436+}
1437+
1438+/**
1439+ * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
1440+ *
1441+ * @operation: One of values in "enum ccs_mac_index".
1442+ * @dentry1: Pointer to "struct dentry".
1443+ * @mnt1: Pointer to "struct vfsmount". Maybe NULL.
1444+ * @dentry2: Pointer to "struct dentry".
1445+ * @mnt2: Pointer to "struct vfsmount". Maybe NULL.
1446+ *
1447+ * Returns 0 on success, negative value otherwise.
1448+ */
1449+static int ccs_path2_perm(const enum ccs_mac_index operation,
1450+ struct dentry *dentry1, struct vfsmount *mnt1,
1451+ struct dentry *dentry2, struct vfsmount *mnt2)
1452+{
1453+ struct ccs_request_info r = { };
1454+ ccs_check_auto_domain_transition();
1455+ r.type = operation;
1456+ r.obj.path[0].dentry = dentry1;
1457+ r.obj.path[0].mnt = mnt1;
1458+ r.obj.path[1].dentry = dentry2;
1459+ r.obj.path[1].mnt = mnt2;
1460+ return ccs_check_acl(&r, true);
1461+}
1462+
1463+/**
1464+ * __ccs_symlink_permission - Check permission for "symlink".
1465+ *
1466+ * @dentry: Pointer to "struct dentry".
1467+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1468+ * @target: Content of symlink.
1469+ *
1470+ * Returns 0 on success, negative value otherwise.
1471+ */
1472+static int __ccs_symlink_permission(struct dentry *dentry,
1473+ struct vfsmount *mnt, const char *target)
1474+{
1475+ struct ccs_request_info r = { };
1476+ ccs_check_auto_domain_transition();
1477+ r.type = CCS_MAC_SYMLINK;
1478+ r.obj.path[0].dentry = dentry;
1479+ r.obj.path[0].mnt = mnt;
1480+ r.obj.pathname[1].name = ccs_encode(target);
1481+ if (!r.obj.pathname[1].name)
1482+ return -ENOMEM;
1483+ ccs_fill_path_info(&r.obj.pathname[1]);
1484+ r.param.s[1] = &r.obj.pathname[1];
1485+ return ccs_check_acl(&r, true);
1486+}
1487+
1488+/**
1489+ * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp" and "unmount".
1490+ *
1491+ * @type: One of values in "enum ccs_mac_index".
1492+ * @dentry: Pointer to "struct dentry".
1493+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
1494+ * @number: Number.
1495+ *
1496+ * Returns 0 on success, negative value otherwise.
1497+ */
1498+static int ccs_path_number_perm(const enum ccs_mac_index type,
1499+ struct dentry *dentry, struct vfsmount *vfsmnt,
1500+ unsigned long number)
1501+{
1502+ struct ccs_request_info r = { };
1503+ ccs_check_auto_domain_transition();
1504+ r.type = type;
1505+ r.obj.path[0].dentry = dentry;
1506+ r.obj.path[0].mnt = vfsmnt;
1507+ r.param.i[0] = number;
1508+ return ccs_check_acl(&r, true);
1509+}
1510+
1511+/**
1512+ * __ccs_ioctl_permission - Check permission for "ioctl".
1513+ *
1514+ * @filp: Pointer to "struct file".
1515+ * @cmd: Ioctl command number.
1516+ * @arg: Param for @cmd.
1517+ *
1518+ * Returns 0 on success, negative value otherwise.
1519+ */
1520+static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
1521+ unsigned long arg)
1522+{
1523+ return ccs_path_number_perm(CCS_MAC_IOCTL, filp->f_dentry,
1524+ filp->f_vfsmnt, cmd);
1525+}
1526+
1527+/**
1528+ * __ccs_chmod_permission - Check permission for "chmod".
1529+ *
1530+ * @dentry: Pointer to "struct dentry".
1531+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
1532+ * @mode: Mode.
1533+ *
1534+ * Returns 0 on success, negative value otherwise.
1535+ */
1536+static int __ccs_chmod_permission(struct dentry *dentry,
1537+ struct vfsmount *vfsmnt, mode_t mode)
1538+{
1539+ if (mode == (mode_t) -1)
1540+ return 0;
1541+ return ccs_path_number_perm(CCS_MAC_CHMOD, dentry, vfsmnt,
1542+ mode & S_IALLUGO);
1543+}
1544+
1545+/**
1546+ * __ccs_chown_permission - Check permission for "chown/chgrp".
1547+ *
1548+ * @dentry: Pointer to "struct dentry".
1549+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
1550+ * @user: User ID.
1551+ * @group: Group ID.
1552+ *
1553+ * Returns 0 on success, negative value otherwise.
1554+ */
1555+static int __ccs_chown_permission(struct dentry *dentry,
1556+ struct vfsmount *vfsmnt, uid_t user,
1557+ gid_t group)
1558+{
1559+ int error = 0;
1560+ if (user == (uid_t) -1 && group == (gid_t) -1)
1561+ return 0;
1562+ if (user != (uid_t) -1)
1563+ error = ccs_path_number_perm(CCS_MAC_CHOWN, dentry,
1564+ vfsmnt, user);
1565+ if (!error && group != (gid_t) -1)
1566+ error = ccs_path_number_perm(CCS_MAC_CHGRP, dentry,
1567+ vfsmnt, group);
1568+ return error;
1569+}
1570+
1571+/**
1572+ * __ccs_fcntl_permission - Check permission for changing O_APPEND flag.
1573+ *
1574+ * @file: Pointer to "struct file".
1575+ * @cmd: Command number.
1576+ * @arg: Value for @cmd.
1577+ *
1578+ * Returns 0 on success, negative value otherwise.
1579+ */
1580+static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
1581+ unsigned long arg)
1582+{
1583+ if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
1584+ return 0;
1585+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
1586+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
1587+ O_WRONLY | (arg & O_APPEND));
1588+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
1589+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
1590+ O_WRONLY | (arg & O_APPEND));
1591+#else
1592+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
1593+ (O_WRONLY + 1) | (arg & O_APPEND));
1594+#endif
1595+}
1596+
1597+/**
1598+ * __ccs_pivot_root_permission - Check permission for pivot_root().
1599+ *
1600+ * @old_path: Pointer to "struct path".
1601+ * @new_path: Pointer to "struct path".
1602+ *
1603+ * Returns 0 on success, negative value otherwise.
1604+ */
1605+static int __ccs_pivot_root_permission(struct path *old_path,
1606+ struct path *new_path)
1607+{
1608+ return ccs_path2_perm(CCS_MAC_PIVOT_ROOT, new_path->dentry,
1609+ new_path->mnt, old_path->dentry, old_path->mnt);
1610+}
1611+
1612+/**
1613+ * __ccs_chroot_permission - Check permission for chroot().
1614+ *
1615+ * @path: Pointer to "struct path".
1616+ *
1617+ * Returns 0 on success, negative value otherwise.
1618+ */
1619+static int __ccs_chroot_permission(struct path *path)
1620+{
1621+ return ccs_path_perm(CCS_MAC_CHROOT, path->dentry, path->mnt);
1622+}
1623+
1624+/**
1625+ * __ccs_umount_permission - Check permission for unmount.
1626+ *
1627+ * @mnt: Pointer to "struct vfsmount".
1628+ * @flags: Unmount flags.
1629+ *
1630+ * Returns 0 on success, negative value otherwise.
1631+ */
1632+static int __ccs_umount_permission(struct vfsmount *mnt, int flags)
1633+{
1634+ return ccs_path_number_perm(CCS_MAC_UMOUNT, mnt->mnt_root, mnt, flags);
1635+}
1636+
1637+/**
1638+ * __ccs_mknod_permission - Check permission for vfs_mknod().
1639+ *
1640+ * @dentry: Pointer to "struct dentry".
1641+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1642+ * @mode: Device type and permission.
1643+ * @dev: Device number for block or character device.
1644+ *
1645+ * Returns 0 on success, negative value otherwise.
1646+ */
1647+static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
1648+ const unsigned int mode, unsigned int dev)
1649+{
1650+ int error = 0;
1651+ const unsigned int perm = mode & S_IALLUGO;
1652+ switch (mode & S_IFMT) {
1653+ case S_IFCHR:
1654+ error = ccs_mkdev_perm(CCS_MAC_MKCHAR, dentry, mnt, perm,
1655+ dev);
1656+ break;
1657+ case S_IFBLK:
1658+ error = ccs_mkdev_perm(CCS_MAC_MKBLOCK, dentry, mnt, perm,
1659+ dev);
1660+ break;
1661+ case S_IFIFO:
1662+ error = ccs_path_number_perm(CCS_MAC_MKFIFO, dentry, mnt,
1663+ perm);
1664+ break;
1665+ case S_IFSOCK:
1666+ error = ccs_path_number_perm(CCS_MAC_MKSOCK, dentry, mnt,
1667+ perm);
1668+ break;
1669+ case 0:
1670+ case S_IFREG:
1671+ error = ccs_path_number_perm(CCS_MAC_CREATE, dentry, mnt,
1672+ perm);
1673+ break;
1674+ }
1675+ return error;
1676+}
1677+
1678+/**
1679+ * __ccs_mkdir_permission - Check permission for vfs_mkdir().
1680+ *
1681+ * @dentry: Pointer to "struct dentry".
1682+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1683+ * @mode: Create mode.
1684+ *
1685+ * Returns 0 on success, negative value otherwise.
1686+ */
1687+static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
1688+ unsigned int mode)
1689+{
1690+ return ccs_path_number_perm(CCS_MAC_MKDIR, dentry, mnt, mode);
1691+}
1692+
1693+/**
1694+ * __ccs_rmdir_permission - Check permission for vfs_rmdir().
1695+ *
1696+ * @dentry: Pointer to "struct dentry".
1697+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1698+ *
1699+ * Returns 0 on success, negative value otherwise.
1700+ */
1701+static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt)
1702+{
1703+ return ccs_path_perm(CCS_MAC_RMDIR, dentry, mnt);
1704+}
1705+
1706+/**
1707+ * __ccs_unlink_permission - Check permission for vfs_unlink().
1708+ *
1709+ * @dentry: Pointer to "struct dentry".
1710+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1711+ *
1712+ * Returns 0 on success, negative value otherwise.
1713+ */
1714+static int __ccs_unlink_permission(struct dentry *dentry, struct vfsmount *mnt)
1715+{
1716+ return ccs_path_perm(CCS_MAC_UNLINK, dentry, mnt);
1717+}
1718+
1719+#ifdef CONFIG_CCSECURITY_GETATTR
1720+
1721+/**
1722+ * __ccs_getattr_permission - Check permission for vfs_getattr().
1723+ *
1724+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1725+ * @dentry: Pointer to "struct dentry".
1726+ *
1727+ * Returns 0 on success, negative value otherwise.
1728+ */
1729+static int __ccs_getattr_permission(struct vfsmount *mnt,
1730+ struct dentry *dentry)
1731+{
1732+ return ccs_path_perm(CCS_MAC_GETATTR, dentry, mnt);
1733+}
1734+
1735+#endif
1736+
1737+/**
1738+ * __ccs_truncate_permission - Check permission for notify_change().
1739+ *
1740+ * @dentry: Pointer to "struct dentry".
1741+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1742+ *
1743+ * Returns 0 on success, negative value otherwise.
1744+ */
1745+static int __ccs_truncate_permission(struct dentry *dentry,
1746+ struct vfsmount *mnt)
1747+{
1748+ return ccs_path_perm(CCS_MAC_TRUNCATE, dentry, mnt);
1749+}
1750+
1751+/**
1752+ * __ccs_rename_permission - Check permission for vfs_rename().
1753+ *
1754+ * @old_dentry: Pointer to "struct dentry".
1755+ * @new_dentry: Pointer to "struct dentry".
1756+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1757+ *
1758+ * Returns 0 on success, negative value otherwise.
1759+ */
1760+static int __ccs_rename_permission(struct dentry *old_dentry,
1761+ struct dentry *new_dentry,
1762+ struct vfsmount *mnt)
1763+{
1764+ return ccs_path2_perm(CCS_MAC_RENAME, old_dentry, mnt, new_dentry,
1765+ mnt);
1766+}
1767+
1768+/**
1769+ * __ccs_link_permission - Check permission for vfs_link().
1770+ *
1771+ * @old_dentry: Pointer to "struct dentry".
1772+ * @new_dentry: Pointer to "struct dentry".
1773+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1774+ *
1775+ * Returns 0 on success, negative value otherwise.
1776+ */
1777+static int __ccs_link_permission(struct dentry *old_dentry,
1778+ struct dentry *new_dentry,
1779+ struct vfsmount *mnt)
1780+{
1781+ return ccs_path2_perm(CCS_MAC_LINK, old_dentry, mnt, new_dentry,
1782+ mnt);
1783+}
1784+
1785+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1786+
1787+/**
1788+ * __ccs_open_exec_permission - Check permission for open_exec().
1789+ *
1790+ * @dentry: Pointer to "struct dentry".
1791+ * @mnt: Pointer to "struct vfsmount".
1792+ *
1793+ * Returns 0 on success, negative value otherwise.
1794+ */
1795+static int __ccs_open_exec_permission(struct dentry *dentry,
1796+ struct vfsmount *mnt)
1797+{
1798+ return (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE) ?
1799+ __ccs_open_permission(dentry, mnt, O_RDONLY + 1) : 0;
1800+}
1801+
1802+/**
1803+ * __ccs_uselib_permission - Check permission for sys_uselib().
1804+ *
1805+ * @dentry: Pointer to "struct dentry".
1806+ * @mnt: Pointer to "struct vfsmount".
1807+ *
1808+ * Returns 0 on success, negative value otherwise.
1809+ */
1810+static int __ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
1811+{
1812+ return __ccs_open_permission(dentry, mnt, O_RDONLY + 1);
1813+}
1814+
1815+#endif
1816+
1817+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
1818+
1819+/**
1820+ * ccs_sysctl_permission - Check permission for sysctl operation.
1821+ *
1822+ * @type: One of values in "enum ccs_mac_index".
1823+ * @filename: Filename to check.
1824+ *
1825+ * Returns 0 on success, negative value otherwise.
1826+ */
1827+static int ccs_sysctl_permission(enum ccs_mac_index type,
1828+ const struct ccs_path_info *filename)
1829+{
1830+ struct ccs_request_info r = { };
1831+ r.type = type;
1832+ r.param.s[0] = filename;
1833+ return ccs_check_acl(&r, true);
1834+}
1835+
1836+/**
1837+ * __ccs_parse_table - Check permission for parse_table().
1838+ *
1839+ * @name: Pointer to "int __user".
1840+ * @nlen: Number of elements in @name.
1841+ * @oldval: Pointer to "void __user".
1842+ * @newval: Pointer to "void __user".
1843+ * @table: Pointer to "struct ctl_table".
1844+ *
1845+ * Returns 0 on success, negative value otherwise.
1846+ *
1847+ * Note that this function is racy because this function checks values in
1848+ * userspace memory which could be changed after permission check.
1849+ */
1850+static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
1851+ void __user *newval, struct ctl_table *table)
1852+{
1853+ int n;
1854+ int error = -ENOMEM;
1855+ int op = 0;
1856+ struct ccs_path_info buf;
1857+ char *buffer = NULL;
1858+ if (oldval)
1859+ op |= 004;
1860+ if (newval)
1861+ op |= 002;
1862+ if (!op) /* Neither read nor write */
1863+ return 0;
1864+ buffer = kmalloc(PAGE_SIZE, GFP_NOFS);
1865+ if (!buffer)
1866+ goto out;
1867+ snprintf(buffer, PAGE_SIZE - 1, "proc:/sys");
1868+repeat:
1869+ if (!nlen) {
1870+ error = -ENOTDIR;
1871+ goto out;
1872+ }
1873+ if (get_user(n, name)) {
1874+ error = -EFAULT;
1875+ goto out;
1876+ }
1877+ for ( ; table->ctl_name || table->procname; table++) {
1878+ int pos;
1879+ const char *cp;
1880+ if (!n || n != table->ctl_name)
1881+ continue;
1882+ pos = strlen(buffer);
1883+ cp = table->procname;
1884+ error = -ENOMEM;
1885+ if (cp) {
1886+ int len = strlen(cp);
1887+ if (len + 2 > PAGE_SIZE - 1)
1888+ goto out;
1889+ buffer[pos++] = '/';
1890+ memmove(buffer + pos, cp, len + 1);
1891+ } else {
1892+ /* Assume nobody assigns "=\$=" for procname. */
1893+ snprintf(buffer + pos, PAGE_SIZE - pos - 1,
1894+ "/=%d=", table->ctl_name);
1895+ if (!memchr(buffer, '\0', PAGE_SIZE - 2))
1896+ goto out;
1897+ }
1898+ if (!table->child)
1899+ goto no_child;
1900+ name++;
1901+ nlen--;
1902+ table = table->child;
1903+ goto repeat;
1904+no_child:
1905+ /* printk("sysctl='%s'\n", buffer); */
1906+ buf.name = ccs_encode(buffer);
1907+ if (!buf.name)
1908+ goto out;
1909+ ccs_fill_path_info(&buf);
1910+ if (op & MAY_READ)
1911+ error = ccs_sysctl_permission(CCS_MAC_READ, &buf);
1912+ else
1913+ error = 0;
1914+ if (!error && (op & MAY_WRITE))
1915+ error = ccs_sysctl_permission(CCS_MAC_WRITE,
1916+ &buf);
1917+ kfree(buf.name);
1918+ goto out;
1919+ }
1920+ error = -ENOTDIR;
1921+out:
1922+ kfree(buffer);
1923+ return error;
1924+}
1925+
1926+#endif
1927+
1928+#ifdef CONFIG_CCSECURITY_NETWORK
1929+
1930+/**
1931+ * ccs_ip_matches_group - Check whether the given IP address matches members of the given IP group.
1932+ *
1933+ * @is_ipv6: True if @address is an IPv6 address.
1934+ * @address: An IPv4 or IPv6 address.
1935+ * @group: Pointer to "struct ccs_ip_group".
1936+ *
1937+ * Returns true if @address matches addresses in @group group, false otherwise.
1938+ *
1939+ * Caller holds ccs_read_lock().
1940+ */
1941+static bool ccs_ip_matches_group(const bool is_ipv6, const u8 *address,
1942+ const struct ccs_group *group)
1943+{
1944+ struct ccs_ip_group *member;
1945+ bool matched = false;
1946+ const u8 size = is_ipv6 ? 16 : 4;
1947+ list_for_each_entry_srcu(member, &group->member_list, head.list,
1948+ &ccs_ss) {
1949+ if (member->head.is_deleted)
1950+ continue;
1951+ if (member->is_ipv6 != is_ipv6)
1952+ continue;
1953+ if (memcmp(&member->ip[0], address, size) > 0 ||
1954+ memcmp(address, &member->ip[1], size) > 0)
1955+ continue;
1956+ matched = true;
1957+ break;
1958+ }
1959+ return matched;
1960+}
1961+
1962+/**
1963+ * ccs_inet_entry - Check permission for INET network operation.
1964+ *
1965+ * @address: Pointer to "struct ccs_addr_info".
1966+ *
1967+ * Returns 0 on success, negative value otherwise.
1968+ */
1969+static int ccs_inet_entry(const struct ccs_addr_info *address)
1970+{
1971+ struct ccs_request_info r = { };
1972+ ccs_check_auto_domain_transition();
1973+ r.type = address->operation;
1974+ r.param.is_ipv6 = address->inet.is_ipv6;
1975+ r.param.ip = address->inet.address;
1976+ r.param.i[0] = ntohs(address->inet.port);
1977+ return ccs_check_acl(&r, true);
1978+}
1979+
1980+/**
1981+ * ccs_check_inet_address - Check permission for inet domain socket's operation.
1982+ *
1983+ * @addr: Pointer to "struct sockaddr".
1984+ * @addr_len: Size of @addr.
1985+ * @port: Port number.
1986+ * @address: Pointer to "struct ccs_addr_info".
1987+ *
1988+ * Returns 0 on success, negative value otherwise.
1989+ */
1990+static int ccs_check_inet_address(const struct sockaddr *addr,
1991+ const unsigned int addr_len, const u16 port,
1992+ struct ccs_addr_info *address)
1993+{
1994+ struct ccs_inet_addr_info *i = &address->inet;
1995+ switch (addr->sa_family) {
1996+ case AF_INET6:
1997+ if (addr_len < SIN6_LEN_RFC2133)
1998+ goto skip;
1999+ i->is_ipv6 = true;
2000+ i->address =
2001+ ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
2002+ i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
2003+ break;
2004+ case AF_INET:
2005+ if (addr_len < sizeof(struct sockaddr_in))
2006+ goto skip;
2007+ i->is_ipv6 = false;
2008+ i->address = (u8 *) &((struct sockaddr_in *) addr)->sin_addr;
2009+ i->port = ((struct sockaddr_in *) addr)->sin_port;
2010+ break;
2011+ default:
2012+ goto skip;
2013+ }
2014+ if (address->operation == CCS_MAC_INET_RAW_BIND ||
2015+ address->operation == CCS_MAC_INET_RAW_SEND ||
2016+ address->operation == CCS_MAC_INET_RAW_RECV)
2017+ i->port = htons(port);
2018+ return ccs_inet_entry(address);
2019+skip:
2020+ return 0;
2021+}
2022+
2023+/**
2024+ * ccs_unix_entry - Check permission for UNIX network operation.
2025+ *
2026+ * @address: Pointer to "struct ccs_addr_info".
2027+ *
2028+ * Returns 0 on success, negative value otherwise.
2029+ */
2030+static int ccs_unix_entry(const struct ccs_addr_info *address)
2031+{
2032+ int error;
2033+ char *buf = address->unix0.addr;
2034+ int len = address->unix0.addr_len - sizeof(sa_family_t);
2035+ if (len <= 0) {
2036+ buf = "anonymous";
2037+ len = 9;
2038+ } else if (buf[0]) {
2039+ len = strnlen(buf, len);
2040+ }
2041+ buf = ccs_encode2(buf, len);
2042+ if (buf) {
2043+ struct ccs_path_info addr;
2044+ struct ccs_request_info r = { };
2045+ addr.name = buf;
2046+ ccs_fill_path_info(&addr);
2047+ r.type = address->operation;
2048+ r.param.s[0] = &addr;
2049+ error = ccs_check_acl(&r, true);
2050+ kfree(buf);
2051+ } else
2052+ error = -ENOMEM;
2053+ return error;
2054+}
2055+
2056+/**
2057+ * ccs_check_unix_address - Check permission for unix domain socket's operation.
2058+ *
2059+ * @addr: Pointer to "struct sockaddr".
2060+ * @addr_len: Size of @addr.
2061+ * @address: Pointer to "struct ccs_addr_info".
2062+ *
2063+ * Returns 0 on success, negative value otherwise.
2064+ */
2065+static int ccs_check_unix_address(struct sockaddr *addr,
2066+ const unsigned int addr_len,
2067+ struct ccs_addr_info *address)
2068+{
2069+ struct ccs_unix_addr_info *u = &address->unix0;
2070+ if (addr->sa_family != AF_UNIX)
2071+ return 0;
2072+ u->addr = ((struct sockaddr_un *) addr)->sun_path;
2073+ u->addr_len = addr_len;
2074+ return ccs_unix_entry(address);
2075+}
2076+
2077+/**
2078+ * ccs_sock_family - Get socket's family.
2079+ *
2080+ * @sk: Pointer to "struct sock".
2081+ *
2082+ * Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
2083+ */
2084+static u8 ccs_sock_family(struct sock *sk)
2085+{
2086+ u8 family;
2087+ if (ccs_kernel_service())
2088+ return 0;
2089+ family = sk->sk_family;
2090+ switch (family) {
2091+ case PF_INET:
2092+ case PF_INET6:
2093+ case PF_UNIX:
2094+ return family;
2095+ default:
2096+ return 0;
2097+ }
2098+}
2099+
2100+/**
2101+ * __ccs_socket_listen_permission - Check permission for listening a socket.
2102+ *
2103+ * @sock: Pointer to "struct socket".
2104+ *
2105+ * Returns 0 on success, negative value otherwise.
2106+ */
2107+static int __ccs_socket_listen_permission(struct socket *sock)
2108+{
2109+ struct ccs_addr_info address;
2110+ const u8 family = ccs_sock_family(sock->sk);
2111+ const unsigned int type = sock->type;
2112+ struct sockaddr_storage addr;
2113+ int addr_len;
2114+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
2115+ return 0;
2116+ {
2117+ const int error = sock->ops->getname(sock, (struct sockaddr *)
2118+ &addr, &addr_len, 0);
2119+ if (error)
2120+ return error;
2121+ }
2122+ if (family == PF_INET || family == PF_INET6)
2123+ address.operation = CCS_MAC_INET_STREAM_LISTEN;
2124+ else if (type == SOCK_STREAM)
2125+ address.operation = CCS_MAC_UNIX_STREAM_LISTEN;
2126+ else
2127+ address.operation = CCS_MAC_UNIX_SEQPACKET_LISTEN;
2128+ if (family == PF_UNIX)
2129+ return ccs_check_unix_address((struct sockaddr *) &addr,
2130+ addr_len, &address);
2131+ return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
2132+ &address);
2133+}
2134+
2135+/**
2136+ * __ccs_socket_connect_permission - Check permission for setting the remote address of a socket.
2137+ *
2138+ * @sock: Pointer to "struct socket".
2139+ * @addr: Pointer to "struct sockaddr".
2140+ * @addr_len: Size of @addr.
2141+ *
2142+ * Returns 0 on success, negative value otherwise.
2143+ */
2144+static int __ccs_socket_connect_permission(struct socket *sock,
2145+ struct sockaddr *addr, int addr_len)
2146+{
2147+ struct ccs_addr_info address;
2148+ const u8 family = ccs_sock_family(sock->sk);
2149+ if (!family)
2150+ return 0;
2151+ switch (sock->type) {
2152+ case SOCK_DGRAM:
2153+ address.operation = family == PF_UNIX ?
2154+ CCS_MAC_UNIX_DGRAM_SEND :
2155+ CCS_MAC_INET_DGRAM_SEND;
2156+ break;
2157+ case SOCK_RAW:
2158+ address.operation = CCS_MAC_INET_RAW_SEND;
2159+ break;
2160+ case SOCK_STREAM:
2161+ address.operation = family == PF_UNIX ?
2162+ CCS_MAC_UNIX_STREAM_CONNECT :
2163+ CCS_MAC_INET_STREAM_CONNECT;
2164+ break;
2165+ case SOCK_SEQPACKET:
2166+ address.operation = CCS_MAC_UNIX_SEQPACKET_CONNECT;
2167+ break;
2168+ default:
2169+ return 0;
2170+ }
2171+ if (family == PF_UNIX)
2172+ return ccs_check_unix_address(addr, addr_len, &address);
2173+ return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
2174+ &address);
2175+}
2176+
2177+/**
2178+ * __ccs_socket_bind_permission - Check permission for setting the local address of a socket.
2179+ *
2180+ * @sock: Pointer to "struct socket".
2181+ * @addr: Pointer to "struct sockaddr".
2182+ * @addr_len: Size of @addr.
2183+ *
2184+ * Returns 0 on success, negative value otherwise.
2185+ */
2186+static int __ccs_socket_bind_permission(struct socket *sock,
2187+ struct sockaddr *addr, int addr_len)
2188+{
2189+ struct ccs_addr_info address;
2190+ const u8 family = ccs_sock_family(sock->sk);
2191+ const unsigned int type = sock->type;
2192+ if (!family)
2193+ return 0;
2194+ switch (type) {
2195+ case SOCK_STREAM:
2196+ address.operation = family == PF_UNIX ?
2197+ CCS_MAC_UNIX_STREAM_BIND :
2198+ CCS_MAC_INET_STREAM_BIND;
2199+ break;
2200+ case SOCK_DGRAM:
2201+ address.operation = family == PF_UNIX ?
2202+ CCS_MAC_UNIX_DGRAM_BIND :
2203+ CCS_MAC_INET_DGRAM_BIND;
2204+ break;
2205+ case SOCK_RAW:
2206+ address.operation = CCS_MAC_INET_RAW_BIND;
2207+ break;
2208+ case SOCK_SEQPACKET:
2209+ address.operation = CCS_MAC_UNIX_SEQPACKET_BIND;
2210+ break;
2211+ default:
2212+ return 0;
2213+ }
2214+ if (family == PF_UNIX)
2215+ return ccs_check_unix_address(addr, addr_len, &address);
2216+ return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
2217+ &address);
2218+}
2219+
2220+/**
2221+ * __ccs_socket_sendmsg_permission - Check permission for sending a datagram.
2222+ *
2223+ * @sock: Pointer to "struct socket".
2224+ * @msg: Pointer to "struct msghdr".
2225+ * @size: Unused.
2226+ *
2227+ * Returns 0 on success, negative value otherwise.
2228+ */
2229+static int __ccs_socket_sendmsg_permission(struct socket *sock,
2230+ struct msghdr *msg, int size)
2231+{
2232+ struct ccs_addr_info address;
2233+ const u8 family = ccs_sock_family(sock->sk);
2234+ const unsigned int type = sock->type;
2235+ if (!msg->msg_name || !family ||
2236+ (type != SOCK_DGRAM && type != SOCK_RAW))
2237+ return 0;
2238+ if (family == PF_UNIX)
2239+ address.operation = CCS_MAC_UNIX_DGRAM_SEND;
2240+ else if (type == SOCK_DGRAM)
2241+ address.operation = CCS_MAC_INET_DGRAM_SEND;
2242+ else
2243+ address.operation = CCS_MAC_INET_RAW_SEND;
2244+ if (family == PF_UNIX)
2245+ return ccs_check_unix_address((struct sockaddr *)
2246+ msg->msg_name, msg->msg_namelen,
2247+ &address);
2248+ return ccs_check_inet_address((struct sockaddr *) msg->msg_name,
2249+ msg->msg_namelen, sock->sk->sk_protocol,
2250+ &address);
2251+}
2252+
2253+/**
2254+ * __ccs_socket_post_accept_permission - Check permission for accepting a socket.
2255+ *
2256+ * @sock: Pointer to "struct socket".
2257+ * @newsock: Pointer to "struct socket".
2258+ *
2259+ * Returns 0 on success, negative value otherwise.
2260+ */
2261+static int __ccs_socket_post_accept_permission(struct socket *sock,
2262+ struct socket *newsock)
2263+{
2264+ struct ccs_addr_info address;
2265+ const u8 family = ccs_sock_family(sock->sk);
2266+ const unsigned int type = sock->type;
2267+ struct sockaddr_storage addr;
2268+ int addr_len;
2269+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
2270+ return 0;
2271+ {
2272+ const int error = newsock->ops->getname(newsock,
2273+ (struct sockaddr *)
2274+ &addr, &addr_len, 2);
2275+ if (error)
2276+ return error;
2277+ }
2278+ if (family == PF_INET || family == PF_INET6)
2279+ address.operation = CCS_MAC_INET_STREAM_ACCEPT;
2280+ else if (type == SOCK_STREAM)
2281+ address.operation = CCS_MAC_UNIX_STREAM_ACCEPT;
2282+ else
2283+ address.operation = CCS_MAC_UNIX_SEQPACKET_ACCEPT;
2284+ if (family == PF_UNIX)
2285+ return ccs_check_unix_address((struct sockaddr *) &addr,
2286+ addr_len, &address);
2287+ return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
2288+ &address);
2289+}
2290+
2291+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
2292+
2293+/**
2294+ * __ccs_socket_post_recvmsg_permission - Check permission for receiving a datagram.
2295+ *
2296+ * @sk: Pointer to "struct sock".
2297+ * @skb: Pointer to "struct sk_buff".
2298+ * @flags: Flags passed to skb_recv_datagram().
2299+ *
2300+ * Returns 0 on success, negative value otherwise.
2301+ */
2302+static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
2303+ struct sk_buff *skb, int flags)
2304+{
2305+ struct ccs_addr_info address;
2306+ const u8 family = ccs_sock_family(sk);
2307+ const unsigned int type = sk->sk_type;
2308+ struct sockaddr_storage addr;
2309+ if (!family || (type != SOCK_DGRAM && type != SOCK_RAW))
2310+ return 0;
2311+ if (family == PF_UNIX)
2312+ address.operation = CCS_MAC_UNIX_DGRAM_RECV;
2313+ else if (type == SOCK_DGRAM)
2314+ address.operation = CCS_MAC_INET_DGRAM_RECV;
2315+ else
2316+ address.operation = CCS_MAC_INET_RAW_RECV;
2317+ switch (family) {
2318+ case PF_INET6:
2319+ {
2320+ struct in6_addr *sin6 = (struct in6_addr *) &addr;
2321+ address.inet.is_ipv6 = true;
2322+ if (type == SOCK_DGRAM &&
2323+ skb->protocol == htons(ETH_P_IP))
2324+ ipv6_addr_set(sin6, 0, 0, htonl(0xffff),
2325+ ip_hdr(skb)->saddr);
2326+ else
2327+ *sin6 = ipv6_hdr(skb)->saddr;
2328+ break;
2329+ }
2330+ case PF_INET:
2331+ {
2332+ struct in_addr *sin4 = (struct in_addr *) &addr;
2333+ address.inet.is_ipv6 = false;
2334+ sin4->s_addr = ip_hdr(skb)->saddr;
2335+ break;
2336+ }
2337+ default: /* == PF_UNIX */
2338+ {
2339+ struct unix_address *u = unix_sk(skb->sk)->addr;
2340+ unsigned int addr_len;
2341+ if (u && u->len <= sizeof(addr)) {
2342+ addr_len = u->len;
2343+ memcpy(&addr, u->name, addr_len);
2344+ } else {
2345+ addr_len = 0;
2346+ addr.ss_family = AF_UNIX;
2347+ }
2348+ if (ccs_check_unix_address((struct sockaddr *) &addr,
2349+ addr_len, &address))
2350+ goto out;
2351+ return 0;
2352+ }
2353+ }
2354+ address.inet.address = (u8 *) &addr;
2355+ if (type == SOCK_DGRAM)
2356+ address.inet.port = udp_hdr(skb)->source;
2357+ else
2358+ address.inet.port = htons(sk->sk_protocol);
2359+ if (ccs_inet_entry(&address))
2360+ goto out;
2361+ return 0;
2362+out:
2363+ /*
2364+ * Remove from queue if MSG_PEEK is used so that
2365+ * the head message from unwanted source in receive queue will not
2366+ * prevent the caller from picking up next message from wanted source
2367+ * when the caller is using MSG_PEEK flag for picking up.
2368+ */
2369+ {
2370+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
2371+ bool slow = false;
2372+ if (type == SOCK_DGRAM && family != PF_UNIX)
2373+ slow = lock_sock_fast(sk);
2374+#else
2375+ if (type == SOCK_DGRAM && family != PF_UNIX)
2376+ lock_sock(sk);
2377+#endif
2378+ skb_kill_datagram(sk, skb, flags);
2379+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
2380+ if (type == SOCK_DGRAM && family != PF_UNIX)
2381+ unlock_sock_fast(sk, slow);
2382+#else
2383+ if (type == SOCK_DGRAM && family != PF_UNIX)
2384+ release_sock(sk);
2385+#endif
2386+ }
2387+ return -EPERM;
2388+}
2389+
2390+#endif
2391+
2392+#endif
2393+
2394+#if defined(CONFIG_CCSECURITY_CAPABILITY) || defined(CONFIG_CCSECURITY_NETWORK)
2395+
2396+/**
2397+ * ccs_kernel_service - Check whether I'm kernel service or not.
2398+ *
2399+ * Returns true if I'm kernel service, false otherwise.
2400+ */
2401+static bool ccs_kernel_service(void)
2402+{
2403+ /* Nothing to do if I am a kernel service. */
2404+ return segment_eq(get_fs(), KERNEL_DS);
2405+}
2406+
2407+#endif
2408+
2409+#ifdef CONFIG_CCSECURITY_CAPABILITY
2410+
2411+/**
2412+ * ccs_capable - Check permission for capability.
2413+ *
2414+ * @operation: Type of operation.
2415+ *
2416+ * Returns true on success, false otherwise.
2417+ */
2418+static bool __ccs_capable(const u8 operation)
2419+{
2420+ struct ccs_request_info r = { };
2421+ r.type = ccs_c2mac[operation];
2422+ return !ccs_check_acl(&r, true);
2423+}
2424+
2425+/**
2426+ * __ccs_socket_create_permission - Check permission for creating a socket.
2427+ *
2428+ * @family: Protocol family.
2429+ * @type: Unused.
2430+ * @protocol: Unused.
2431+ *
2432+ * Returns 0 on success, negative value otherwise.
2433+ */
2434+static int __ccs_socket_create_permission(int family, int type, int protocol)
2435+{
2436+ if (ccs_kernel_service())
2437+ return 0;
2438+ if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
2439+ return -EPERM;
2440+ if (family == PF_NETLINK && !ccs_capable(CCS_USE_ROUTE_SOCKET))
2441+ return -EPERM;
2442+ return 0;
2443+}
2444+
2445+#endif
2446+
2447+/**
2448+ * ccs_manager - Check whether the current process is a policy manager.
2449+ *
2450+ * Returns true if the current process is permitted to modify policy
2451+ * via /proc/ccs/ interface.
2452+ *
2453+ * Caller holds ccs_read_lock().
2454+ */
2455+bool ccs_manager(void)
2456+{
2457+ struct ccs_security *task;
2458+ if (!ccs_policy_loaded)
2459+ return true;
2460+ task = ccs_current_security();
2461+ if (task->ccs_flags & CCS_TASK_IS_MANAGER)
2462+ return true;
2463+ {
2464+ struct ccs_request_info r = { };
2465+ r.type = CCS_MAC_MODIFY_POLICY;
2466+ if (ccs_check_acl(&r, true) == 0) {
2467+ /* Set manager flag. */
2468+ task->ccs_flags |= CCS_TASK_IS_MANAGER;
2469+ return true;
2470+ }
2471+ }
2472+ { /* Reduce error messages. */
2473+ static pid_t ccs_last_pid;
2474+ const pid_t pid = current->pid;
2475+ if (ccs_last_pid != pid) {
2476+ const char *exe = ccs_get_exe();
2477+ printk(KERN_WARNING "'%s' (pid=%u domain='%s') is"
2478+ " not permitted to update policies.\n", exe,
2479+ pid, task->ccs_domain_info->domainname->name);
2480+ ccs_last_pid = pid;
2481+ kfree(exe);
2482+ }
2483+ }
2484+ return false;
2485+}
2486+
2487+#ifdef CONFIG_CCSECURITY_PTRACE
2488+
2489+/**
2490+ * __ccs_ptrace_permission - Check permission for ptrace().
2491+ *
2492+ * @request: Command number.
2493+ * @pid: Target's PID.
2494+ *
2495+ * Returns 0 on success, negative value otherwise.
2496+ */
2497+static int __ccs_ptrace_permission(long request, long pid)
2498+{
2499+ struct ccs_domain_info *dest;
2500+ int error = -ESRCH;
2501+ const int idx = ccs_read_lock();
2502+ ccs_check_auto_domain_transition();
2503+ if (request == PTRACE_TRACEME) {
2504+ dest = ccs_current_domain();
2505+ } else {
2506+ struct task_struct *p;
2507+ ccs_tasklist_lock();
2508+ p = ccsecurity_exports.find_task_by_vpid((pid_t) pid);
2509+ if (p)
2510+ dest = ccs_task_domain(p);
2511+ else
2512+ dest = NULL;
2513+ ccs_tasklist_unlock();
2514+ }
2515+ if (dest) {
2516+ struct ccs_request_info r = { };
2517+ r.type = CCS_MAC_PTRACE;
2518+ r.param.i[0] = request;
2519+ r.param.s[0] = dest->domainname;
2520+ error = ccs_check_acl(&r, true);
2521+ }
2522+ ccs_read_unlock(idx);
2523+ return error;
2524+}
2525+
2526+#endif
2527+
2528+#ifdef CONFIG_CCSECURITY_SIGNAL
2529+
2530+/**
2531+ * __ccs_signal_permission - Check permission for signal.
2532+ *
2533+ * @sig: Signal number.
2534+ *
2535+ * Returns 0 on success, negative value otherwise.
2536+ *
2537+ * Caller holds ccs_read_lock().
2538+ */
2539+static int __ccs_signal_permission(const int sig)
2540+{
2541+ struct ccs_request_info r = { };
2542+ const int idx = ccs_read_lock();
2543+ int error;
2544+ ccs_check_auto_domain_transition();
2545+ r.type = CCS_MAC_SIGNAL;
2546+ r.param.i[0] = sig;
2547+ error = ccs_check_acl(&r, true);
2548+ ccs_read_unlock(idx);
2549+ return error;
2550+}
2551+
2552+/**
2553+ * ccs_signal_permission0 - Check permission for signal.
2554+ *
2555+ * @pid: Unused.
2556+ * @sig: Signal number.
2557+ *
2558+ * Returns 0 on success, negative value otherwise.
2559+ */
2560+static int ccs_signal_permission0(const int pid, const int sig)
2561+{
2562+ return __ccs_signal_permission(sig);
2563+}
2564+
2565+/**
2566+ * ccs_signal_permission1 - Permission check for signal().
2567+ *
2568+ * @tgid: Unused.
2569+ * @pid: Unused.
2570+ * @sig: Signal number.
2571+ *
2572+ * Returns 0 on success, negative value otherwise.
2573+ */
2574+static int ccs_signal_permission1(pid_t tgid, pid_t pid, int sig)
2575+{
2576+ return __ccs_signal_permission(sig);
2577+}
2578+
2579+#endif
2580+
2581+#ifdef CONFIG_CCSECURITY_ENVIRON
2582+
2583+/**
2584+ * ccs_env_perm - Check permission for environment variable's name.
2585+ *
2586+ * @r: Pointer to "struct ccs_request_info".
2587+ * @name: Name of environment variable. Maybe "".
2588+ * @value: Value of environment variable. Maybe "".
2589+ *
2590+ * Returns 0 on success, negative value otherwise.
2591+ */
2592+static int ccs_env_perm(struct ccs_request_info *r, const char *name,
2593+ const char *value)
2594+{
2595+ struct ccs_path_info n;
2596+ struct ccs_path_info v;
2597+ n.name = name;
2598+ ccs_fill_path_info(&n);
2599+ v.name = value;
2600+ ccs_fill_path_info(&v);
2601+ r->type = CCS_MAC_ENVIRON;
2602+ r->param.s[2] = &n;
2603+ r->param.s[3] = &v;
2604+ return ccs_check_acl(r, false);
2605+}
2606+
2607+/**
2608+ * ccs_environ - Check permission for environment variable names.
2609+ *
2610+ * @r: Pointer to "struct ccs_request_info".
2611+ *
2612+ * Returns 0 on success, negative value otherwise.
2613+ */
2614+static int ccs_environ(struct ccs_request_info *r)
2615+{
2616+ struct linux_binprm *bprm = r->bprm;
2617+ /* env_page.data is allocated by ccs_dump_page(). */
2618+ struct ccs_page_dump env_page = { };
2619+ char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
2620+ int arg_len = 0;
2621+ unsigned long pos = bprm->p;
2622+ int offset = pos % PAGE_SIZE;
2623+ int argv_count = bprm->argc;
2624+ int envp_count = bprm->envc;
2625+ int error = -ENOMEM;
2626+ arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, GFP_NOFS);
2627+ if (!arg_ptr) {
2628+ r->failed_by_oom = true;
2629+ goto out;
2630+ }
2631+ while (error == -ENOMEM) {
2632+ if (!ccs_dump_page(bprm, pos, &env_page)) {
2633+ r->failed_by_oom = true;
2634+ goto out;
2635+ }
2636+ pos += PAGE_SIZE - offset;
2637+ /* Read. */
2638+ while (argv_count && offset < PAGE_SIZE) {
2639+ if (!env_page.data[offset++])
2640+ argv_count--;
2641+ }
2642+ if (argv_count) {
2643+ offset = 0;
2644+ continue;
2645+ }
2646+ while (offset < PAGE_SIZE) {
2647+ char *value;
2648+ const unsigned char c = env_page.data[offset++];
2649+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
2650+ if (c > ' ' && c < 127 && c != '\\') {
2651+ arg_ptr[arg_len++] = c;
2652+ } else {
2653+ arg_ptr[arg_len++] = '\\';
2654+ arg_ptr[arg_len++] = (c >> 6) + '0';
2655+ arg_ptr[arg_len++]
2656+ = ((c >> 3) & 7) + '0';
2657+ arg_ptr[arg_len++] = (c & 7) + '0';
2658+ }
2659+ } else {
2660+ arg_ptr[arg_len] = '\0';
2661+ }
2662+ if (c)
2663+ continue;
2664+ value = strchr(arg_ptr, '=');
2665+ if (value)
2666+ *value++ = '\0';
2667+ else
2668+ value = "";
2669+ if (ccs_env_perm(r, arg_ptr, value)) {
2670+ error = -EPERM;
2671+ break;
2672+ }
2673+ if (!--envp_count) {
2674+ error = 0;
2675+ break;
2676+ }
2677+ arg_len = 0;
2678+ }
2679+ offset = 0;
2680+ }
2681+out:
2682+ kfree(env_page.data);
2683+ kfree(arg_ptr);
2684+ return error;
2685+}
2686+
2687+#endif
2688+
2689+/**
2690+ * ccs_path_matches_group_or_pattern - Check whether the given pathname matches the given group or the given pattern.
2691+ *
2692+ * @path: Pointer to "struct ccs_path_info".
2693+ * @group: Pointer to "struct ccs_group". Maybe NULL.
2694+ * @pattern: Poiner to "struct ccs_path_info". Maybe NULL.
2695+ * @match: True if positive match, false othwerwise.
2696+ *
2697+ * Returns true on success, false otherwise.
2698+ */
2699+static bool ccs_path_matches_group_or_pattern
2700+(const struct ccs_path_info *path, const struct ccs_group *group,
2701+ const struct ccs_path_info *pattern, const bool match)
2702+{
2703+ if (group)
2704+ return ccs_path_matches_group(path, group) == match;
2705+ else if (pattern != &ccs_null_name)
2706+ return ccs_path_matches_pattern(path, pattern) == match;
2707+ else
2708+ return !match;
2709+}
2710+
2711+/**
2712+ * ccs_check_argv - Check argv[] in "struct linux_binbrm".
2713+ *
2714+ * @r: Pointer to "struct ccs_request_info".
2715+ * @index: Index number to check.
2716+ * @group: Pointer to "struct ccs_group". Maybe NULL.
2717+ * @value: Poiner to "struct ccs_path_info". NULL if @group != NULL.
2718+ * @match: True if positive match, false othwerwise.
2719+ *
2720+ * Returns true on success, false otherwise.
2721+ */
2722+static bool ccs_check_argv(struct ccs_request_info *r, unsigned long index,
2723+ const struct ccs_group *group,
2724+ const struct ccs_path_info *value,
2725+ const bool match)
2726+{
2727+ struct linux_binprm *bprm = r->bprm;
2728+ struct ccs_page_dump *dump = &r->dump;
2729+ char *arg_ptr = r->tmp;
2730+ int arg_len = 0;
2731+ unsigned long pos = bprm->p;
2732+ int offset = pos % PAGE_SIZE;
2733+ struct ccs_path_info arg;
2734+ if (index > bprm->argc)
2735+ return false;
2736+ while (1) {
2737+ if (!ccs_dump_page(bprm, pos, dump)) {
2738+ r->failed_by_oom = true;
2739+ return false;
2740+ }
2741+ pos += PAGE_SIZE - offset;
2742+ while (offset < PAGE_SIZE) {
2743+ const unsigned char c = dump->data[offset++];
2744+ if (index) {
2745+ if (!c)
2746+ index--;
2747+ continue;
2748+ }
2749+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
2750+ if (c > ' ' && c < 127 && c != '\\') {
2751+ arg_ptr[arg_len++] = c;
2752+ } else {
2753+ arg_ptr[arg_len++] = '\\';
2754+ arg_ptr[arg_len++] = (c >> 6) + '0';
2755+ arg_ptr[arg_len++] =
2756+ ((c >> 3) & 7) + '0';
2757+ arg_ptr[arg_len++] = (c & 7) + '0';
2758+ }
2759+ continue;
2760+ }
2761+ arg_ptr[arg_len] = '\0';
2762+ arg.name = arg_ptr;
2763+ ccs_fill_path_info(&arg);
2764+ return ccs_path_matches_group_or_pattern
2765+ (&arg, group, value, match);
2766+ }
2767+ offset = 0;
2768+ }
2769+}
2770+
2771+/**
2772+ * ccs_check_envp - Check envp[] in "struct linux_binbrm".
2773+ *
2774+ * @r: Pointer to "struct ccs_request_info".
2775+ * @name: Pointer to "struct ccs_path_info".
2776+ * @group: Pointer to "struct ccs_group". Maybe NULL.
2777+ * @value: Pointer to "struct ccs_path_info". NULL if @group != NULL.
2778+ * @match: True if positive match, false othwerwise.
2779+ *
2780+ * Returns true on success, false otherwise.
2781+ */
2782+static bool ccs_check_envp(struct ccs_request_info *r,
2783+ const struct ccs_path_info *name,
2784+ const struct ccs_group *group,
2785+ const struct ccs_path_info *value,
2786+ const bool match)
2787+{
2788+ struct linux_binprm *bprm = r->bprm;
2789+ struct ccs_page_dump *dump = &r->dump;
2790+ char *arg_ptr = r->tmp;
2791+ int arg_len = 0;
2792+ unsigned long pos = bprm->p;
2793+ int offset = pos % PAGE_SIZE;
2794+ int argv_count = bprm->argc;
2795+ int envp_count = bprm->envc;
2796+ bool result = (value != &ccs_null_name) == match;
2797+ struct ccs_path_info env;
2798+ char *cp;
2799+ while (envp_count) {
2800+ if (!ccs_dump_page(bprm, pos, dump)) {
2801+ r->failed_by_oom = true;
2802+ return false;
2803+ }
2804+ pos += PAGE_SIZE - offset;
2805+ while (envp_count && offset < PAGE_SIZE) {
2806+ const unsigned char c = dump->data[offset++];
2807+ if (argv_count) {
2808+ if (!c)
2809+ argv_count--;
2810+ continue;
2811+ }
2812+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
2813+ if (c > ' ' && c < 127 && c != '\\') {
2814+ arg_ptr[arg_len++] = c;
2815+ } else {
2816+ arg_ptr[arg_len++] = '\\';
2817+ arg_ptr[arg_len++] = (c >> 6) + '0';
2818+ arg_ptr[arg_len++] =
2819+ ((c >> 3) & 7) + '0';
2820+ arg_ptr[arg_len++] = (c & 7) + '0';
2821+ }
2822+ } else {
2823+ arg_ptr[arg_len] = '\0';
2824+ }
2825+ if (c)
2826+ continue;
2827+ arg_len = 0;
2828+ envp_count--;
2829+ /* Check. */
2830+ cp = strchr(arg_ptr, '=');
2831+ if (!cp)
2832+ cp = "";
2833+ else
2834+ *cp++ = '\0';
2835+ env.name = arg_ptr;
2836+ ccs_fill_path_info(&env);
2837+ if (!ccs_path_matches_pattern(&env, name))
2838+ continue;
2839+ result = true;
2840+ env.name = cp;
2841+ ccs_fill_path_info(&env);
2842+ if (ccs_path_matches_group_or_pattern
2843+ (&env, group, value, match))
2844+ continue;
2845+ return false;
2846+ }
2847+ offset = 0;
2848+ }
2849+ return result;
2850+}
2851+
2852+/**
2853+ * ccs_get_attributes - Revalidate "struct inode".
2854+ *
2855+ * @r: Pointer to "struct ccs_request_info".
2856+ *
2857+ * Returns nothing.
2858+ */
2859+void ccs_get_attributes(struct ccs_request_info *r)
2860+{
2861+ u8 i;
2862+ struct dentry *dentry = NULL;
2863+
2864+ if (r->obj.validate_done)
2865+ return;
2866+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
2867+ struct inode *inode;
2868+ switch (i) {
2869+ case CCS_PATH1:
2870+ dentry = r->obj.path[0].dentry;
2871+ if (!dentry)
2872+ continue;
2873+ break;
2874+ case CCS_PATH2:
2875+ dentry = r->obj.path[1].dentry;
2876+ if (!dentry)
2877+ continue;
2878+ break;
2879+ default:
2880+ if (!dentry)
2881+ continue;
2882+ dentry = dget_parent(dentry);
2883+ break;
2884+ }
2885+ inode = dentry->d_inode;
2886+ if (inode) {
2887+ struct ccs_mini_stat *stat = &r->obj.stat[i];
2888+ stat->uid = inode->i_uid;
2889+ stat->gid = inode->i_gid;
2890+ stat->ino = inode->i_ino;
2891+ stat->mode = inode->i_mode;
2892+ stat->dev = inode->i_sb->s_dev;
2893+ stat->rdev = inode->i_rdev;
2894+ stat->fsmagic = dentry->d_sb->s_magic;
2895+ r->obj.stat_valid[i] = true;
2896+ }
2897+ if (i & 1) /* parent directory */
2898+ dput(dentry);
2899+ }
2900+ r->obj.validate_done = true;
2901+}
2902+
2903+/**
2904+ * ccs_populate_patharg - Calculate pathname for permission check and audit logs.
2905+ *
2906+ * @r: Pointer to "struct ccs_request_info".
2907+ * @first: True for first pathname, false for second pathname.
2908+ *
2909+ * Returns nothing.
2910+ */
2911+void ccs_populate_patharg(struct ccs_request_info *r, const bool first)
2912+{
2913+ struct ccs_path_info *buf = &r->obj.pathname[!first];
2914+ struct path *path = &r->obj.path[!first];
2915+ if (!buf->name && path->dentry) {
2916+ buf->name = ccs_realpath(path);
2917+ /* Set OOM flag if failed. */
2918+ if (!buf->name) {
2919+ r->failed_by_oom = true;
2920+ return;
2921+ }
2922+ ccs_fill_path_info(buf);
2923+ }
2924+ if (!r->param.s[!first] && buf->name)
2925+ r->param.s[!first] = buf;
2926+}
2927+
2928+/**
2929+ * ccs_cond2arg - Assign values to condition variables.
2930+ *
2931+ * @arg: Pointer to "struct ccs_cond_arg".
2932+ * @cmd: One of values in "enum ccs_conditions_index".
2933+ * @condp: Pointer to "union ccs_condition_element *".
2934+ * @r: Pointer to "struct ccs_request_info".
2935+ *
2936+ * Returns true on success, false othwerwise.
2937+ *
2938+ * This function should not fail. But it can fail if (for example) out of
2939+ * memory has occured while calculating ccs_populate_patharg() or
2940+ * ccs_get_exename().
2941+ */
2942+static bool ccs_cond2arg(struct ccs_cond_arg *arg,
2943+ const enum ccs_conditions_index cmd,
2944+ const union ccs_condition_element **condp,
2945+ struct ccs_request_info *r)
2946+{
2947+ struct ccs_mini_stat *stat;
2948+ unsigned long value;
2949+ const struct linux_binprm *bprm = r->bprm;
2950+ const struct ccs_request_param *param = &r->param;
2951+ arg->type = CCS_ARG_TYPE_NUMBER;
2952+ switch (cmd) {
2953+ case CCS_SELF_UID:
2954+ value = current_uid();
2955+ break;
2956+ case CCS_SELF_EUID:
2957+ value = current_euid();
2958+ break;
2959+ case CCS_SELF_SUID:
2960+ value = current_suid();
2961+ break;
2962+ case CCS_SELF_FSUID:
2963+ value = current_fsuid();
2964+ break;
2965+ case CCS_SELF_GID:
2966+ value = current_gid();
2967+ break;
2968+ case CCS_SELF_EGID:
2969+ value = current_egid();
2970+ break;
2971+ case CCS_SELF_SGID:
2972+ value = current_sgid();
2973+ break;
2974+ case CCS_SELF_FSGID:
2975+ value = current_fsgid();
2976+ break;
2977+ case CCS_SELF_PID:
2978+ value = ccs_sys_getpid();
2979+ break;
2980+ case CCS_SELF_PPID:
2981+ value = ccs_sys_getppid();
2982+ break;
2983+ case CCS_OBJ_IS_SOCKET:
2984+ value = S_IFSOCK;
2985+ break;
2986+ case CCS_OBJ_IS_SYMLINK:
2987+ value = S_IFLNK;
2988+ break;
2989+ case CCS_OBJ_IS_FILE:
2990+ value = S_IFREG;
2991+ break;
2992+ case CCS_OBJ_IS_BLOCK_DEV:
2993+ value = S_IFBLK;
2994+ break;
2995+ case CCS_OBJ_IS_DIRECTORY:
2996+ value = S_IFDIR;
2997+ break;
2998+ case CCS_OBJ_IS_CHAR_DEV:
2999+ value = S_IFCHR;
3000+ break;
3001+ case CCS_OBJ_IS_FIFO:
3002+ value = S_IFIFO;
3003+ break;
3004+ case CCS_EXEC_ARGC:
3005+ if (!bprm)
3006+ return false;
3007+ value = bprm->argc;
3008+ break;
3009+ case CCS_EXEC_ENVC:
3010+ if (!bprm)
3011+ return false;
3012+ value = bprm->envc;
3013+ break;
3014+ case CCS_TASK_TYPE:
3015+ value = ((u8) ccs_current_flags()) &
3016+ CCS_TASK_IS_EXECUTE_HANDLER;
3017+ break;
3018+ case CCS_TASK_EXECUTE_HANDLER:
3019+ value = CCS_TASK_IS_EXECUTE_HANDLER;
3020+ break;
3021+ case CCS_ARGV_ENTRY:
3022+ case CCS_IMM_NUMBER_ENTRY1:
3023+ value = (*condp)->value;
3024+ (*condp)++;
3025+ break;
3026+ case CCS_COND_NARG0:
3027+ value = param->i[0];
3028+ break;
3029+ case CCS_COND_NARG1:
3030+ value = param->i[1];
3031+ break;
3032+ case CCS_COND_NARG2:
3033+ value = param->i[2];
3034+ break;
3035+ case CCS_HANDLER_PATH:
3036+ case CCS_TRANSIT_DOMAIN:
3037+ case CCS_COND_IPARG:
3038+ /* Values are loaded by caller. Just return a dummy. */
3039+ arg->type = CCS_ARG_TYPE_NONE;
3040+ value = 0;
3041+ break;
3042+ default:
3043+ goto not_single_value;
3044+ }
3045+ arg->value[0] = value;
3046+ arg->value[1] = value;
3047+ return true;
3048+not_single_value:
3049+ if (cmd == CCS_IMM_NUMBER_ENTRY2) {
3050+ arg->value[0] = (*condp)->value;
3051+ (*condp)++;
3052+ arg->value[1] = (*condp)->value;
3053+ (*condp)++;
3054+ return true;
3055+ }
3056+ switch (cmd) {
3057+ case CCS_COND_SARG0:
3058+ if (!r->param.s[0])
3059+ ccs_populate_patharg(r, true);
3060+ arg->name = r->param.s[0];
3061+ break;
3062+ case CCS_COND_SARG1:
3063+ if (!r->param.s[1])
3064+ ccs_populate_patharg(r, false);
3065+ arg->name = r->param.s[1];
3066+ break;
3067+ case CCS_COND_SARG2:
3068+ arg->name = r->param.s[2];
3069+ break;
3070+ case CCS_COND_SARG3:
3071+ arg->name = r->param.s[3];
3072+ break;
3073+ case CCS_ENVP_ENTRY:
3074+ case CCS_IMM_NAME_ENTRY:
3075+ arg->name = (*condp)->path;
3076+ (*condp)++;
3077+ break;
3078+ case CCS_SELF_EXE:
3079+ if (!r->exename.name) {
3080+ ccs_get_exename(&r->exename);
3081+ /* Set OOM flag if failed. */
3082+ if (!r->exename.name)
3083+ r->failed_by_oom = true;
3084+ }
3085+ arg->name = &r->exename;
3086+ break;
3087+ case CCS_COND_DOMAIN:
3088+ arg->name = r->param.s[0];
3089+ break;
3090+ case CCS_SELF_DOMAIN:
3091+ arg->name = ccs_current_domain()->domainname;
3092+ break;
3093+ default:
3094+ goto not_single_name;
3095+ }
3096+ if (!arg->name)
3097+ return false;
3098+ arg->type = CCS_ARG_TYPE_NAME;
3099+ return true;
3100+not_single_name:
3101+ if (cmd == CCS_IMM_GROUP) {
3102+ arg->type = CCS_ARG_TYPE_GROUP;
3103+ arg->group = (*condp)->group;
3104+ (*condp)++;
3105+ return true;
3106+ }
3107+#ifdef CONFIG_CCSECURITY_NETWORK
3108+ if (cmd == CCS_IMM_IPV4ADDR_ENTRY1) {
3109+ arg->type = CCS_ARG_TYPE_IPV4ADDR;
3110+ memmove(&arg->ip[0], &(*condp)->ip, 4);
3111+ memmove(&arg->ip[1], &(*condp)->ip, 4);
3112+ (*condp)++;
3113+ return true;
3114+ }
3115+ if (cmd == CCS_IMM_IPV4ADDR_ENTRY2) {
3116+ arg->type = CCS_ARG_TYPE_IPV4ADDR;
3117+ memmove(&arg->ip[0], &(*condp)->ip, 4);
3118+ (*condp)++;
3119+ memmove(&arg->ip[1], &(*condp)->ip, 4);
3120+ (*condp)++;
3121+ return true;
3122+ }
3123+ if (cmd == CCS_IMM_IPV6ADDR_ENTRY1) {
3124+ arg->type = CCS_ARG_TYPE_IPV6ADDR;
3125+ memmove(&arg->ip[0], &(*condp)->ip, 16);
3126+ memmove(&arg->ip[1], &(*condp)->ip, 16);
3127+ *condp = (void *)
3128+ (((u8 *) *condp) + sizeof(struct in6_addr));
3129+ return true;
3130+ }
3131+ if (cmd == CCS_IMM_IPV6ADDR_ENTRY2) {
3132+ arg->type = CCS_ARG_TYPE_IPV6ADDR;
3133+ memmove(&arg->ip[0], &(*condp)->ip, 16);
3134+ *condp = (void *)
3135+ (((u8 *) *condp) + sizeof(struct in6_addr));
3136+ memmove(&arg->ip[1], &(*condp)->ip, 16);
3137+ *condp = (void *)
3138+ (((u8 *) *condp) + sizeof(struct in6_addr));
3139+ return true;
3140+ }
3141+#endif
3142+ switch (cmd) {
3143+ case CCS_MODE_SETUID:
3144+ value = S_ISUID;
3145+ break;
3146+ case CCS_MODE_SETGID:
3147+ value = S_ISGID;
3148+ break;
3149+ case CCS_MODE_STICKY:
3150+ value = S_ISVTX;
3151+ break;
3152+ case CCS_MODE_OWNER_READ:
3153+ value = S_IRUSR;
3154+ break;
3155+ case CCS_MODE_OWNER_WRITE:
3156+ value = S_IWUSR;
3157+ break;
3158+ case CCS_MODE_OWNER_EXECUTE:
3159+ value = S_IXUSR;
3160+ break;
3161+ case CCS_MODE_GROUP_READ:
3162+ value = S_IRGRP;
3163+ break;
3164+ case CCS_MODE_GROUP_WRITE:
3165+ value = S_IWGRP;
3166+ break;
3167+ case CCS_MODE_GROUP_EXECUTE:
3168+ value = S_IXGRP;
3169+ break;
3170+ case CCS_MODE_OTHERS_READ:
3171+ value = S_IROTH;
3172+ break;
3173+ case CCS_MODE_OTHERS_WRITE:
3174+ value = S_IWOTH;
3175+ break;
3176+ case CCS_MODE_OTHERS_EXECUTE:
3177+ value = S_IXOTH;
3178+ break;
3179+ default:
3180+ goto not_bitop;
3181+ }
3182+ arg->type = CCS_ARG_TYPE_BITOP;
3183+ arg->value[0] = value;
3184+ return true;
3185+not_bitop:
3186+ arg->type = CCS_ARG_TYPE_NUMBER;
3187+ if (!r->obj.path[0].dentry && !r->obj.path[1].dentry)
3188+ return false;
3189+ ccs_get_attributes(r);
3190+ value = (cmd - CCS_PATH_ATTRIBUTE_START) >> 4;
3191+ if (value > 3)
3192+ return false;
3193+ stat = &r->obj.stat[value];
3194+ if (!stat)
3195+ return false;
3196+ switch ((cmd - CCS_PATH_ATTRIBUTE_START) & 0xF) {
3197+ case CCS_PATH_ATTRIBUTE_UID:
3198+ value = stat->uid;
3199+ break;
3200+ case CCS_PATH_ATTRIBUTE_GID:
3201+ value = stat->gid;
3202+ break;
3203+ case CCS_PATH_ATTRIBUTE_INO:
3204+ value = stat->ino;
3205+ break;
3206+ case CCS_PATH_ATTRIBUTE_MAJOR:
3207+ value = MAJOR(stat->dev);
3208+ break;
3209+ case CCS_PATH_ATTRIBUTE_MINOR:
3210+ value = MINOR(stat->dev);
3211+ break;
3212+ case CCS_PATH_ATTRIBUTE_TYPE:
3213+ value = stat->mode & S_IFMT;
3214+ break;
3215+ case CCS_PATH_ATTRIBUTE_DEV_MAJOR:
3216+ value = MAJOR(stat->rdev);
3217+ break;
3218+ case CCS_PATH_ATTRIBUTE_DEV_MINOR:
3219+ value = MINOR(stat->rdev);
3220+ break;
3221+ case CCS_PATH_ATTRIBUTE_PERM:
3222+ value = stat->mode & S_IALLUGO;
3223+ break;
3224+ case CCS_PATH_ATTRIBUTE_FSMAGIC:
3225+ value = stat->fsmagic;
3226+ break;
3227+ default:
3228+ return false;
3229+ }
3230+ arg->value[0] = value;
3231+ arg->value[1] = value;
3232+ return true;
3233+}
3234+
3235+/**
3236+ * ccs_condition - Check condition part.
3237+ *
3238+ * @r: Pointer to "struct ccs_request_info".
3239+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
3240+ *
3241+ * Returns true on success, false otherwise.
3242+ *
3243+ * Caller holds ccs_read_lock().
3244+ */
3245+static bool ccs_condition(struct ccs_request_info *r,
3246+ const struct ccs_condition *cond)
3247+{
3248+ const union ccs_condition_element *condp;
3249+ if (!cond)
3250+ return true;
3251+ condp = (typeof(condp)) (cond + 1);
3252+ while ((void *) condp < (void *) ((u8 *) cond) + cond->size) {
3253+ struct ccs_cond_arg left;
3254+ struct ccs_cond_arg right;
3255+ const enum ccs_conditions_index left_op = condp->left;
3256+ const enum ccs_conditions_index right_op = condp->right;
3257+ const bool match = !condp->is_not;
3258+ condp++;
3259+ if (!ccs_cond2arg(&left, left_op, &condp, r) ||
3260+ !ccs_cond2arg(&right, right_op, &condp, r)) {
3261+ /*
3262+ * Something wrong (e.g. out of memory or invalid
3263+ * argument) occured. We can't check permission.
3264+ */
3265+ return false;
3266+ }
3267+ if (left.type == CCS_ARG_TYPE_NUMBER) {
3268+ if (left_op == CCS_ARGV_ENTRY) {
3269+ if (!r->bprm)
3270+ return false;
3271+ else if (right.type == CCS_ARG_TYPE_NAME)
3272+ right.group = NULL;
3273+ else if (right.type == CCS_ARG_TYPE_GROUP)
3274+ right.name = NULL;
3275+ else
3276+ return false;
3277+ if (ccs_check_argv(r, left.value[0],
3278+ right.group, right.name,
3279+ match))
3280+ continue;
3281+ return false;
3282+ }
3283+ if (right.type == CCS_ARG_TYPE_NUMBER) {
3284+ if ((left.value[0] <= right.value[1] &&
3285+ left.value[1] >= right.value[0]) == match)
3286+ continue;
3287+ return false;
3288+ }
3289+ if (right.type == CCS_ARG_TYPE_GROUP) {
3290+ if (ccs_number_matches_group
3291+ (left.value[0], left.value[1], right.group)
3292+ == match)
3293+ continue;
3294+ return false;
3295+ }
3296+ if (right.type == CCS_ARG_TYPE_BITOP) {
3297+ if (!(left.value[0] & right.value[0]) ==
3298+ !match)
3299+ continue;
3300+ return false;
3301+ }
3302+ return false;
3303+ }
3304+ if (left.type == CCS_ARG_TYPE_NAME) {
3305+ if (right.type == CCS_ARG_TYPE_NAME)
3306+ right.group = NULL;
3307+ else if (right.type == CCS_ARG_TYPE_GROUP)
3308+ right.name = NULL;
3309+ else
3310+ return false;
3311+ if (left_op == CCS_ENVP_ENTRY) {
3312+ if (r->bprm && ccs_check_envp
3313+ (r, left.name, right.group, right.name,
3314+ match))
3315+ continue;
3316+ } else if (ccs_path_matches_group_or_pattern
3317+ (left.name, right.group, right.name, match))
3318+ continue;
3319+ return false;
3320+ }
3321+ if (left.type != CCS_ARG_TYPE_NONE)
3322+ return false;
3323+ /* Check IPv4 or IPv6 address expressions. */
3324+ if (left_op == CCS_COND_IPARG) {
3325+#ifdef CONFIG_CCSECURITY_NETWORK
3326+ if (right.type == CCS_ARG_TYPE_GROUP) {
3327+ if (ccs_ip_matches_group
3328+ (r->param.is_ipv6, r->param.ip,
3329+ right.group) == match)
3330+ continue;
3331+ } else if (right.type == CCS_ARG_TYPE_IPV6ADDR) {
3332+ if (r->param.is_ipv6 &&
3333+ (memcmp(r->param.ip, &right.ip[0],
3334+ 16) >= 0 &&
3335+ memcmp(r->param.ip, &right.ip[1],
3336+ 16) <= 0) == match)
3337+ continue;
3338+ } else if (right.type == CCS_ARG_TYPE_IPV4ADDR) {
3339+ if (!r->param.is_ipv6 &&
3340+ (memcmp(r->param.ip, &right.ip[0],
3341+ 4) >= 0 &&
3342+ memcmp(r->param.ip, &right.ip[1],
3343+ 4) <= 0) == match)
3344+ continue;
3345+ }
3346+#endif
3347+ return false;
3348+ }
3349+ if (left_op == CCS_HANDLER_PATH) {
3350+ r->handler_path_candidate = right.name;
3351+ continue;
3352+ }
3353+ if (left_op == CCS_TRANSIT_DOMAIN) {
3354+ r->transition_candidate = right.name;
3355+ continue;
3356+ }
3357+ return false;
3358+ }
3359+ return true;
3360+}
3361+
3362+/**
3363+ * ccs_check_auto_domain_transition - Check "auto_domain_transition" entry.
3364+ *
3365+ * Returns nothing.
3366+ *
3367+ * If "auto_domain_transition" keyword was specified and transition to that
3368+ * domain failed, the current thread will be killed by SIGKILL.
3369+ */
3370+static void ccs_check_auto_domain_transition(void)
3371+{
3372+#ifdef CONFIG_CCSECURITY_AUTO_DOMAIN_TRANSITION
3373+ struct ccs_request_info r = { };
3374+ const int idx = ccs_read_lock();
3375+ r.type = CCS_MAC_AUTO_DOMAIN_TRANSITION;
3376+ ccs_check_acl(&r, true);
3377+ if (r.result != CCS_MATCHING_ALLOWED ||
3378+ ccs_transit_domain(r.transition->name))
3379+ goto done;
3380+ printk(KERN_WARNING "ERROR: Unable to transit to '%s' domain.\n",
3381+ r.transition->name);
3382+ force_sig(SIGKILL, current);
3383+done:
3384+ ccs_read_unlock(idx);
3385+#endif
3386+}
3387+
3388+/**
3389+ * ccs_byte_range - Check whether the string is a \ooo style octal value.
3390+ *
3391+ * @str: Pointer to the string.
3392+ *
3393+ * Returns true if @str is a \ooo style octal value, false otherwise.
3394+ */
3395+static bool ccs_byte_range(const char *str)
3396+{
3397+ return *str >= '0' && *str++ <= '3' &&
3398+ *str >= '0' && *str++ <= '7' &&
3399+ *str >= '0' && *str <= '7';
3400+}
3401+
3402+/**
3403+ * ccs_decimal - Check whether the character is a decimal character.
3404+ *
3405+ * @c: The character to check.
3406+ *
3407+ * Returns true if @c is a decimal character, false otherwise.
3408+ */
3409+static bool ccs_decimal(const char c)
3410+{
3411+ return c >= '0' && c <= '9';
3412+}
3413+
3414+/**
3415+ * ccs_hexadecimal - Check whether the character is a hexadecimal character.
3416+ *
3417+ * @c: The character to check.
3418+ *
3419+ * Returns true if @c is a hexadecimal character, false otherwise.
3420+ */
3421+static bool ccs_hexadecimal(const char c)
3422+{
3423+ return (c >= '0' && c <= '9') ||
3424+ (c >= 'A' && c <= 'F') ||
3425+ (c >= 'a' && c <= 'f');
3426+}
3427+
3428+/**
3429+ * ccs_alphabet_char - Check whether the character is an alphabet.
3430+ *
3431+ * @c: The character to check.
3432+ *
3433+ * Returns true if @c is an alphabet character, false otherwise.
3434+ */
3435+static bool ccs_alphabet_char(const char c)
3436+{
3437+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
3438+}
3439+
3440+/**
3441+ * ccs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
3442+ *
3443+ * @filename: The start of string to check.
3444+ * @filename_end: The end of string to check.
3445+ * @pattern: The start of pattern to compare.
3446+ * @pattern_end: The end of pattern to compare.
3447+ *
3448+ * Returns true if @filename matches @pattern, false otherwise.
3449+ */
3450+static bool ccs_file_matches_pattern2(const char *filename,
3451+ const char *filename_end,
3452+ const char *pattern,
3453+ const char *pattern_end)
3454+{
3455+ while (filename < filename_end && pattern < pattern_end) {
3456+ char c;
3457+ if (*pattern != '\\') {
3458+ if (*filename++ != *pattern++)
3459+ return false;
3460+ continue;
3461+ }
3462+ c = *filename;
3463+ pattern++;
3464+ switch (*pattern) {
3465+ int i;
3466+ int j;
3467+ case '?':
3468+ if (c == '/') {
3469+ return false;
3470+ } else if (c == '\\') {
3471+ if (ccs_byte_range(filename + 1))
3472+ filename += 3;
3473+ else
3474+ return false;
3475+ }
3476+ break;
3477+ case '+':
3478+ if (!ccs_decimal(c))
3479+ return false;
3480+ break;
3481+ case 'x':
3482+ if (!ccs_hexadecimal(c))
3483+ return false;
3484+ break;
3485+ case 'a':
3486+ if (!ccs_alphabet_char(c))
3487+ return false;
3488+ break;
3489+ case '0':
3490+ case '1':
3491+ case '2':
3492+ case '3':
3493+ if (c == '\\' && ccs_byte_range(filename + 1)
3494+ && !strncmp(filename + 1, pattern, 3)) {
3495+ filename += 3;
3496+ pattern += 2;
3497+ break;
3498+ }
3499+ return false; /* Not matched. */
3500+ case '*':
3501+ case '@':
3502+ for (i = 0; i <= filename_end - filename; i++) {
3503+ if (ccs_file_matches_pattern2(filename + i,
3504+ filename_end,
3505+ pattern + 1,
3506+ pattern_end))
3507+ return true;
3508+ c = filename[i];
3509+ if (c == '.' && *pattern == '@')
3510+ break;
3511+ if (c != '\\')
3512+ continue;
3513+ if (ccs_byte_range(filename + i + 1))
3514+ i += 3;
3515+ else
3516+ break; /* Bad pattern. */
3517+ }
3518+ return false; /* Not matched. */
3519+ default:
3520+ j = 0;
3521+ c = *pattern;
3522+ if (c == '$') {
3523+ while (ccs_decimal(filename[j]))
3524+ j++;
3525+ } else if (c == 'X') {
3526+ while (ccs_hexadecimal(filename[j]))
3527+ j++;
3528+ } else if (c == 'A') {
3529+ while (ccs_alphabet_char(filename[j]))
3530+ j++;
3531+ }
3532+ for (i = 1; i <= j; i++) {
3533+ if (ccs_file_matches_pattern2(filename + i,
3534+ filename_end,
3535+ pattern + 1,
3536+ pattern_end))
3537+ return true;
3538+ }
3539+ return false; /* Not matched or bad pattern. */
3540+ }
3541+ filename++;
3542+ pattern++;
3543+ }
3544+ /* Ignore trailing "\*" and "\@" in @pattern. */
3545+ while (*pattern == '\\' &&
3546+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
3547+ pattern += 2;
3548+ return filename == filename_end && pattern == pattern_end;
3549+}
3550+
3551+/**
3552+ * ccs_file_matches_pattern - Pattern matching without '/' character.
3553+ *
3554+ * @filename: The start of string to check.
3555+ * @filename_end: The end of string to check.
3556+ * @pattern: The start of pattern to compare.
3557+ * @pattern_end: The end of pattern to compare.
3558+ *
3559+ * Returns true if @filename matches @pattern, false otherwise.
3560+ */
3561+static bool ccs_file_matches_pattern(const char *filename,
3562+ const char *filename_end,
3563+ const char *pattern,
3564+ const char *pattern_end)
3565+{
3566+ const char *pattern_start = pattern;
3567+ bool first = true;
3568+ bool result;
3569+ while (pattern < pattern_end - 1) {
3570+ /* Split at "\-" pattern. */
3571+ if (*pattern++ != '\\' || *pattern++ != '-')
3572+ continue;
3573+ result = ccs_file_matches_pattern2(filename, filename_end,
3574+ pattern_start, pattern - 2);
3575+ if (first)
3576+ result = !result;
3577+ if (result)
3578+ return false;
3579+ first = false;
3580+ pattern_start = pattern;
3581+ }
3582+ result = ccs_file_matches_pattern2(filename, filename_end,
3583+ pattern_start, pattern_end);
3584+ return first ? result : !result;
3585+}
3586+
3587+/**
3588+ * ccs_path_matches_pattern2 - Do pathname pattern matching.
3589+ *
3590+ * @f: The start of string to check.
3591+ * @p: The start of pattern to compare.
3592+ *
3593+ * Returns true if @f matches @p, false otherwise.
3594+ */
3595+static bool ccs_path_matches_pattern2(const char *f, const char *p)
3596+{
3597+ const char *f_delimiter;
3598+ const char *p_delimiter;
3599+ char recursive_end;
3600+ while (*f && *p) {
3601+ f_delimiter = strchr(f, '/');
3602+ if (!f_delimiter)
3603+ f_delimiter = f + strlen(f);
3604+ p_delimiter = strchr(p, '/');
3605+ if (!p_delimiter)
3606+ p_delimiter = p + strlen(p);
3607+ if (*p == '\\') {
3608+ if (*(p + 1) == '{') {
3609+ recursive_end = '}';
3610+ goto recursive;
3611+ }
3612+ if (*(p + 1) == '(') {
3613+ recursive_end = ')';
3614+ goto recursive;
3615+ }
3616+ }
3617+ if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
3618+ return false;
3619+ f = f_delimiter;
3620+ if (*f)
3621+ f++;
3622+ p = p_delimiter;
3623+ if (*p)
3624+ p++;
3625+ }
3626+ /* Ignore trailing "\*" and "\@" in @pattern. */
3627+ while (*p == '\\' &&
3628+ (*(p + 1) == '*' || *(p + 1) == '@'))
3629+ p += 2;
3630+ return !*f && !*p;
3631+recursive:
3632+ /*
3633+ * The "\{" or "\(" pattern is permitted only after '/' character.
3634+ * This guarantees that below "*(p - 1)" is safe.
3635+ * Also, the "\}" or "\)" pattern is permitted only before '/'
3636+ * character so that "\{" + "\}" or "\(" + "\)" pair will not break
3637+ * the "\-" operator.
3638+ */
3639+ if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
3640+ *(p_delimiter - 1) != recursive_end || *(p_delimiter - 2) != '\\')
3641+ return false; /* Bad pattern. */
3642+ if (recursive_end == ')') {
3643+ /* Check zero repetition. */
3644+ if (ccs_path_matches_pattern2(f, p_delimiter + 1))
3645+ return true;
3646+ /* Fall back to one or more repetition. */
3647+ }
3648+ do {
3649+ /* Compare current component with pattern. */
3650+ if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
3651+ p_delimiter - 2))
3652+ break;
3653+ /* Proceed to next component. */
3654+ f = f_delimiter;
3655+ if (!*f)
3656+ break;
3657+ f++;
3658+ /* Continue comparison. */
3659+ if (ccs_path_matches_pattern2(f, p_delimiter + 1))
3660+ return true;
3661+ f_delimiter = strchr(f, '/');
3662+ } while (f_delimiter);
3663+ return false; /* Not matched. */
3664+}
3665+
3666+/**
3667+ * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
3668+ *
3669+ * @filename: The filename to check.
3670+ * @pattern: The pattern to compare.
3671+ *
3672+ * Returns true if matches, false otherwise.
3673+ *
3674+ * The following patterns are available.
3675+ * \ooo Octal representation of a byte.
3676+ * \* Zero or more repetitions of characters other than '/'.
3677+ * \@ Zero or more repetitions of characters other than '/' or '.'.
3678+ * \? 1 byte character other than '/'.
3679+ * \$ One or more repetitions of decimal digits.
3680+ * \+ 1 decimal digit.
3681+ * \X One or more repetitions of hexadecimal digits.
3682+ * \x 1 hexadecimal digit.
3683+ * \A One or more repetitions of alphabet characters.
3684+ * \a 1 alphabet character.
3685+ *
3686+ * \- Subtraction operator.
3687+ *
3688+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
3689+ * /dir/dir/dir/ ).
3690+ *
3691+ * /\(dir\)/ '/' + 'Zero or more repetitions of dir/' (e.g. / /dir/
3692+ * /dir/dir/ ).
3693+ */
3694+static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
3695+ const struct ccs_path_info *pattern)
3696+{
3697+ const char *f = filename->name;
3698+ const char *p = pattern->name;
3699+ const int len = pattern->const_len;
3700+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
3701+ if (len == pattern->total_len)
3702+ return !ccs_pathcmp(filename, pattern);
3703+ /* Compare the initial length without patterns. */
3704+ if (strncmp(f, p, len))
3705+ return false;
3706+ f += len;
3707+ p += len;
3708+ /* Compare the last component first. */
3709+ {
3710+ const char *f2 = strrchr(f, '/');
3711+ const char *p2 = strrchr(p, '/');
3712+ if (!f2++)
3713+ f2 = f;
3714+ if (!p2++)
3715+ p2 = p;
3716+ if (!ccs_file_matches_pattern(f2, filename->name
3717+ + filename->total_len,
3718+ p2, pattern->name
3719+ + pattern->total_len))
3720+ return false;
3721+ }
3722+ return ccs_path_matches_pattern2(f, p);
3723+}
3724+
3725+/**
3726+ * ccs_clear_request_info - Release memory allocated during permission check.
3727+ *
3728+ * @r: Pointer to "struct ccs_request_info".
3729+ *
3730+ * Returns nothing.
3731+ */
3732+static void ccs_clear_request_info(struct ccs_request_info *r)
3733+{
3734+ u8 i;
3735+ /*
3736+ * r->obj.pathname[0] (which is referenced by r->obj.s[0]) and
3737+ * r->obj.pathname[1] (which is referenced by r->obj.s[1]) may contain
3738+ * pathnames allocated using ccs_populate_patharg() or ccs_mount_acl().
3739+ * Their callers do not allocate memory until pathnames becomes needed
3740+ * for checking condition or auditing requests.
3741+ *
3742+ * r->obj.s[2] and r->obj.s[3] are used by
3743+ * ccs_mount_acl()/ccs_env_perm() and are allocated/released by their
3744+ * callers.
3745+ */
3746+ for (i = 0; i < 2; i++) {
3747+ kfree(r->obj.pathname[i].name);
3748+ r->obj.pathname[i].name = NULL;
3749+ }
3750+ kfree(r->exename.name);
3751+ r->exename.name = NULL;
3752+}
--- trunk/caitsith-patch/security/caitsith/gc.c (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/gc.c (revision 2)
@@ -0,0 +1,581 @@
1+/*
2+ * security/caitsith/gc.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 0.1 2012/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/***** SECTION1: Constants definition *****/
12+
13+/* For compatibility with older kernels. */
14+#ifndef for_each_process
15+#define for_each_process for_each_task
16+#endif
17+
18+/* The list for "struct ccs_io_buffer". */
19+static LIST_HEAD(ccs_io_buffer_list);
20+/* Lock for protecting ccs_io_buffer_list. */
21+static DEFINE_SPINLOCK(ccs_io_buffer_list_lock);
22+
23+/***** SECTION2: Structure definition *****/
24+
25+/***** SECTION3: Prototype definition section *****/
26+
27+static bool ccs_domain_used_by_task(struct ccs_domain_info *domain);
28+static bool ccs_name_used_by_io_buffer(const char *string, const size_t size);
29+static bool ccs_struct_used_by_io_buffer(const struct list_head *element);
30+static int ccs_gc_thread(void *unused);
31+static void ccs_collect_acl(struct list_head *list);
32+static void ccs_collect_entry(void);
33+static void ccs_collect_member(const enum ccs_policy_id id,
34+ struct list_head *member_list);
35+static void ccs_memory_free(const void *ptr, const enum ccs_policy_id type);
36+static void ccs_try_to_gc(const enum ccs_policy_id type,
37+ struct list_head *element);
38+
39+/***** SECTION4: Standalone functions section *****/
40+
41+/***** SECTION5: Variables definition section *****/
42+
43+/*
44+ * Lock for syscall users.
45+ *
46+ * This lock is held for only protecting single SRCU section.
47+ */
48+struct srcu_struct ccs_ss;
49+
50+/***** SECTION6: Dependent functions section *****/
51+
52+/**
53+ * ccs_memory_free - Free memory for elements.
54+ *
55+ * @ptr: Pointer to allocated memory.
56+ * @type: One of values in "enum ccs_policy_id".
57+ *
58+ * Returns nothing.
59+ *
60+ * Caller holds ccs_policy_lock mutex.
61+ */
62+static void ccs_memory_free(const void *ptr, const enum ccs_policy_id type)
63+{
64+ /* Size of an element. */
65+ static const u8 e[CCS_MAX_POLICY] = {
66+ [CCS_ID_GROUP] = sizeof(struct ccs_group),
67+#ifdef CONFIG_CCSECURITY_NETWORK
68+ [CCS_ID_IP_GROUP] = sizeof(struct ccs_ip_group),
69+#endif
70+ [CCS_ID_STRING_GROUP] = sizeof(struct ccs_string_group),
71+ [CCS_ID_NUMBER_GROUP] = sizeof(struct ccs_number_group),
72+ /* [CCS_ID_CONDITION] = "struct ccs_condition"->size, */
73+ /* [CCS_ID_NAME] = "struct ccs_name"->size, */
74+ /* [CCS_ID_ACL] = sizeof(struct ccs_acl_info), */
75+ [CCS_ID_DOMAIN] = sizeof(struct ccs_domain_info),
76+ };
77+ size_t size;
78+ if (type == CCS_ID_ACL)
79+ size = sizeof(struct ccs_acl_info);
80+ else if (type == CCS_ID_NAME)
81+ size = container_of(ptr, typeof(struct ccs_name),
82+ head.list)->size;
83+ else if (type == CCS_ID_CONDITION)
84+ size = container_of(ptr, typeof(struct ccs_condition),
85+ head.list)->size;
86+ else
87+ size = e[type];
88+ ccs_memory_used[CCS_MEMORY_POLICY] -= ccs_round2(size);
89+ kfree(ptr);
90+}
91+
92+/**
93+ * ccs_struct_used_by_io_buffer - Check whether the list element is used by /proc/ccs/ users or not.
94+ *
95+ * @element: Pointer to "struct list_head".
96+ *
97+ * Returns true if @element is used by /proc/ccs/ users, false otherwise.
98+ */
99+static bool ccs_struct_used_by_io_buffer(const struct list_head *element)
100+{
101+ struct ccs_io_buffer *head;
102+ bool in_use = false;
103+ spin_lock(&ccs_io_buffer_list_lock);
104+ list_for_each_entry(head, &ccs_io_buffer_list, list) {
105+ head->users++;
106+ spin_unlock(&ccs_io_buffer_list_lock);
107+ mutex_lock(&head->io_sem);
108+ if (head->r.acl == element || head->r.subacl == element ||
109+ head->r.group == element || &head->w.acl->list == element)
110+ in_use = true;
111+ mutex_unlock(&head->io_sem);
112+ spin_lock(&ccs_io_buffer_list_lock);
113+ head->users--;
114+ if (in_use)
115+ break;
116+ }
117+ spin_unlock(&ccs_io_buffer_list_lock);
118+ return in_use;
119+}
120+
121+/**
122+ * ccs_name_used_by_io_buffer - Check whether the string is used by /proc/ccs/ users or not.
123+ *
124+ * @string: String to check.
125+ * @size: Memory allocated for @string .
126+ *
127+ * Returns true if @string is used by /proc/ccs/ users, false otherwise.
128+ */
129+static bool ccs_name_used_by_io_buffer(const char *string, const size_t size)
130+{
131+ struct ccs_io_buffer *head;
132+ bool in_use = false;
133+ spin_lock(&ccs_io_buffer_list_lock);
134+ list_for_each_entry(head, &ccs_io_buffer_list, list) {
135+ int i;
136+ head->users++;
137+ spin_unlock(&ccs_io_buffer_list_lock);
138+ mutex_lock(&head->io_sem);
139+ for (i = 0; i < CCS_MAX_IO_READ_QUEUE; i++) {
140+ const char *w = head->r.w[i];
141+ if (w < string || w > string + size)
142+ continue;
143+ in_use = true;
144+ break;
145+ }
146+ mutex_unlock(&head->io_sem);
147+ spin_lock(&ccs_io_buffer_list_lock);
148+ head->users--;
149+ if (in_use)
150+ break;
151+ }
152+ spin_unlock(&ccs_io_buffer_list_lock);
153+ return in_use;
154+}
155+
156+/**
157+ * ccs_domain_used_by_task - Check whether the given pointer is referenced by a task.
158+ *
159+ * @domain: Pointer to "struct ccs_domain_info".
160+ *
161+ * Returns true if @domain is in use, false otherwise.
162+ */
163+static bool ccs_domain_used_by_task(struct ccs_domain_info *domain)
164+{
165+ bool in_use = false;
166+ /*
167+ * Don't delete this domain if somebody is doing execve().
168+ *
169+ * Since ccs_finish_execve() first reverts ccs_domain_info and then
170+ * updates ccs_flags, we need smp_rmb() to make sure that GC first
171+ * checks ccs_flags and then checks ccs_domain_info.
172+ */
173+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
174+ int idx;
175+ rcu_read_lock();
176+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
177+ struct ccs_security *ptr;
178+ struct list_head *list = &ccs_task_security_list[idx];
179+ list_for_each_entry_rcu(ptr, list, list) {
180+ if (!(ptr->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
181+ smp_rmb(); /* Avoid out of order execution. */
182+ if (ptr->ccs_domain_info != domain)
183+ continue;
184+ }
185+ in_use = true;
186+ goto out;
187+ }
188+ }
189+out:
190+ rcu_read_unlock();
191+#else
192+ struct task_struct *g;
193+ struct task_struct *t;
194+ ccs_tasklist_lock();
195+ do_each_thread(g, t) {
196+ if (!(t->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
197+ smp_rmb(); /* Avoid out of order execution. */
198+ if (t->ccs_domain_info != domain)
199+ continue;
200+ }
201+ in_use = true;
202+ goto out;
203+ } while_each_thread(g, t);
204+out:
205+ ccs_tasklist_unlock();
206+#endif
207+ return in_use;
208+}
209+
210+/**
211+ * ccs_del_acl - Delete members in "struct ccs_acl_info".
212+ *
213+ * @element: Pointer to "struct list_head".
214+ *
215+ * Returns nothing.
216+ */
217+static inline void ccs_del_acl(struct list_head *element)
218+{
219+ struct ccs_acl_info *acl = container_of(element, typeof(*acl), list);
220+ ccs_put_condition(acl->cond);
221+}
222+
223+/**
224+ * ccs_del_domain - Delete members in "struct ccs_domain_info".
225+ *
226+ * @element: Pointer to "struct list_head".
227+ *
228+ * Returns nothing.
229+ *
230+ * Caller holds ccs_policy_lock mutex.
231+ */
232+static inline void ccs_del_domain(struct list_head *element)
233+{
234+ struct ccs_domain_info *domain =
235+ container_of(element, typeof(*domain), list);
236+ ccs_put_name(domain->domainname);
237+}
238+
239+/**
240+ * ccs_del_string_group - Delete members in "struct ccs_string_group".
241+ *
242+ * @element: Pointer to "struct list_head".
243+ *
244+ * Returns nothing.
245+ */
246+static inline void ccs_del_string_group(struct list_head *element)
247+{
248+ struct ccs_string_group *member =
249+ container_of(element, typeof(*member), head.list);
250+ ccs_put_name(member->member_name);
251+}
252+
253+/**
254+ * ccs_del_group - Delete "struct ccs_group".
255+ *
256+ * @element: Pointer to "struct list_head".
257+ *
258+ * Returns nothing.
259+ */
260+static inline void ccs_del_group(struct list_head *element)
261+{
262+ struct ccs_group *group =
263+ container_of(element, typeof(*group), head.list);
264+ ccs_put_name(group->group_name);
265+}
266+
267+/**
268+ * ccs_del_condition - Delete members in "struct ccs_condition".
269+ *
270+ * @element: Pointer to "struct list_head".
271+ *
272+ * Returns nothing.
273+ */
274+void ccs_del_condition(struct list_head *element)
275+{
276+ struct ccs_condition *cond = container_of(element, typeof(*cond),
277+ head.list);
278+ const union ccs_condition_element *condp = (typeof(condp)) (cond + 1);
279+ while ((void *) condp < (void *) ((u8 *) cond) + cond->size) {
280+ const enum ccs_conditions_index left = condp->left;
281+ const enum ccs_conditions_index right = condp->right;
282+ condp++;
283+ if (left == CCS_ARGV_ENTRY)
284+ condp++;
285+ else if (left == CCS_ENVP_ENTRY) {
286+ ccs_put_name(condp->path);
287+ condp++;
288+ }
289+ if (right == CCS_IMM_GROUP) {
290+ ccs_put_group(condp->group);
291+ condp++;
292+ } else if (right == CCS_IMM_NAME_ENTRY) {
293+ if (condp->path != &ccs_null_name)
294+ ccs_put_name(condp->path);
295+ condp++;
296+ } else if (right == CCS_IMM_NUMBER_ENTRY1)
297+ condp++;
298+ else if (right == CCS_IMM_NUMBER_ENTRY2)
299+ condp += 2;
300+#ifdef CONFIG_CCSECURITY_NETWORK
301+ else if (right == CCS_IMM_IPV6ADDR_ENTRY1)
302+ condp = (void *)
303+ (((u8 *) condp) + sizeof(struct in6_addr));
304+ else if (right == CCS_IMM_IPV6ADDR_ENTRY2)
305+ condp = (void *)
306+ (((u8 *) condp) + sizeof(struct in6_addr) * 2);
307+#endif
308+ }
309+}
310+
311+/**
312+ * ccs_try_to_gc - Try to kfree() an entry.
313+ *
314+ * @type: One of values in "enum ccs_policy_id".
315+ * @element: Pointer to "struct list_head".
316+ *
317+ * Returns nothing.
318+ *
319+ * Caller holds ccs_policy_lock mutex.
320+ */
321+static void ccs_try_to_gc(const enum ccs_policy_id type,
322+ struct list_head *element)
323+{
324+ /*
325+ * __list_del_entry() guarantees that the list element became no longer
326+ * reachable from the list which the element was originally on (e.g.
327+ * ccs_domain_list). Also, synchronize_srcu() guarantees that the list
328+ * element became no longer referenced by syscall users.
329+ */
330+ __list_del_entry(element);
331+ mutex_unlock(&ccs_policy_lock);
332+ synchronize_srcu(&ccs_ss);
333+ /*
334+ * However, there are two users which may still be using the list
335+ * element. We need to defer until both users forget this element.
336+ *
337+ * Don't kfree() until "struct ccs_io_buffer"->r.{group,acl,subacl} and
338+ * "struct ccs_io_buffer"->w.acl forget this element.
339+ */
340+ if (ccs_struct_used_by_io_buffer(element))
341+ goto reinject;
342+ switch (type) {
343+ case CCS_ID_GROUP:
344+ ccs_del_group(element);
345+ break;
346+ case CCS_ID_STRING_GROUP:
347+ ccs_del_string_group(element);
348+ break;
349+ case CCS_ID_CONDITION:
350+ ccs_del_condition(element);
351+ break;
352+ case CCS_ID_NAME:
353+ /*
354+ * Don't kfree() until all "struct ccs_io_buffer"->r.w[] forget
355+ * this element.
356+ */
357+ if (ccs_name_used_by_io_buffer
358+ (container_of(element, typeof(struct ccs_name),
359+ head.list)->entry.name,
360+ container_of(element, typeof(struct ccs_name),
361+ head.list)->size))
362+ goto reinject;
363+ break;
364+ case CCS_ID_ACL:
365+ ccs_del_acl(element);
366+ break;
367+ case CCS_ID_DOMAIN:
368+ /*
369+ * Don't kfree() until all "struct task_struct" forget this
370+ * element.
371+ */
372+ if (ccs_domain_used_by_task
373+ (container_of(element, typeof(struct ccs_domain_info),
374+ list)))
375+ goto reinject;
376+ ccs_del_domain(element);
377+ break;
378+ default:
379+ break;
380+ }
381+ mutex_lock(&ccs_policy_lock);
382+ ccs_memory_free(element, type);
383+ return;
384+reinject:
385+ /*
386+ * We can safely reinject this element here bacause
387+ * (1) Appending list elements and removing list elements are protected
388+ * by ccs_policy_lock mutex.
389+ * (2) Only this function removes list elements and this function is
390+ * exclusively executed by ccs_gc_mutex mutex.
391+ * are true.
392+ */
393+ mutex_lock(&ccs_policy_lock);
394+ list_add_rcu(element, element->prev);
395+}
396+
397+/**
398+ * ccs_collect_member - Delete elements with "struct ccs_acl_head".
399+ *
400+ * @id: One of values in "enum ccs_policy_id".
401+ * @member_list: Pointer to "struct list_head".
402+ *
403+ * Returns nothing.
404+ *
405+ * Caller holds ccs_policy_lock mutex.
406+ */
407+static void ccs_collect_member(const enum ccs_policy_id id,
408+ struct list_head *member_list)
409+{
410+ struct ccs_acl_head *member;
411+ struct ccs_acl_head *tmp;
412+ list_for_each_entry_safe(member, tmp, member_list, list) {
413+ if (!member->is_deleted)
414+ continue;
415+ member->is_deleted = CCS_GC_IN_PROGRESS;
416+ ccs_try_to_gc(id, &member->list);
417+ }
418+}
419+
420+/**
421+ * ccs_collect_acl - Delete elements in "struct ccs_acl_info".
422+ *
423+ * @list: Pointer to "struct list_head".
424+ *
425+ * Returns nothing.
426+ *
427+ * Caller holds ccs_policy_lock mutex.
428+ */
429+static void ccs_collect_acl(struct list_head *list)
430+{
431+ struct ccs_acl_info *acl;
432+ struct ccs_acl_info *tmp;
433+ list_for_each_entry_safe(acl, tmp, list, list) {
434+ if (!acl->is_deleted)
435+ continue;
436+ ccs_try_to_gc(CCS_ID_ACL, &acl->list);
437+ }
438+}
439+
440+/**
441+ * ccs_collect_entry - Try to kfree() deleted elements.
442+ *
443+ * Returns nothing.
444+ */
445+static void ccs_collect_entry(void)
446+{
447+ int i;
448+ mutex_lock(&ccs_policy_lock);
449+ {
450+ struct ccs_domain_info *domain;
451+ struct ccs_domain_info *tmp;
452+ list_for_each_entry_safe(domain, tmp, &ccs_domain_list, list) {
453+ if (ccs_domain_used_by_task(domain))
454+ continue;
455+ ccs_try_to_gc(CCS_ID_DOMAIN, &domain->list);
456+ }
457+ }
458+ for (i = 0; i < CCS_MAX_MAC_INDEX; i++) {
459+ struct ccs_acl_info *ptr;
460+ struct ccs_acl_info *tmp;
461+ struct list_head * const list = &ccs_acl_list[i];
462+ list_for_each_entry_safe(ptr, tmp, list, list) {
463+ ccs_collect_acl(&ptr->acl_info_list);
464+ if (!ptr->is_deleted ||
465+ !list_empty(&ptr->acl_info_list))
466+ continue;
467+ /* ptr->is_deleted = CCS_GC_IN_PROGRESS; */
468+ ccs_try_to_gc(CCS_ID_ACL, &ptr->list);
469+ }
470+ }
471+ {
472+ struct ccs_shared_acl_head *ptr;
473+ struct ccs_shared_acl_head *tmp;
474+ list_for_each_entry_safe(ptr, tmp, &ccs_condition_list, list) {
475+ if (atomic_read(&ptr->users) > 0)
476+ continue;
477+ atomic_set(&ptr->users, CCS_GC_IN_PROGRESS);
478+ ccs_try_to_gc(CCS_ID_CONDITION, &ptr->list);
479+ }
480+ }
481+ for (i = 0; i < CCS_MAX_GROUP; i++) {
482+ struct list_head *list = &ccs_group_list[i];
483+ struct ccs_group *group;
484+ struct ccs_group *tmp;
485+ enum ccs_policy_id id = CCS_ID_STRING_GROUP;
486+ if (i == CCS_NUMBER_GROUP)
487+ id = CCS_ID_NUMBER_GROUP;
488+#ifdef CONFIG_CCSECURITY_NETWORK
489+ else if (i == CCS_IP_GROUP)
490+ id = CCS_ID_IP_GROUP;
491+#endif
492+ list_for_each_entry_safe(group, tmp, list, head.list) {
493+ ccs_collect_member(id, &group->member_list);
494+ if (!list_empty(&group->member_list) ||
495+ atomic_read(&group->head.users) > 0)
496+ continue;
497+ atomic_set(&group->head.users, CCS_GC_IN_PROGRESS);
498+ ccs_try_to_gc(CCS_ID_GROUP, &group->head.list);
499+ }
500+ }
501+ for (i = 0; i < CCS_MAX_HASH; i++) {
502+ struct list_head *list = &ccs_name_list[i];
503+ struct ccs_shared_acl_head *ptr;
504+ struct ccs_shared_acl_head *tmp;
505+ list_for_each_entry_safe(ptr, tmp, list, list) {
506+ if (atomic_read(&ptr->users) > 0)
507+ continue;
508+ atomic_set(&ptr->users, CCS_GC_IN_PROGRESS);
509+ ccs_try_to_gc(CCS_ID_NAME, &ptr->list);
510+ }
511+ }
512+ mutex_unlock(&ccs_policy_lock);
513+}
514+
515+/**
516+ * ccs_gc_thread - Garbage collector thread function.
517+ *
518+ * @unused: Unused.
519+ *
520+ * Returns 0.
521+ */
522+static int ccs_gc_thread(void *unused)
523+{
524+ /* Garbage collector thread is exclusive. */
525+ static DEFINE_MUTEX(ccs_gc_mutex);
526+ if (!mutex_trylock(&ccs_gc_mutex))
527+ goto out;
528+ ccs_collect_entry();
529+ {
530+ struct ccs_io_buffer *head;
531+ struct ccs_io_buffer *tmp;
532+ spin_lock(&ccs_io_buffer_list_lock);
533+ list_for_each_entry_safe(head, tmp, &ccs_io_buffer_list,
534+ list) {
535+ if (head->users)
536+ continue;
537+ list_del(&head->list);
538+ kfree(head->read_buf);
539+ kfree(head->write_buf);
540+ kfree(head);
541+ }
542+ spin_unlock(&ccs_io_buffer_list_lock);
543+ }
544+ mutex_unlock(&ccs_gc_mutex);
545+out:
546+ /* This acts as do_exit(0). */
547+ return 0;
548+}
549+
550+/**
551+ * ccs_notify_gc - Register/unregister /proc/ccs/ users.
552+ *
553+ * @head: Pointer to "struct ccs_io_buffer".
554+ * @is_register: True if register, false if unregister.
555+ *
556+ * Returns nothing.
557+ */
558+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register)
559+{
560+ bool is_write = false;
561+ spin_lock(&ccs_io_buffer_list_lock);
562+ if (is_register) {
563+ head->users = 1;
564+ list_add(&head->list, &ccs_io_buffer_list);
565+ } else {
566+ is_write = head->write_buf != NULL;
567+ if (!--head->users) {
568+ list_del(&head->list);
569+ kfree(head->read_buf);
570+ kfree(head->write_buf);
571+ kfree(head);
572+ }
573+ }
574+ spin_unlock(&ccs_io_buffer_list_lock);
575+ if (is_write) {
576+ struct task_struct *task = kthread_create(ccs_gc_thread, NULL,
577+ "GC for CCS");
578+ if (!IS_ERR(task))
579+ wake_up_process(task);
580+ }
581+}
--- trunk/caitsith-patch/security/caitsith/Makefile (nonexistent)
+++ trunk/caitsith-patch/security/caitsith/Makefile (revision 2)
@@ -0,0 +1,22 @@
1+ccsecurity-objs := permission.o gc.o memory.o policy_io.o realpath.o
2+
3+obj-y += load_policy.o
4+ifdef CONFIG_CCSECURITY_LKM
5+obj-m += ccsecurity.o
6+else
7+obj-y += ccsecurity.o
8+endif
9+
10+$(obj)/policy/policy.conf:
11+ @mkdir -p $(obj)/policy/
12+ @echo Creating an empty policy/policy.conf
13+ @touch $@
14+
15+$(obj)/builtin-policy.h: $(obj)/policy/policy.conf
16+ @echo Generating built-in policy for CaitSith 0.1.
17+ @echo "static char ccs_builtin_policy[] __initdata =" > $@.tmp
18+ @sed -e 's/\\/\\134/g' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/policy.conf >> $@.tmp
19+ @echo "\"\";" >> $@.tmp
20+ @mv $@.tmp $@
21+
22+$(obj)/policy_io.o: $(obj)/builtin-policy.h
--- trunk/caitsith-tools/caitsith-tools.spec (nonexistent)
+++ trunk/caitsith-tools/caitsith-tools.spec (revision 2)
@@ -0,0 +1,55 @@
1+Summary: Userspace tools for CaitSith 0.1
2+
3+Name: caitsith-tools
4+Version: 0.1
5+Release: 1
6+License: GPL
7+Group: System Environment/Kernel
8+ExclusiveOS: Linux
9+Autoreqprov: no
10+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
11+##
12+## This spec file is intended to be distribution independent.
13+## I don't enable "BuildRequires:" line because rpmbuild will fail on
14+## environments where packages are managed by (e.g.) apt.
15+##
16+# BuildRequires: ncurses-devel
17+Requires: ncurses
18+Conflicts: caitsith-tools < 0.1-1
19+
20+Source0: http://osdn.dl.sourceforge.jp/caitsith/XXXXX/caitsith-tools-0.1-20120401.tar.gz
21+
22+%description
23+This package contains userspace tools for administrating CaitSith 0.1.
24+Please see http://caitsith.sourceforge.jp/ for documentation.
25+
26+%prep
27+
28+%setup -q -n caitsithtools
29+
30+%build
31+
32+make USRLIBDIR=%_libdir CFLAGS="-Wall $RPM_OPT_FLAGS"
33+
34+%install
35+
36+rm -rf $RPM_BUILD_ROOT
37+make INSTALLDIR=$RPM_BUILD_ROOT USRLIBDIR=%_libdir install
38+
39+%clean
40+
41+rm -rf $RPM_BUILD_ROOT
42+
43+%post
44+ldconfig || true
45+
46+%files
47+%defattr(-,root,root)
48+/sbin/
49+%_libdir/caitsith/
50+%_libdir/libcaitsith*
51+/usr/sbin/
52+
53+%changelog
54+* Sun Apr 01 2012 0.1-1
55+- First-release.
--- trunk/caitsith-tools/kernel_test/ccs_param_test.c (nonexistent)
+++ trunk/caitsith-tools/kernel_test/ccs_param_test.c (revision 2)
@@ -0,0 +1,1764 @@
1+#include <stdio.h>
2+#include <stdlib.h>
3+#include <string.h>
4+#include <unistd.h>
5+#include <sys/types.h>
6+#include <sys/stat.h>
7+#include <sys/socket.h>
8+#include <netinet/in.h>
9+#include <sys/ptrace.h>
10+#include <sys/wait.h>
11+#include <linux/ip.h>
12+#include <fcntl.h>
13+#include <errno.h>
14+
15+static FILE *fp = NULL;
16+
17+static void set(const char *str)
18+{
19+ fprintf(fp, "%s\n", str);
20+ fflush(fp);
21+}
22+
23+static void unset(const char *str)
24+{
25+ fprintf(fp, "delete %s\n", str);
26+ fflush(fp);
27+}
28+
29+static void unset2(const char *str)
30+{
31+ const char *cp = str;
32+ while (*cp) {
33+ if (*cp++ != '\n')
34+ continue;
35+ fprintf(fp, "delete ");
36+ fwrite(str, cp - str, 1, fp);
37+ str = cp;
38+ }
39+ fprintf(fp, "delete %s\n", str);
40+ fflush(fp);
41+}
42+
43+static void check(const char *prompt, int result)
44+{
45+ int err = errno;
46+ printf("%s%s\n", prompt, result ? "Success" : "Failed");
47+ if (!result) {
48+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
49+ {
50+ int fd2 = open("/proc/caitsith/self_domain", O_RDONLY);
51+ char c;
52+ fprintf(stderr, "task.domain=\"");
53+ while (read(fd2, &c, 1) == 1)
54+ fprintf(stderr, "%c", c);
55+ close(fd2);
56+ fprintf(stderr, "\"\n");
57+ }
58+ exit(1);
59+ }
60+ printf("\n");
61+ fflush(stdout);
62+}
63+
64+static void check_init(const char *prompt, const char *expected)
65+{
66+ int result;
67+ int fd = open("/proc/caitsith/.process_status", O_RDWR);
68+ char buffer[1024];
69+ char *cp;
70+ memset(buffer, 0, sizeof(buffer));
71+ kill(1, SIGHUP);
72+ sleep(1);
73+ write(fd, "1\n", 2);
74+ read(fd, buffer, sizeof(buffer) - 1);
75+ close(fd);
76+ cp = strchr(buffer, ' ');
77+ if (cp++)
78+ memmove(buffer, cp, strlen(cp) + 1);
79+ result = !strcmp(buffer, expected);
80+ printf("%s%s\n", prompt, result ? "Success" : "Failed");
81+ if (!result) {
82+ fprintf(stderr, "Err: expected='%s' result='%s'\n",
83+ expected, buffer);
84+ exit(1);
85+ }
86+ printf("\n");
87+ fflush(stdout);
88+}
89+
90+static void test_task_transition(void)
91+{
92+ int fd = open("/proc/caitsith/self_domain", O_WRONLY);
93+ char *policy;
94+
95+ policy = "100 acl manual_domain_transition\n"
96+ "0 allow domain=\"domain\\$\"\n";
97+ set(policy);
98+ check(policy, write(fd, "domain0", 7) != EOF);
99+ check(policy, write(fd, "domain10", 8) != EOF);
100+ check(policy, write(fd, "domainXYX", 9) == EOF);
101+ check(policy, write(fd, "domain200", 9) != EOF);
102+ unset(policy);
103+
104+ policy = "100 acl auto_domain_transition\n"
105+ "0 allow task.pid=1 transition=\"<init3>\"\n";
106+ set(policy);
107+ check_init(policy, "<init3>");
108+ unset(policy);
109+
110+ policy = "100 acl auto_domain_transition\n"
111+ "0 allow task.pid=1 task.uid!=0 transition=\"<init2>\"\n";
112+ set(policy);
113+ check_init(policy, "<init3>");
114+ unset(policy);
115+
116+ policy = "100 acl auto_domain_transition\n"
117+ "0 allow task.pid=1 transition=\"<init>\"\n";
118+ set(policy);
119+ check_init(policy, "<init>");
120+ unset(policy);
121+
122+ close(fd);
123+}
124+
125+static void test_file_read(void)
126+{
127+ int fd;
128+ char *policy;
129+
130+ policy = "100 acl read\n";
131+ set(policy);
132+ fd = open("/dev/null", O_RDONLY);
133+ check(policy, fd != EOF);
134+ close(fd);
135+ unset(policy);
136+
137+ policy = "100 acl read\n"
138+ "0 allow\n"
139+ "1 deny\n";
140+ set(policy);
141+ fd = open("/dev/null", O_RDONLY);
142+ check(policy, fd != EOF);
143+ close(fd);
144+ unset(policy);
145+
146+ policy = "100 acl read\n"
147+ "0 deny\n"
148+ "1 allow\n";
149+ set(policy);
150+ fd = open("/dev/null", O_RDONLY);
151+ check(policy, fd == EOF);
152+ close(fd);
153+ unset(policy);
154+
155+ policy = "100 acl read path=\"/dev/null\"\n"
156+ "0 allow\n"
157+ "1 deny\n";
158+ set(policy);
159+ fd = open("/dev/null", O_RDONLY);
160+ check(policy, fd != EOF);
161+ close(fd);
162+ unset(policy);
163+
164+ policy = "100 acl read path=\"/dev/null\"\n"
165+ "0 deny\n"
166+ "1 allow\n";
167+ set(policy);
168+ fd = open("/dev/null", O_RDONLY);
169+ check(policy, fd == EOF);
170+ close(fd);
171+ unset(policy);
172+
173+ policy = "100 acl read\n"
174+ "0 allow path=\"/dev/null\"\n"
175+ "1 deny\n";
176+ set(policy);
177+ fd = open("/dev/null", O_RDONLY);
178+ check(policy, fd != EOF);
179+ close(fd);
180+ unset(policy);
181+
182+ policy = "100 acl read\n"
183+ "0 deny path=\"/dev/null\"\n"
184+ "1 allow\n";
185+ set(policy);
186+ fd = open("/dev/null", O_RDONLY);
187+ check(policy, fd == EOF);
188+ close(fd);
189+ unset(policy);
190+
191+ policy = "100 acl read\n"
192+ "0 allow path.type=char path.dev_major=1 path.dev_minor=3\n"
193+ "1 deny\n";
194+ set(policy);
195+ fd = open("/dev/null", O_RDONLY);
196+ check(policy, fd != EOF);
197+ close(fd);
198+ unset(policy);
199+
200+ policy = "100 acl read\n"
201+ "0 deny path.type=char path.dev_major=1 path.dev_minor=3\n"
202+ "1 allow\n";
203+ set(policy);
204+ fd = open("/dev/null", O_RDONLY);
205+ check(policy, fd == EOF);
206+ close(fd);
207+ unset(policy);
208+
209+ policy = "100 acl read\n"
210+ "0 allow path.type=char path.dev_major=1 path.dev_minor!=3\n"
211+ "1 deny\n";
212+ set(policy);
213+ fd = open("/dev/null", O_RDONLY);
214+ check(policy, fd == EOF);
215+ close(fd);
216+ unset(policy);
217+
218+ policy = "100 acl read\n"
219+ "0 deny path.type=char path.dev_major=1 path.dev_minor!=3\n"
220+ "1 allow\n";
221+ set(policy);
222+ fd = open("/dev/null", O_RDONLY);
223+ check(policy, fd != EOF);
224+ close(fd);
225+ unset(policy);
226+
227+ policy = "string_group GROUP1 /dev/null\n"
228+ "100 acl read\n"
229+ "0 allow path=@GROUP1\n"
230+ "1 deny\n";
231+ set(policy);
232+ fd = open("/dev/null", O_RDONLY);
233+ check(policy, fd != EOF);
234+ close(fd);
235+ unset2(policy);
236+
237+ policy = "string_group GROUP1 /dev/null\n"
238+ "100 acl read\n"
239+ "0 deny path=@GROUP1\n"
240+ "1 allow\n";
241+ set(policy);
242+ fd = open("/dev/null", O_RDONLY);
243+ check(policy, fd == EOF);
244+ close(fd);
245+ unset2(policy);
246+
247+ policy = "string_group GROUP1 /dev/null\n"
248+ "100 acl read\n"
249+ "0 allow path!=@GROUP1\n"
250+ "1 deny\n";
251+ set(policy);
252+ fd = open("/dev/null", O_RDONLY);
253+ check(policy, fd == EOF);
254+ close(fd);
255+ unset2(policy);
256+
257+ policy = "string_group GROUP1 /dev/null\n"
258+ "100 acl read\n"
259+ "0 deny path!=@GROUP1\n"
260+ "1 allow\n";
261+ set(policy);
262+ fd = open("/dev/null", O_RDONLY);
263+ check(policy, fd != EOF);
264+ close(fd);
265+ unset2(policy);
266+
267+ policy = "string_group GROUP1 /dev/null\n"
268+ "number_group MAJOR 1\n"
269+ "number_group MINOR 3\n"
270+ "100 acl read\n"
271+ "0 allow path=@GROUP1 path.dev_major=@MAJOR"
272+ " path.dev_minor=@MINOR\n"
273+ "1 deny\n";
274+ set(policy);
275+ fd = open("/dev/null", O_RDONLY);
276+ check(policy, fd != EOF);
277+ close(fd);
278+ unset2(policy);
279+
280+ policy = "string_group GROUP1 /dev/null\n"
281+ "number_group MAJOR 1\n"
282+ "number_group MINOR 3\n"
283+ "100 acl read\n"
284+ "0 deny path=@GROUP1 path.dev_major=@MAJOR"
285+ " path.dev_minor=@MINOR\n"
286+ "1 allow\n";
287+ set(policy);
288+ fd = open("/dev/null", O_RDONLY);
289+ check(policy, fd == EOF);
290+ close(fd);
291+ unset2(policy);
292+
293+ policy = "string_group GROUP1 /dev/zero\n"
294+ "string_group GROUP1 /dev/null\n"
295+ "string_group GROUP1 /dev/urandom\n"
296+ "number_group MAJOR 0\n"
297+ "number_group MAJOR 2-255\n"
298+ "number_group MINOR 00-0x2\n"
299+ "number_group MINOR 255\n"
300+ "100 acl read\n"
301+ "0 allow path=@GROUP1 path.dev_major=@MAJOR"
302+ " path.dev_minor=@MINOR\n"
303+ "1 deny\n";
304+ set(policy);
305+ fd = open("/dev/null", O_RDONLY);
306+ check(policy, fd == EOF);
307+ close(fd);
308+ unset2(policy);
309+
310+ policy = "string_group GROUP1 /dev/zero\n"
311+ "string_group GROUP1 /dev/null\n"
312+ "string_group GROUP1 /dev/urandom\n"
313+ "number_group MAJOR 0\n"
314+ "number_group MAJOR 2-255\n"
315+ "number_group MINOR 00-0x2\n"
316+ "number_group MINOR 255\n"
317+ "100 acl read\n"
318+ "0 allow path=@GROUP1 path.dev_major!=@MAJOR"
319+ " path.dev_minor!=@MINOR\n"
320+ "1 deny\n";
321+ set(policy);
322+ fd = open("/dev/null", O_RDONLY);
323+ check(policy, fd != EOF);
324+ close(fd);
325+ unset2(policy);
326+}
327+
328+static void test_file_write(void)
329+{
330+ int fd;
331+ char *policy;
332+
333+ policy = "100 acl write\n"
334+ "0 allow\n"
335+ "100 acl append\n"
336+ "0 deny\n";
337+ set(policy);
338+ fd = open("/dev/null", O_WRONLY);
339+ check(policy, fd != EOF);
340+ close(fd);
341+ unset2(policy);
342+
343+ policy = "100 acl write\n"
344+ "0 deny\n"
345+ "100 acl append\n"
346+ "0 allow\n";
347+ set(policy);
348+ fd = open("/dev/null", O_WRONLY);
349+ check(policy, fd == EOF);
350+ close(fd);
351+ unset2(policy);
352+
353+ policy = "100 acl write\n"
354+ "0 allow\n"
355+ "100 acl append\n"
356+ "0 deny\n";
357+ set(policy);
358+ fd = open("/dev/null", O_WRONLY | O_APPEND);
359+ check(policy, fd == EOF);
360+ close(fd);
361+ unset2(policy);
362+
363+ policy = "100 acl write\n"
364+ "0 deny\n"
365+ "100 acl append\n"
366+ "0 append\n";
367+ set(policy);
368+ fd = open("/dev/null", O_WRONLY | O_APPEND);
369+ check(policy, fd != EOF);
370+ close(fd);
371+ unset2(policy);
372+
373+ policy = "100 acl write\n"
374+ "0 allow path.type=char path.dev_major=1 path.dev_minor=3\n"
375+ "1 deny\n";
376+ set(policy);
377+ fd = open("/dev/null", O_WRONLY | O_TRUNC);
378+ check(policy, fd != EOF);
379+ close(fd);
380+ unset(policy);
381+
382+ policy = "100 acl write\n"
383+ "0 allow path.type=char path.dev_major=1"
384+ " path.dev_minor=@MINOR\n"
385+ "1 deny\n";
386+ set(policy);
387+ fd = open("/dev/null", O_WRONLY | O_TRUNC);
388+ check(policy, fd == EOF);
389+ close(fd);
390+ unset(policy);
391+
392+ policy = "100 acl write\n"
393+ "0 allow path.parent.type=directory path.parent.uid=0"
394+ " path.parent.perm=0755\n"
395+ "1 deny\n";
396+ set(policy);
397+ fd = open("/dev/null", O_WRONLY);
398+ check(policy, fd != EOF);
399+ close(fd);
400+ unset(policy);
401+
402+ policy = "100 acl write\n"
403+ "0 allow path.parent.uid=task.uid path.parent.gid=task.gid\n"
404+ "1 deny\n";
405+ set(policy);
406+ fd = open("/dev/null", O_WRONLY);
407+ check(policy, fd != EOF);
408+ close(fd);
409+ unset(policy);
410+
411+ policy = "100 acl write\n"
412+ "0 allow task.uid=path.parent.uid task.gid=path.parent.gid\n"
413+ "1 deny\n";
414+ set(policy);
415+ fd = open("/dev/null", O_WRONLY);
416+ check(policy, fd != EOF);
417+ close(fd);
418+ unset(policy);
419+}
420+
421+static void test_file_create(void)
422+{
423+ int fd;
424+ char *policy;
425+
426+ policy = "100 acl create\n"
427+ "0 allow path.uid=0\n"
428+ "1 deny\n";
429+ set(policy);
430+ unlink("/tmp/file");
431+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
432+ check(policy, fd == EOF);
433+ close(fd);
434+ unset(policy);
435+
436+ policy = "100 acl create\n"
437+ "0 allow path=\"/tmp/file\" path.parent.uid=0\n"
438+ "1 deny\n";
439+ set(policy);
440+ unlink("/tmp/file");
441+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
442+ check(policy, fd != EOF);
443+ close(fd);
444+ unset(policy);
445+
446+ policy = "number_group GROUP1 1-0xFFFFFFFF\n"
447+ "100 acl create\n"
448+ "0 allow path.parent.uid!=@GROUP1 perm=0600\n"
449+ "1 deny\n";
450+ set(policy);
451+ unlink("/tmp/file");
452+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
453+ check(policy, fd != EOF);
454+ close(fd);
455+ unset2(policy);
456+
457+ policy = "number_group GROUP1 1-0xFFFFFFFF\n"
458+ "100 acl create\n"
459+ "0 allow path.parent.uid!=@GROUP1 perm!=0600\n"
460+ "1 deny\n";
461+ set(policy);
462+ unlink("/tmp/file");
463+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
464+ check(policy, fd == EOF);
465+ close(fd);
466+ unset2(policy);
467+
468+ policy = "100 acl create\n"
469+ "0 allow path.parent.uid=task.uid\n"
470+ "1 deny\n";
471+ set(policy);
472+ unlink("/tmp/file");
473+ fd = open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600);
474+ check(policy, fd != EOF);
475+ close(fd);
476+ unset(policy);
477+}
478+
479+static void test_file_unlink(void)
480+{
481+ char *policy;
482+
483+ policy = "100 acl unlink\n"
484+ "0 allow path.uid=0 path.uid=path.parent.uid\n"
485+ "1 deny\n";
486+ set(policy);
487+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
488+ check(policy, unlink("/tmp/file") == 0);
489+ unset(policy);
490+
491+ policy = "100 acl unlink\n"
492+ "0 deny path.uid=0 path.uid=path.parent.uid\n"
493+ "1 allow\n";
494+ set(policy);
495+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
496+ check(policy, unlink("/tmp/file") == EOF);
497+ unset(policy);
498+}
499+
500+static void test_file_link(void)
501+{
502+ char *policy;
503+
504+ policy = "100 acl link\n"
505+ "0 allow old_path.uid=0 old_path.uid=old_path.parent.uid"
506+ " old_path.parent.ino=new_path.parent.ino\n"
507+ "1 deny\n";
508+ set(policy);
509+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
510+ unlink("/tmp/file2");
511+ check(policy, link("/tmp/file", "/tmp/file2") == 0);
512+ unset(policy);
513+
514+ policy = "100 acl link\n"
515+ "0 deny old_path.uid=0 old_path.uid=old_path.parent.uid\n"
516+ "1 allow\n";
517+ set(policy);
518+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
519+ unlink("/tmp/file2");
520+ check(policy, link("/tmp/file", "/tmp/file2") == EOF);
521+ unset(policy);
522+}
523+
524+static void test_file_rename(void)
525+{
526+ char *policy;
527+
528+ policy = "100 acl rename\n"
529+ "0 allow old_path.uid=0 old_path.uid=old_path.parent.uid"
530+ " old_path.parent.ino=new_path.parent.ino\n"
531+ "1 deny\n";
532+ set(policy);
533+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
534+ unlink("/tmp/file2");
535+ check(policy, rename("/tmp/file", "/tmp/file2") == 0);
536+ unset(policy);
537+
538+ policy = "100 acl rename\n"
539+ "0 deny old_path.uid=0 old_path.uid=old_path.parent.uid\n"
540+ "1 allow\n";
541+ set(policy);
542+ close(open("/tmp/file", O_CREAT | O_WRONLY | O_EXCL, 0600));
543+ unlink("/tmp/file2");
544+ check(policy, rename("/tmp/file", "/tmp/file2") == EOF);
545+ unset(policy);
546+}
547+
548+static void test_network_inet_stream(void)
549+{
550+ struct sockaddr_in addr1 = { };
551+ struct sockaddr_in addr2 = { };
552+ socklen_t size = sizeof(addr1);
553+ int fd1;
554+ int fd2;
555+ int fd3;
556+ char *policy;
557+ char buffer[1024];
558+ memset(buffer, 0, sizeof(buffer));
559+
560+ fd1 = socket(PF_INET, SOCK_STREAM, 0);
561+ fd2 = socket(PF_INET, SOCK_STREAM, 0);
562+ addr1.sin_family = AF_INET;
563+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
564+
565+ policy = "100 acl inet_stream_bind\n"
566+ "0 allow ip=127.0.0.1 port!=0\n"
567+ "1 deny\n";
568+ set(policy);
569+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
570+ EOF);
571+ unset(policy);
572+
573+ policy = "100 acl inet_stream_bind\n"
574+ "0 allow ip!=127.0.0.1 port=0\n"
575+ "1 deny\n";
576+ set(policy);
577+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
578+ EOF);
579+ unset(policy);
580+
581+ policy = "100 acl inet_stream_bind\n"
582+ "0 allow ip=127.0.0.1 port=0 path.uid=task.uid\n"
583+ "1 deny\n";
584+ set(policy);
585+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
586+ EOF);
587+ unset(policy);
588+
589+ policy = "100 acl inet_stream_bind\n"
590+ "0 allow ip=127.0.0.1 port=0\n"
591+ "1 deny\n";
592+ set(policy);
593+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
594+ 0);
595+ unset(policy);
596+
597+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
598+
599+ snprintf(buffer, sizeof(buffer) - 1,
600+ "100 acl inet_stream_listen\n"
601+ "0 allow ip=127.0.0.1 port!=%u\n"
602+ "1 deny\n", ntohs(addr1.sin_port));
603+ policy = buffer;
604+ set(policy);
605+ check(policy, listen(fd1, 5) == EOF);
606+ unset(policy);
607+
608+ snprintf(buffer, sizeof(buffer) - 1,
609+ "100 acl inet_stream_listen\n"
610+ "0 allow ip=127.0.0.1 port=%u\n"
611+ "1 deny\n", ntohs(addr1.sin_port));
612+ policy = buffer;
613+ set(policy);
614+ check(policy, listen(fd1, 5) == 0);
615+ unset(policy);
616+
617+ snprintf(buffer, sizeof(buffer) - 1,
618+ "100 acl inet_stream_connect\n"
619+ "0 allow ip=127.0.0.1 port!=%u\n"
620+ "1 deny\n", ntohs(addr1.sin_port));
621+ policy = buffer;
622+ set(policy);
623+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
624+ == EOF);
625+ unset(policy);
626+
627+ snprintf(buffer, sizeof(buffer) - 1,
628+ "100 acl inet_stream_connect\n"
629+ "0 allow ip=127.0.0.1 port=%u\n"
630+ "1 deny\n", ntohs(addr1.sin_port));
631+ policy = buffer;
632+ set(policy);
633+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
634+ == 0);
635+ unset(policy);
636+
637+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
638+
639+ snprintf(buffer, sizeof(buffer) - 1,
640+ "100 acl inet_stream_accept\n"
641+ "0 allow ip=127.0.0.1 port=%u\n"
642+ "1 deny\n", ntohs(addr2.sin_port));
643+ policy = buffer;
644+ set(policy);
645+ fd3 = accept(fd1, NULL, 0);
646+ check(policy, fd3 != EOF);
647+ close(fd3);
648+ unset(policy);
649+
650+ snprintf(buffer, sizeof(buffer) - 1,
651+ "100 acl inet_stream_connect\n"
652+ "0 allow ip=127.0.0.1 port=%u\n"
653+ "1 deny\n", ntohs(addr1.sin_port));
654+ policy = buffer;
655+ set(policy);
656+ close(fd2);
657+ fd2 = socket(PF_INET, SOCK_STREAM, 0);
658+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
659+ == 0);
660+ unset(policy);
661+
662+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
663+
664+ snprintf(buffer, sizeof(buffer) - 1,
665+ "100 acl inet_stream_accept\n"
666+ "0 allow ip=127.0.0.1 port!=%u\n"
667+ "1 deny\n", ntohs(addr2.sin_port));
668+ policy = buffer;
669+ set(policy);
670+ fd3 = accept(fd1, NULL, 0);
671+ check(policy, fd3 == EOF);
672+ close(fd3);
673+ unset(policy);
674+
675+ close(fd1);
676+ close(fd2);
677+}
678+
679+static void test_network_inet_dgram(void)
680+{
681+ struct sockaddr_in addr1 = { };
682+ struct sockaddr_in addr2 = { };
683+ socklen_t size = sizeof(addr1);
684+ int fd1;
685+ int fd2;
686+ char c;
687+ char *policy;
688+ char buffer[1024];
689+ memset(buffer, 0, sizeof(buffer));
690+
691+ fd1 = socket(PF_INET, SOCK_DGRAM, 0);
692+ fd2 = socket(PF_INET, SOCK_DGRAM, 0);
693+ addr1.sin_family = AF_INET;
694+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
695+
696+ policy = "100 acl inet_dgram_bind\n"
697+ "0 allow ip=127.0.0.1 port!=0\n"
698+ "1 deny\n";
699+ set(policy);
700+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
701+ EOF);
702+ unset(policy);
703+
704+ policy = "100 acl inet_dgram_bind\n"
705+ "0 allow ip!=127.0.0.1 port=0\n"
706+ "1 deny\n";
707+ set(policy);
708+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
709+ EOF);
710+ unset(policy);
711+
712+ policy = "100 acl inet_dgram_bind\n"
713+ "0 allow ip=127.0.0.1 port=0 path.uid=task.uid\n"
714+ "1 deny\n";
715+ set(policy);
716+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
717+ EOF);
718+ unset(policy);
719+
720+ policy = "100 acl inet_dgram_bind\n"
721+ "0 allow ip=127.0.0.1 port=0\n"
722+ "1 deny\n";
723+ set(policy);
724+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
725+ 0);
726+ unset(policy);
727+
728+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
729+
730+ snprintf(buffer, sizeof(buffer) - 1,
731+ "100 acl inet_dgram_send\n"
732+ "0 allow ip=127.0.0.1 port!=%u\n"
733+ "1 deny\n", ntohs(addr1.sin_port));
734+ policy = buffer;
735+ set(policy);
736+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
737+ == EOF);
738+ unset(policy);
739+
740+ snprintf(buffer, sizeof(buffer) - 1,
741+ "100 acl inet_dgram_send\n"
742+ "0 allow ip=127.0.0.1 port=%u\n"
743+ "1 deny\n", ntohs(addr1.sin_port));
744+ policy = buffer;
745+ set(policy);
746+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
747+ == 0);
748+ unset(policy);
749+
750+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
751+
752+ snprintf(buffer, sizeof(buffer) - 1,
753+ "100 acl inet_dgram_send\n"
754+ "0 allow ip=127.0.0.1 port=%u\n"
755+ "1 deny\n", ntohs(addr1.sin_port));
756+ policy = buffer;
757+ set(policy);
758+ check(policy, send(fd2, "", 1, 0) != EOF);
759+ unset(policy);
760+
761+ snprintf(buffer, sizeof(buffer) - 1,
762+ "100 acl inet_dgram_recv\n"
763+ "0 allow ip=127.0.0.1 port=%u\n"
764+ "1 deny\n", ntohs(addr2.sin_port));
765+ policy = buffer;
766+ set(policy);
767+ check(policy, recv(fd1, &c, 1, 0) != EOF);
768+ unset(policy);
769+
770+ snprintf(buffer, sizeof(buffer) - 1,
771+ "100 acl inet_dgram_send\n"
772+ "0 allow ip=127.0.0.1 port=%u\n"
773+ "1 deny\n", ntohs(addr1.sin_port));
774+ policy = buffer;
775+ set(policy);
776+ check(policy, send(fd2, "", 1, 0) != EOF);
777+ unset(policy);
778+
779+ snprintf(buffer, sizeof(buffer) - 1,
780+ "100 acl inet_dgram_recv\n"
781+ "0 allow ip=127.0.0.1 port!=%u\n"
782+ "1 deny\n", ntohs(addr2.sin_port));
783+ policy = buffer;
784+ set(policy);
785+ check(policy, recv(fd1, &c, 1, 0) == EOF);
786+ unset(policy);
787+
788+ snprintf(buffer, sizeof(buffer) - 1,
789+ "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
790+ "100 acl inet_dgram_send\n"
791+ "0 allow ip=@LOCALHOST port=%u\n"
792+ "1 deny\n", ntohs(addr1.sin_port));
793+ policy = buffer;
794+ set(policy);
795+ check(policy, send(fd2, "", 1, 0) != EOF);
796+ unset2(policy);
797+
798+ snprintf(buffer, sizeof(buffer) - 1,
799+ "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
800+ "100 acl inet_dgram_recv\n"
801+ "0 allow ip!=@LOCALHOST port=%u\n"
802+ "1 deny\n", ntohs(addr2.sin_port));
803+ policy = buffer;
804+ set(policy);
805+ check(policy, recv(fd1, &c, 1, 0) == EOF);
806+ unset2(policy);
807+
808+ close(fd1);
809+ close(fd2);
810+}
811+
812+static void test_network_inet_raw(void)
813+{
814+ struct sockaddr_in addr = { };
815+ static struct iphdr ip = { };
816+ int fd1;
817+ int fd2;
818+ char *policy;
819+ fd1 = socket(PF_INET, SOCK_RAW, 1);
820+ fd2 = socket(PF_INET, SOCK_RAW, 1);
821+ addr.sin_family = AF_INET;
822+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
823+ ip.version = 4;
824+ ip.ihl = sizeof(struct iphdr) / 4;
825+ ip.protocol = IPPROTO_RAW;
826+ ip.daddr = htonl(INADDR_LOOPBACK);
827+ ip.saddr = ip.daddr;
828+
829+ policy = "100 acl inet_raw_bind\n"
830+ "0 allow ip=127.0.0.1 proto!=1\n"
831+ "1 deny\n";
832+ set(policy);
833+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
834+ EOF);
835+ unset(policy);
836+
837+ policy = "100 acl inet_raw_bind\n"
838+ "0 allow ip!=127.0.0.1 proto=1\n"
839+ "1 deny\n";
840+ set(policy);
841+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
842+ EOF);
843+ unset(policy);
844+
845+ policy = "100 acl inet_raw_bind\n"
846+ "0 allow ip=127.0.0.1 proto=1 path.uid=task.uid\n"
847+ "1 deny\n";
848+ set(policy);
849+ check(policy, bind(fd1, (struct sockaddr *) &addr, sizeof(addr)) ==
850+ EOF);
851+ unset(policy);
852+
853+ policy = "100 acl inet_raw_bind\n"
854+ "0 allow ip=127.0.0.1 proto=1\n"
855+ "1 deny\n";
856+ set(policy);
857+ check(policy, bind(fd2, (struct sockaddr *) &addr, sizeof(addr)) ==
858+ 0);
859+ unset(policy);
860+
861+ policy = "100 acl inet_raw_send\n"
862+ "0 allow ip=127.0.0.1 proto!=1\n"
863+ "1 deny\n";
864+ set(policy);
865+ check(policy, connect(fd2, (struct sockaddr *) &addr, sizeof(addr))
866+ == EOF);
867+ unset(policy);
868+
869+ policy = "100 acl inet_raw_send\n"
870+ "0 allow ip=127.0.0.1 proto=1\n"
871+ "1 deny\n";
872+ set(policy);
873+ check(policy, connect(fd2, (struct sockaddr *) &addr, sizeof(addr))
874+ == 0);
875+ unset(policy);
876+
877+ policy = "100 acl inet_raw_send\n"
878+ "0 allow ip=127.0.0.1 proto=1\n"
879+ "1 deny\n";
880+ set(policy);
881+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
882+ unset(policy);
883+
884+ policy = "100 acl inet_raw_recv\n"
885+ "0 allow ip=127.0.0.1 proto=1\n"
886+ "1 deny\n";
887+ set(policy);
888+ check(policy, recv(fd1, &ip, sizeof(ip), MSG_DONTWAIT) != EOF);
889+ unset(policy);
890+
891+ policy = "100 acl inet_raw_send\n"
892+ "0 allow ip=127.0.0.1 proto=1\n"
893+ "1 deny\n";
894+ set(policy);
895+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
896+ unset(policy);
897+
898+ policy = "100 acl inet_raw_recv\n"
899+ "0 allow ip=127.0.0.1 proto!=1\n"
900+ "1 deny\n";
901+ set(policy);
902+ check(policy, recv(fd1, &ip, sizeof(ip), MSG_DONTWAIT) == EOF);
903+ unset(policy);
904+
905+ policy = "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
906+ "100 acl inet_raw_send\n"
907+ "0 allow ip=@LOCALHOST proto=1\n"
908+ "1 deny\n";
909+ set(policy);
910+ check(policy, send(fd2, &ip, sizeof(ip), 0) != EOF);
911+ unset2(policy);
912+
913+ policy = "ip_group LOCALHOST 127.0.0.0-127.255.255.255\n"
914+ "100 acl inet_raw_recv\n"
915+ "0 allow ip!=@LOCALHOST proto=1\n"
916+ "1 deny\n";
917+ set(policy);
918+ check(policy, recv(fd1, &ip, sizeof(ip), MSG_DONTWAIT) == EOF);
919+ unset2(policy);
920+
921+ close(fd1);
922+ close(fd2);
923+}
924+
925+static void test_network_inet6_stream(void)
926+{
927+ struct sockaddr_in6 addr1 = { };
928+ struct sockaddr_in6 addr2 = { };
929+ socklen_t size = sizeof(addr1);
930+ int fd1;
931+ int fd2;
932+ int fd3;
933+ char *policy;
934+ char buffer[1024];
935+ memset(buffer, 0, sizeof(buffer));
936+
937+ fd1 = socket(PF_INET6, SOCK_STREAM, 0);
938+ fd2 = socket(PF_INET6, SOCK_STREAM, 0);
939+ addr1.sin6_family = AF_INET6;
940+ addr1.sin6_addr = in6addr_loopback;
941+
942+ policy = "100 acl inet_stream_bind\n"
943+ "0 allow ip=::1 port!=0\n"
944+ "1 deny\n";
945+ set(policy);
946+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
947+ EOF);
948+ unset(policy);
949+
950+ policy = "100 acl inet_stream_bind\n"
951+ "0 allow ip!=::1 port=0\n"
952+ "1 deny\n";
953+ set(policy);
954+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
955+ EOF);
956+ unset(policy);
957+
958+ policy = "100 acl inet_stream_bind\n"
959+ "0 allow ip=::1 port=0 path.uid=task.uid\n"
960+ "1 deny\n";
961+ set(policy);
962+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
963+ EOF);
964+ unset(policy);
965+
966+ policy = "100 acl inet_stream_bind\n"
967+ "0 allow ip=::1 port=0\n"
968+ "1 deny\n";
969+ set(policy);
970+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
971+ 0);
972+ unset(policy);
973+
974+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
975+
976+ snprintf(buffer, sizeof(buffer) - 1,
977+ "100 acl inet_stream_listen\n"
978+ "0 allow ip=::1 port!=%u\n"
979+ "1 deny\n", ntohs(addr1.sin6_port));
980+ policy = buffer;
981+ set(policy);
982+ check(policy, listen(fd1, 5) == EOF);
983+ unset(policy);
984+
985+ snprintf(buffer, sizeof(buffer) - 1,
986+ "100 acl inet_stream_listen\n"
987+ "0 allow ip=::1 port=%u\n"
988+ "1 deny\n", ntohs(addr1.sin6_port));
989+ policy = buffer;
990+ set(policy);
991+ check(policy, listen(fd1, 5) == 0);
992+ unset(policy);
993+
994+ snprintf(buffer, sizeof(buffer) - 1,
995+ "100 acl inet_stream_connect\n"
996+ "0 allow ip=::1 port!=%u\n"
997+ "1 deny\n", ntohs(addr1.sin6_port));
998+ policy = buffer;
999+ set(policy);
1000+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1001+ == EOF);
1002+ unset(policy);
1003+
1004+ snprintf(buffer, sizeof(buffer) - 1,
1005+ "100 acl inet_stream_connect\n"
1006+ "0 allow ip=::1 port=%u\n"
1007+ "1 deny\n", ntohs(addr1.sin6_port));
1008+ policy = buffer;
1009+ set(policy);
1010+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1011+ == 0);
1012+ unset(policy);
1013+
1014+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1015+
1016+ snprintf(buffer, sizeof(buffer) - 1,
1017+ "100 acl inet_stream_accept\n"
1018+ "0 allow ip=::1 port=%u\n"
1019+ "1 deny\n", ntohs(addr2.sin6_port));
1020+ policy = buffer;
1021+ set(policy);
1022+ fd3 = accept(fd1, NULL, 0);
1023+ check(policy, fd3 != EOF);
1024+ close(fd3);
1025+ unset(policy);
1026+
1027+ snprintf(buffer, sizeof(buffer) - 1,
1028+ "100 acl inet_stream_connect\n"
1029+ "0 allow ip=::1 port=%u\n"
1030+ "1 deny\n", ntohs(addr1.sin6_port));
1031+ policy = buffer;
1032+ set(policy);
1033+ close(fd2);
1034+ fd2 = socket(PF_INET6, SOCK_STREAM, 0);
1035+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1036+ == 0);
1037+ unset(policy);
1038+
1039+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1040+
1041+ snprintf(buffer, sizeof(buffer) - 1,
1042+ "100 acl inet_stream_accept\n"
1043+ "0 allow ip=::1 port!=%u\n"
1044+ "1 deny\n", ntohs(addr2.sin6_port));
1045+ policy = buffer;
1046+ set(policy);
1047+ fd3 = accept(fd1, NULL, 0);
1048+ check(policy, fd3 == EOF);
1049+ close(fd3);
1050+ unset(policy);
1051+
1052+ close(fd1);
1053+ close(fd2);
1054+}
1055+
1056+static void test_network_inet6_dgram(void)
1057+{
1058+ struct sockaddr_in6 addr1 = { };
1059+ struct sockaddr_in6 addr2 = { };
1060+ socklen_t size = sizeof(addr1);
1061+ int fd1;
1062+ int fd2;
1063+ char c;
1064+ char *policy;
1065+ char buffer[1024];
1066+ memset(buffer, 0, sizeof(buffer));
1067+
1068+ fd1 = socket(PF_INET6, SOCK_DGRAM, 0);
1069+ fd2 = socket(PF_INET6, SOCK_DGRAM, 0);
1070+ addr1.sin6_family = AF_INET6;
1071+ addr1.sin6_addr = in6addr_loopback;
1072+
1073+ policy = "100 acl inet_dgram_bind\n"
1074+ "0 allow ip=::1 port!=0\n"
1075+ "1 deny\n";
1076+ set(policy);
1077+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1078+ EOF);
1079+ unset(policy);
1080+
1081+ policy = "100 acl inet_dgram_bind\n"
1082+ "0 allow ip!=::1 port=0\n"
1083+ "1 deny\n";
1084+ set(policy);
1085+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1086+ EOF);
1087+ unset(policy);
1088+
1089+ policy = "100 acl inet_dgram_bind\n"
1090+ "0 allow ip=::1 port=0 path.uid=task.uid\n"
1091+ "1 deny\n";
1092+ set(policy);
1093+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1094+ EOF);
1095+ unset(policy);
1096+
1097+ policy = "100 acl inet_dgram_bind\n"
1098+ "0 allow ip=::1 port=0\n"
1099+ "1 deny\n";
1100+ set(policy);
1101+ check(policy, bind(fd1, (struct sockaddr *) &addr1, sizeof(addr1)) ==
1102+ 0);
1103+ unset(policy);
1104+
1105+ getsockname(fd1, (struct sockaddr *) &addr1, &size);
1106+
1107+ snprintf(buffer, sizeof(buffer) - 1,
1108+ "100 acl inet_dgram_send\n"
1109+ "0 allow ip=::1 port!=%u\n"
1110+ "1 deny\n", ntohs(addr1.sin6_port));
1111+ policy = buffer;
1112+ set(policy);
1113+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1114+ == EOF);
1115+ unset(policy);
1116+
1117+ snprintf(buffer, sizeof(buffer) - 1,
1118+ "100 acl inet_dgram_send\n"
1119+ "0 allow ip=::1 port=%u\n"
1120+ "1 deny\n", ntohs(addr1.sin6_port));
1121+ policy = buffer;
1122+ set(policy);
1123+ check(policy, connect(fd2, (struct sockaddr *) &addr1, sizeof(addr1))
1124+ == 0);
1125+ unset(policy);
1126+
1127+ getsockname(fd2, (struct sockaddr *) &addr2, &size);
1128+
1129+ snprintf(buffer, sizeof(buffer) - 1,
1130+ "100 acl inet_dgram_send\n"
1131+ "0 allow ip=::1 port=%u\n"
1132+ "1 deny\n", ntohs(addr1.sin6_port));
1133+ policy = buffer;
1134+ set(policy);
1135+ check(policy, send(fd2, "", 1, 0) != EOF);
1136+ unset(policy);
1137+
1138+ snprintf(buffer, sizeof(buffer) - 1,
1139+ "100 acl inet_dgram_recv\n"
1140+ "0 allow ip=::1 port=%u\n"
1141+ "1 deny\n", ntohs(addr2.sin6_port));
1142+ policy = buffer;
1143+ set(policy);
1144+ check(policy, recv(fd1, &c, 1, 0) != EOF);
1145+ unset(policy);
1146+
1147+ snprintf(buffer, sizeof(buffer) - 1,
1148+ "100 acl inet_dgram_send\n"
1149+ "0 allow ip=::1 port=%u\n"
1150+ "1 deny\n", ntohs(addr1.sin6_port));
1151+ policy = buffer;
1152+ set(policy);
1153+ check(policy, send(fd2, "", 1, 0) != EOF);
1154+ unset(policy);
1155+
1156+ snprintf(buffer, sizeof(buffer) - 1,
1157+ "100 acl inet_dgram_recv\n"
1158+ "0 allow ip=::1 port!=%u\n"
1159+ "1 deny\n", ntohs(addr2.sin6_port));
1160+ policy = buffer;
1161+ set(policy);
1162+ check(policy, recv(fd1, &c, 1, 0) == EOF);
1163+ unset(policy);
1164+
1165+ snprintf(buffer, sizeof(buffer) - 1,
1166+ "ip_group LOCALHOST ::-::ffff\n"
1167+ "100 acl inet_dgram_send\n"
1168+ "0 allow ip=@LOCALHOST port=%u\n"
1169+ "1 deny\n", ntohs(addr1.sin6_port));
1170+ policy = buffer;
1171+ set(policy);
1172+ check(policy, send(fd2, "", 1, 0) != EOF);
1173+ unset2(policy);
1174+
1175+ snprintf(buffer, sizeof(buffer) - 1,
1176+ "ip_group LOCALHOST ::-::ffff\n"
1177+ "100 acl inet_dgram_recv\n"
1178+ "0 allow ip!=@LOCALHOST port=%u\n"
1179+ "1 deny\n", ntohs(addr2.sin6_port));
1180+ policy = buffer;
1181+ set(policy);
1182+ check(policy, recv(fd1, &c, 1, 0) == EOF);
1183+ unset2(policy);
1184+
1185+ close(fd1);
1186+ close(fd2);
1187+}
1188+
1189+static void test_capability(void)
1190+{
1191+ char *policy;
1192+
1193+ policy = "100 acl set_priority\n"
1194+ "0 allow task.uid=0\n"
1195+ "1 deny\n";
1196+ set(policy);
1197+ check(policy, nice(0) == 0);
1198+ unset(policy);
1199+
1200+ policy = "100 acl set_priority\n"
1201+ "0 allow task.uid=task.gid task.type!=execute_handler\n"
1202+ "1 deny\n";
1203+ set(policy);
1204+ check(policy, nice(0) == 0);
1205+ unset(policy);
1206+
1207+ policy = "100 acl set_priority\n"
1208+ "0 deny task.uid=0\n"
1209+ "1 allow\n";
1210+ set(policy);
1211+ check(policy, nice(0) == EOF);
1212+ unset(policy);
1213+
1214+ policy = "100 acl set_priority\n"
1215+ "0 allow task.uid=task.gid task.type=execute_handler\n"
1216+ "1 deny\n";
1217+ set(policy);
1218+ check(policy, nice(0) == EOF);
1219+ unset(policy);
1220+}
1221+
1222+static void detach_init(void)
1223+{
1224+ ptrace(PTRACE_DETACH, 1, NULL, NULL);
1225+ kill(1, SIGCONT);
1226+ sleep(1);
1227+}
1228+
1229+static void test_ptrace(void)
1230+{
1231+ char *policy;
1232+
1233+ policy = "100 acl ptrace\n"
1234+ "0 allow cmd=1 domain!=\"foo\"\n"
1235+ "0 allow cmd=17\n"
1236+ "1 deny\n";
1237+ set(policy);
1238+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == EOF);
1239+ unset(policy);
1240+ detach_init();
1241+
1242+ policy = "100 acl ptrace\n"
1243+ "0 allow cmd=16 domain=\"foo\"\n"
1244+ "0 allow cmd=17\n"
1245+ "1 deny\n";
1246+ set(policy);
1247+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == EOF);
1248+ unset(policy);
1249+ detach_init();
1250+
1251+ policy = "100 acl ptrace\n"
1252+ "0 allow cmd=16 domain!=\"foo\"\n"
1253+ "0 allow cmd=17\n"
1254+ "1 deny\n";
1255+ set(policy);
1256+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == 0);
1257+ unset(policy);
1258+ detach_init();
1259+
1260+ policy = "string_group DOMAINS <init>\n"
1261+ "100 acl ptrace\n"
1262+ "0 allow cmd=16 domain=@DOMAINS\n"
1263+ "0 allow cmd=17\n"
1264+ "1 deny\n";
1265+ set(policy);
1266+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == 0);
1267+ unset2(policy);
1268+ detach_init();
1269+
1270+ policy = "string_group DOMAINS <init>\n"
1271+ "100 acl ptrace\n"
1272+ "0 allow cmd=16 domain!=@DOMAINS\n"
1273+ "0 allow cmd=17\n"
1274+ "1 deny\n";
1275+ set(policy);
1276+ check(policy, ptrace(PTRACE_ATTACH, 1, NULL, NULL) == EOF);
1277+ unset2(policy);
1278+ detach_init();
1279+}
1280+
1281+static void test_signal(void)
1282+{
1283+ char *policy;
1284+
1285+ policy = "100 acl signal task.domain=\"domain200\"\n"
1286+ "0 allow sig=1 task.uid=0\n"
1287+ "1 deny\n";
1288+ set(policy);
1289+ check(policy, kill(1, 1) == 0);
1290+ unset(policy);
1291+
1292+ policy = "100 acl signal task.domain=\"domain200\"\n"
1293+ "0 allow sig!=1 task.uid=0\n"
1294+ "1 deny\n";
1295+ set(policy);
1296+ check(policy, kill(1, 1) == EOF);
1297+ unset(policy);
1298+
1299+ policy = "100 acl signal\n"
1300+ "0 allow task.domain!=\"domain200\"\n"
1301+ "0 allow sig=1\n"
1302+ "1 deny\n";
1303+ set(policy);
1304+ check(policy, kill(1, 1) == 0);
1305+ unset(policy);
1306+
1307+ policy = "100 acl signal\n"
1308+ "0 deny task.domain=\"domain200\"\n"
1309+ "0 allow\n";
1310+ set(policy);
1311+ check(policy, kill(1, 1) == EOF);
1312+ unset(policy);
1313+
1314+ policy = "100 acl signal\n"
1315+ "0 deny sig=1 task.domain=\"domain200\"\n"
1316+ "0 allow\n";
1317+ set(policy);
1318+ check(policy, kill(1, 1) == EOF);
1319+ unset(policy);
1320+}
1321+
1322+static int fork_exec(char *envp[])
1323+{
1324+ int ret_ignored;
1325+ int pipe_fd[2] = { EOF, EOF };
1326+ int err = 0;
1327+ pid_t pid;
1328+ if (pipe(pipe_fd)) {
1329+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
1330+ exit(1);
1331+ }
1332+ pid = fork();
1333+ if (pid == 0) {
1334+ char *argv[2] = { "/bin/true", NULL };
1335+ execve("/bin/true", argv, envp);
1336+ err = errno;
1337+ ret_ignored = write(pipe_fd[1], &err, sizeof(err));
1338+ _exit(0);
1339+ }
1340+ close(pipe_fd[1]);
1341+ ret_ignored = read(pipe_fd[0], &err, sizeof(err));
1342+ close(pipe_fd[0]);
1343+ wait(NULL);
1344+ errno = err;
1345+ return err ? EOF : 0;
1346+}
1347+
1348+static void test_environ(void)
1349+{
1350+ char *policy;
1351+ char *envp[2];
1352+ envp[1] = NULL;
1353+
1354+ policy = "100 acl environ name=\"PATH2\"\n"
1355+ "0 allow value=\"/\"\n"
1356+ "1 deny\n";
1357+ set(policy);
1358+ envp[0] = "PATH2=/";
1359+ check(policy, fork_exec(envp) == 0);
1360+ unset(policy);
1361+
1362+ policy = "100 acl environ name=\"PATH2\"\n"
1363+ "0 allow value!=\"/\"\n"
1364+ "1 deny\n";
1365+ set(policy);
1366+ envp[0] = "PATH2=/";
1367+ check(policy, fork_exec(envp) == EOF);
1368+ unset(policy);
1369+
1370+ policy = "100 acl environ name=\"PATH2\"\n"
1371+ "0 deny value!=\"/\"\n"
1372+ "1 allow\n";
1373+ set(policy);
1374+ envp[0] = "PATH2=/";
1375+ check(policy, fork_exec(envp) == 0);
1376+ unset(policy);
1377+
1378+ policy = "100 acl environ name=\"PATH2\"\n"
1379+ "0 deny value=\"/\"\n"
1380+ "1 allow\n";
1381+ set(policy);
1382+ envp[0] = "PATH2=/";
1383+ check(policy, fork_exec(envp) == EOF);
1384+ unset(policy);
1385+
1386+ policy = "100 acl execute path=\"/bin/true\"\n"
1387+ "0 allow envp[\"PATH2\"]=\"/\"\n"
1388+ "1 deny\n";
1389+ set(policy);
1390+ envp[0] = "PATH2=/";
1391+ check(policy, fork_exec(envp) == 0);
1392+ unset(policy);
1393+
1394+ policy = "100 acl execute path=\"/bin/true\"\n"
1395+ "0 allow envp[\"PATH2\"]!=\"/\"\n"
1396+ "1 deny\n";
1397+ set(policy);
1398+ envp[0] = "PATH2=/";
1399+ check(policy, fork_exec(envp) == EOF);
1400+ unset(policy);
1401+
1402+ policy = "100 acl execute path=\"/bin/true\"\n"
1403+ "0 allow envp[\"PATH2\"]!=NULL\n"
1404+ "1 deny\n";
1405+ set(policy);
1406+ envp[0] = "PATH2";
1407+ check(policy, fork_exec(envp) == 0);
1408+ unset(policy);
1409+
1410+ policy = "100 acl execute path=\"/bin/true\"\n"
1411+ "0 allow envp[\"PATH2\"]!=NULL\n"
1412+ "1 deny\n";
1413+ set(policy);
1414+ envp[0] = "PATH2=";
1415+ check(policy, fork_exec(envp) == 0);
1416+ unset(policy);
1417+
1418+ policy = "100 acl execute path=\"/bin/true\"\n"
1419+ "0 allow envp[\"PATH2\"]!=NULL\n"
1420+ "1 deny\n";
1421+ set(policy);
1422+ envp[0] = "PATH2=/";
1423+ check(policy, fork_exec(envp) == 0);
1424+ unset(policy);
1425+
1426+ policy = "100 acl execute path=\"/bin/true\"\n"
1427+ "0 allow envp[\"PATH2\"]=NULL\n"
1428+ "1 deny\n";
1429+ set(policy);
1430+ envp[0] = "PATH2";
1431+ check(policy, fork_exec(envp) == EOF);
1432+ unset(policy);
1433+
1434+ policy = "100 acl execute path=\"/bin/true\"\n"
1435+ "0 allow envp[\"PATH2\"]=NULL\n"
1436+ "1 deny\n";
1437+ set(policy);
1438+ envp[0] = "PATH2=";
1439+ check(policy, fork_exec(envp) == EOF);
1440+ unset(policy);
1441+
1442+ policy = "100 acl execute path=\"/bin/true\"\n"
1443+ "0 allow envp[\"PATH2\"]=NULL\n"
1444+ "1 deny\n";
1445+ set(policy);
1446+ envp[0] = "PATH2=/";
1447+ check(policy, fork_exec(envp) == EOF);
1448+ unset(policy);
1449+
1450+ policy = "100 acl execute path=\"/bin/true\"\n"
1451+ "0 allow envp[\"\"]=NULL\n"
1452+ "1 deny\n";
1453+ set(policy);
1454+ envp[0] = "";
1455+ check(policy, fork_exec(envp) == EOF);
1456+ unset(policy);
1457+
1458+ policy = "100 acl execute path=\"/bin/true\"\n"
1459+ "0 allow envp[\"\"]!=NULL\n"
1460+ "1 deny\n";
1461+ set(policy);
1462+ envp[0] = "";
1463+ check(policy, fork_exec(envp) == 0);
1464+ unset(policy);
1465+
1466+ policy = "100 acl execute path=\"/bin/true\"\n"
1467+ "0 allow envp[\"\"]!=NULL\n"
1468+ "1 deny\n";
1469+ set(policy);
1470+ envp[0] = "=";
1471+ check(policy, fork_exec(envp) == 0);
1472+ unset(policy);
1473+
1474+ policy = "100 acl execute path=\"/bin/true\"\n"
1475+ "0 allow envp[\"\"]!=NULL\n"
1476+ "1 deny\n";
1477+ set(policy);
1478+ envp[0] = "=/";
1479+ check(policy, fork_exec(envp) == 0);
1480+ unset(policy);
1481+}
1482+
1483+static int fork_exec2(char *argv[], char *envp[])
1484+{
1485+ int ret_ignored;
1486+ int pipe_fd[2] = { EOF, EOF };
1487+ int err = 0;
1488+ pid_t pid;
1489+ if (pipe(pipe_fd)) {
1490+ fprintf(stderr, "Err: %s(%d)\n", strerror(err), err);
1491+ exit(1);
1492+ }
1493+ pid = fork();
1494+ if (pid == 0) {
1495+ execve("/bin/true", argv, envp);
1496+ err = errno;
1497+ ret_ignored = write(pipe_fd[1], &err, sizeof(err));
1498+ _exit(0);
1499+ }
1500+ close(pipe_fd[1]);
1501+ ret_ignored = read(pipe_fd[0], &err, sizeof(err));
1502+ close(pipe_fd[0]);
1503+ wait(NULL);
1504+ errno = err;
1505+ return err ? EOF : 0;
1506+}
1507+
1508+static void test_file_execute(void)
1509+{
1510+ char *policy;
1511+ char *argv[5];
1512+ char *envp[5];
1513+ memset(argv, 0, sizeof(argv));
1514+ memset(envp, 0, sizeof(envp));
1515+
1516+ policy = "100 acl execute path=\"/bin/true\"\n"
1517+ "0 allow argc=1\n"
1518+ "1 deny\n";
1519+ set(policy);
1520+ argv[0]="true";
1521+ check(policy, fork_exec2(argv, envp) == 0);
1522+ unset(policy);
1523+
1524+ policy = "100 acl execute path=\"/bin/true\"\n"
1525+ "0 allow argc!=1\n"
1526+ "1 deny\n";
1527+ set(policy);
1528+ check(policy, fork_exec2(argv, envp) == EOF);
1529+ unset(policy);
1530+
1531+ policy = "100 acl execute path=\"/bin/true\"\n"
1532+ "0 deny argc!=1\n"
1533+ "1 allow\n";
1534+ set(policy);
1535+ check(policy, fork_exec2(argv, envp) == 0);
1536+ unset(policy);
1537+
1538+ policy = "100 acl execute path=\"/bin/true\"\n"
1539+ "0 deny argc=1\n"
1540+ "1 allow\n";
1541+ set(policy);
1542+ check(policy, fork_exec2(argv, envp) == EOF);
1543+ unset(policy);
1544+
1545+ policy = "100 acl execute path=\"/bin/true\"\n"
1546+ "0 deny argv[0]!=\"true\"\n"
1547+ "1 allow\n";
1548+ set(policy);
1549+ check(policy, fork_exec2(argv, envp) == 0);
1550+ unset(policy);
1551+
1552+ policy = "100 acl execute path=\"/bin/true\"\n"
1553+ "0 deny argv[0]=\"true\"\n"
1554+ "1 allow\n";
1555+ set(policy);
1556+ check(policy, fork_exec2(argv, envp) == EOF);
1557+ unset(policy);
1558+
1559+ policy = "100 acl execute path=\"/bin/true\"\n"
1560+ "0 allow argv[0]!=\"true\"\n"
1561+ "1 deny\n";
1562+ set(policy);
1563+ check(policy, fork_exec2(argv, envp) == EOF);
1564+ unset(policy);
1565+
1566+ policy = "100 acl execute path=\"/bin/true\"\n"
1567+ "0 allow argv[0]=\"true\"\n"
1568+ "1 deny\n";
1569+ set(policy);
1570+ check(policy, fork_exec2(argv, envp) == 0);
1571+ unset(policy);
1572+
1573+ policy = "string_group EXEC_ARGV0 false\n"
1574+ "string_group EXEC_ARGV0 true\n"
1575+ "100 acl execute path=\"/bin/true\"\n"
1576+ "0 deny argv[0]!=@EXEC_ARGV0\n"
1577+ "1 allow\n";
1578+ set(policy);
1579+ check(policy, fork_exec2(argv, envp) == 0);
1580+ unset2(policy);
1581+
1582+ policy = "string_group EXEC_ARGV0 false\n"
1583+ "string_group EXEC_ARGV0 true\n"
1584+ "100 acl execute path=\"/bin/true\"\n"
1585+ "0 deny argv[0]=@EXEC_ARGV0\n"
1586+ "1 allow\n";
1587+ set(policy);
1588+ check(policy, fork_exec2(argv, envp) == EOF);
1589+ unset2(policy);
1590+
1591+ policy = "string_group EXEC_ARGV0 false\n"
1592+ "string_group EXEC_ARGV0 true\n"
1593+ "100 acl execute path=\"/bin/true\"\n"
1594+ "0 allow argv[0]!=@EXEC_ARGV0\n"
1595+ "1 deny\n";
1596+ set(policy);
1597+ check(policy, fork_exec2(argv, envp) == EOF);
1598+ unset2(policy);
1599+
1600+ policy = "string_group EXEC_ARGV0 false\n"
1601+ "string_group EXEC_ARGV0 true\n"
1602+ "100 acl execute path=\"/bin/true\"\n"
1603+ "0 allow argv[0]=@EXEC_ARGV0\n"
1604+ "1 deny\n";
1605+ set(policy);
1606+ check(policy, fork_exec2(argv, envp) == 0);
1607+ unset2(policy);
1608+
1609+
1610+ policy = "100 acl execute path=\"/bin/true\"\n"
1611+ "0 allow envc=1\n"
1612+ "1 deny\n";
1613+ set(policy);
1614+ envp[0]="PATH=/";
1615+ check(policy, fork_exec2(argv, envp) == 0);
1616+ unset(policy);
1617+
1618+ policy = "100 acl execute path=\"/bin/true\"\n"
1619+ "0 allow envc!=1\n"
1620+ "1 deny\n";
1621+ set(policy);
1622+ check(policy, fork_exec2(argv, envp) == EOF);
1623+ unset(policy);
1624+
1625+ policy = "100 acl execute path=\"/bin/true\"\n"
1626+ "0 deny envc!=1\n"
1627+ "1 allow\n";
1628+ set(policy);
1629+ check(policy, fork_exec2(argv, envp) == 0);
1630+ unset(policy);
1631+
1632+ policy = "100 acl execute path=\"/bin/true\"\n"
1633+ "0 deny envc=1\n"
1634+ "1 allow\n";
1635+ set(policy);
1636+ check(policy, fork_exec2(argv, envp) == EOF);
1637+ unset(policy);
1638+
1639+ policy = "100 acl execute path=\"/bin/true\"\n"
1640+ "0 deny envp[\"PATH\"]!=\"/\"\n"
1641+ "1 allow\n";
1642+ set(policy);
1643+ check(policy, fork_exec2(argv, envp) == 0);
1644+ unset(policy);
1645+
1646+ policy = "100 acl execute path=\"/bin/true\"\n"
1647+ "0 deny envp[\"PATH\"]=\"/\"\n"
1648+ "1 allow\n";
1649+ set(policy);
1650+ check(policy, fork_exec2(argv, envp) == EOF);
1651+ unset(policy);
1652+
1653+ policy = "100 acl execute path=\"/bin/true\"\n"
1654+ "0 allow envp[\"PATH\"]!=\"/\"\n"
1655+ "1 deny\n";
1656+ set(policy);
1657+ check(policy, fork_exec2(argv, envp) == EOF);
1658+ unset(policy);
1659+
1660+ policy = "100 acl execute path=\"/bin/true\"\n"
1661+ "0 allow envp[\"PATH\"]=\"/\"\n"
1662+ "1 deny\n";
1663+ set(policy);
1664+ check(policy, fork_exec2(argv, envp) == 0);
1665+ unset(policy);
1666+
1667+ policy = "string_group PATH_VALUES /bin\n"
1668+ "string_group PATH_VALUES /\n"
1669+ "string_group PATH_VALUES /sbin\n"
1670+ "100 acl execute path=\"/bin/true\"\n"
1671+ "0 deny envp[\"PATH\"]!=@PATH_VALUES\n"
1672+ "1 allow\n";
1673+ set(policy);
1674+ check(policy, fork_exec2(argv, envp) == 0);
1675+ unset2(policy);
1676+
1677+ policy = "string_group PATH_VALUES /bin\n"
1678+ "string_group PATH_VALUES /\n"
1679+ "string_group PATH_VALUES /sbin\n"
1680+ "100 acl execute path=\"/bin/true\"\n"
1681+ "0 deny envp[\"PATH\"]=@PATH_VALUES\n"
1682+ "1 allow\n";
1683+ set(policy);
1684+ check(policy, fork_exec2(argv, envp) == EOF);
1685+ unset2(policy);
1686+
1687+ policy = "string_group PATH_VALUES /bin\n"
1688+ "string_group PATH_VALUES /\n"
1689+ "string_group PATH_VALUES /sbin\n"
1690+ "100 acl execute path=\"/bin/true\"\n"
1691+ "0 allow envp[\"PATH\"]!=@PATH_VALUES\n"
1692+ "1 deny\n";
1693+ set(policy);
1694+ check(policy, fork_exec2(argv, envp) == EOF);
1695+ unset2(policy);
1696+
1697+ policy = "string_group PATH_VALUES /bin\n"
1698+ "string_group PATH_VALUES /\n"
1699+ "string_group PATH_VALUES /sbin\n"
1700+ "100 acl execute path=\"/bin/true\"\n"
1701+ "0 allow envp[\"PATH\"]=@PATH_VALUES\n"
1702+ "1 deny\n";
1703+ set(policy);
1704+ check(policy, fork_exec2(argv, envp) == 0);
1705+ unset2(policy);
1706+
1707+ policy = "100 acl execute path=\"/bin/true\"\n"
1708+ "0 deny envp[\"PATH\"]!=NULL\n"
1709+ "1 allow\n";
1710+ set(policy);
1711+ check(policy, fork_exec2(argv, envp) == EOF);
1712+ unset(policy);
1713+
1714+ policy = "100 acl execute path=\"/bin/true\"\n"
1715+ "0 deny envp[\"PATH\"]=NULL\n"
1716+ "1 allow\n";
1717+ set(policy);
1718+ check(policy, fork_exec2(argv, envp) == 0);
1719+ unset(policy);
1720+
1721+ policy = "100 acl execute path=\"/bin/true\"\n"
1722+ "0 allow envp[\"PATH\"]!=NULL\n"
1723+ "1 deny\n";
1724+ set(policy);
1725+ check(policy, fork_exec2(argv, envp) == 0);
1726+ unset(policy);
1727+
1728+ policy = "100 acl execute path=\"/bin/true\"\n"
1729+ "0 allow envp[\"PATH\"]=NULL\n"
1730+ "1 deny\n";
1731+ set(policy);
1732+ check(policy, fork_exec2(argv, envp) == EOF);
1733+ unset(policy);
1734+}
1735+
1736+int main(int argc, char *argv[])
1737+{
1738+ fp = fopen("/proc/caitsith/policy", "w");
1739+ if (!fp) {
1740+ fprintf(stderr, " Can't open /proc/caitsith/policy\n");
1741+ return 1;
1742+ }
1743+ fprintf(fp, "quota audit[0]"
1744+ " allowed=1024 unmatched=1024 denied=1024\n");
1745+
1746+ test_task_transition();
1747+ test_file_read();
1748+ test_file_write();
1749+ test_file_create();
1750+ test_file_unlink();
1751+ test_file_link();
1752+ test_file_rename();
1753+ test_network_inet_stream();
1754+ test_network_inet_dgram();
1755+ test_network_inet_raw();
1756+ test_network_inet6_stream();
1757+ test_network_inet6_dgram();
1758+ test_capability();
1759+ test_ptrace();
1760+ test_signal();
1761+ test_environ();
1762+ test_file_execute();
1763+ return 0;
1764+}
--- trunk/caitsith-tools/kernel_test/ccs_log_test.c (nonexistent)
+++ trunk/caitsith-tools/kernel_test/ccs_log_test.c (revision 2)
@@ -0,0 +1,394 @@
1+#include <stdio.h>
2+#include <string.h>
3+#include <sys/types.h>
4+#include <sys/stat.h>
5+#include <fcntl.h>
6+#include <unistd.h>
7+#include <linux/kdev_t.h>
8+#include <sys/mount.h>
9+#include <sys/ioctl.h>
10+
11+#ifndef MS_MOVE
12+#define MS_MOVE 8192
13+#endif
14+#ifndef MS_UNBINDABLE
15+#define MS_UNBINDABLE (1<<17)
16+#endif
17+#ifndef MS_PRIVATE
18+#define MS_PRIVATE (1<<18)
19+#endif
20+#ifndef MS_SLAVE
21+#define MS_SLAVE (1<<19)
22+#endif
23+#ifndef MS_SHARED
24+#define MS_SHARED (1<<20)
25+#endif
26+
27+#include <asm/unistd.h>
28+static inline int pivot_root(const char *new_root, const char *put_old)
29+{
30+ return syscall(__NR_pivot_root, new_root, put_old);
31+}
32+
33+static _Bool debug = 0;
34+
35+static char *read_log(const char *expected_result, const char *expected_action)
36+{
37+ static int fd = EOF;
38+ static char buffer[16384];
39+ if (fd == EOF)
40+ fd = open("/proc/caitsith/audit", O_RDONLY);
41+ memset(buffer, 0, sizeof(buffer));
42+ while (buffer[0] = '\0', read(fd, buffer, sizeof(buffer) - 1) > 0) {
43+ char *cp1;
44+ char *cp2;
45+ if (debug)
46+ printf("Got '%s'\n", buffer);
47+ cp1 = strstr(buffer, " / ");
48+ if (buffer[0] != '#' || !cp1 || !strchr(buffer, '\n')) {
49+ fprintf(stderr,
50+ "Expected complete audit log, got '%s'\n",
51+ buffer);
52+ return NULL;
53+ }
54+ *cp1 = '\0';
55+ if (!strstr(buffer, expected_result))
56+ continue;
57+ cp1 += 3;
58+ cp2 = strchr(cp1, ' ');
59+ if (!cp2) {
60+ fprintf(stderr,
61+ "Expected complete audit log, got '%s'\n",
62+ cp1);
63+ return NULL;
64+ }
65+ *cp2++ = '\0';
66+ if (strcmp(expected_action, cp1))
67+ continue;
68+ return cp2;
69+ }
70+ fprintf(stderr, "Expected '%s' '%s', found none\n",
71+ expected_result, expected_action);
72+ return NULL;
73+}
74+
75+static void create_dummy(const char *path)
76+{
77+ close(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600));
78+}
79+
80+static void test_execute(void)
81+{
82+ char *args[3] = { "null", "--help", NULL };
83+ char *envs[3] = { "PATH=/", "HOME=/", NULL };
84+ create_dummy("/tmp/null");
85+ chmod("/tmp/null", 0700);
86+ execve("/tmp/null", args, envs);
87+}
88+
89+static void test_read(void)
90+{
91+ close(open("/dev/null", O_RDONLY));
92+}
93+
94+static void test_write(void)
95+{
96+ close(open("/dev/null", O_WRONLY));
97+}
98+
99+static void test_append(void)
100+{
101+ close(open("/dev/null", O_WRONLY | O_APPEND));
102+}
103+
104+static void test_create(void)
105+{
106+ unlink("/tmp/null");
107+ create_dummy("/tmp/null");
108+}
109+
110+static void test_unlink(void)
111+{
112+ create_dummy("/tmp/null");
113+ unlink("/tmp/null");
114+}
115+
116+static void test_getattr(void)
117+{
118+ struct stat buf;
119+ create_dummy("/tmp/null");
120+ stat("/tmp/null", &buf);
121+}
122+
123+static void test_mkdir(void)
124+{
125+ rmdir("/tmp/nulldir");
126+ mkdir("/tmp/nulldir", 0755);
127+}
128+
129+static void test_rmdir(void)
130+{
131+ mkdir("/tmp/nulldir", 0755);
132+ rmdir("/tmp/nulldir");
133+}
134+
135+static void test_mkfifo(void)
136+{
137+ unlink("/tmp/null");
138+ mknod("/tmp/null", S_IFIFO, 0);
139+}
140+
141+static void test_mksock(void)
142+{
143+ unlink("/tmp/null");
144+ mknod("/tmp/null", S_IFSOCK, 0);
145+}
146+
147+static void test_truncate(void)
148+{
149+ create_dummy("/tmp/null");
150+ truncate("/tmp/null", 0);
151+}
152+
153+static void test_symlink(void)
154+{
155+ unlink("/tmp/null");
156+ symlink("symlink'starget", "/tmp/null");
157+}
158+
159+static void test_mkblock(void)
160+{
161+ unlink("/tmp/null");
162+ mknod("/tmp/null", S_IFBLK, MKDEV(1, 0));
163+}
164+
165+static void test_mkchar(void)
166+{
167+ unlink("/tmp/null");
168+ mknod("/tmp/null", S_IFCHR, MKDEV(1, 3));
169+}
170+
171+static void test_link(void)
172+{
173+ create_dummy("/tmp/link");
174+ unlink("/tmp/newlink");
175+ link("/tmp/link", "/tmp/newlink");
176+}
177+
178+static void test_rename(void)
179+{
180+ link("/dev/null", "/dev/null0");
181+ rename("/dev/null0", "/dev/null1");
182+ unlink("/dev/null1");
183+}
184+
185+static void test_chmod(void)
186+{
187+ chmod("/dev/null", 0666);
188+}
189+
190+static void test_chown(void)
191+{
192+ chown("/dev/null", 0, -1);
193+}
194+
195+static void test_chgrp(void)
196+{
197+ chown("/dev/null", -1, 0);
198+}
199+
200+static void test_ioctl(void)
201+{
202+ int fd = open("/dev/null", 3);
203+ ioctl(fd, 0);
204+ close(fd);
205+}
206+
207+static void test_chroot(void)
208+{
209+ chroot("/");
210+}
211+
212+static void test_mount1(void)
213+{
214+ mount(NULL, "/tmp", "tmpfs", 0, "size=10%,uid=0,gid=0");
215+ umount("/tmp");
216+}
217+
218+static void test_mount2(void)
219+{
220+ mount("/", "/", NULL, MS_BIND, NULL);
221+}
222+
223+static void test_mount3(void)
224+{
225+ mount("/", "/", NULL, MS_MOVE, NULL);
226+}
227+
228+static void test_mount4(void)
229+{
230+ mount(NULL, "/", NULL, MS_REMOUNT | MS_NOATIME, "errors=remount-ro");
231+}
232+
233+static void test_unmount(void)
234+{
235+ umount2("/", 1);
236+}
237+
238+static void test_pivot_root(void)
239+{
240+ pivot_root("/", "/");
241+}
242+
243+static _Bool check_policy(const char *policy, const char *decision,
244+ const char *condition)
245+{
246+ static char buffer[16384];
247+ FILE *fp = fopen("/proc/caitsith/policy", "r");
248+ _Bool found = 0;
249+ if (!fp) {
250+ fprintf(stderr, "Can't read /proc/caitsith/policy interface.\n");
251+ return 0;
252+ }
253+ memset(buffer, 0, sizeof(buffer));
254+ while (fgets(buffer, sizeof(buffer) - 1, fp)) {
255+ if (strstr(buffer, decision) && strstr(buffer, condition)) {
256+ found = 1;
257+ break;
258+ }
259+ }
260+ fclose(fp);
261+ if (found) {
262+ printf("%s %s%s\n", policy, decision, condition);
263+ return 1;
264+ }
265+ fprintf(stderr, "Can't find %s %s%s\n",
266+ policy, decision, condition);
267+ return 0;
268+}
269+
270+int main(int argc, char *argv[])
271+{
272+ unsigned int i;
273+ char buffer[16384];
274+ struct {
275+ const char *action;
276+ void (*func) (void);
277+ } testcases[] = {
278+ { "execute", test_execute },
279+ { "read", test_read },
280+ { "write", test_write },
281+ { "append", test_append },
282+ { "create", test_create },
283+ { "unlink", test_unlink },
284+ { "getattr", test_getattr },
285+ { "mkdir", test_mkdir },
286+ { "rmdir", test_rmdir },
287+ { "mkfifo", test_mkfifo },
288+ { "mksock", test_mksock },
289+ { "truncate", test_truncate },
290+ { "symlink", test_symlink },
291+ { "mkblock", test_mkblock },
292+ { "mkchar", test_mkchar },
293+ { "link", test_link },
294+ { "rename", test_rename },
295+ { "chmod", test_chmod },
296+ { "chown", test_chown },
297+ { "chgrp", test_chgrp },
298+ { "ioctl", test_ioctl },
299+ { "chroot", test_chroot },
300+ { "mount", test_mount1 },
301+ { "mount", test_mount2 },
302+ { "mount", test_mount3 },
303+ { "mount", test_mount4 },
304+ { "unmount", test_unmount },
305+ { "pivot_root", test_pivot_root },
306+ /*
307+ acl inet_stream_bind
308+ acl inet_stream_listen
309+ acl inet_stream_connect
310+ acl inet_stream_accept
311+ acl inet_dgram_bind
312+ acl inet_dgram_send
313+ acl inet_dgram_recv
314+ acl inet_raw_bind
315+ acl inet_raw_send
316+ acl inet_raw_recv
317+ acl unix_stream_bind
318+ acl unix_stream_listen
319+ # acl unix_stream_connect
320+ acl unix_stream_accept
321+ acl unix_dgram_bind
322+ acl unix_dgram_send
323+ acl unix_dgram_recv
324+ acl unix_seqpacket_bind
325+ acl unix_seqpacket_listen
326+ acl unix_seqpacket_connect
327+ acl unix_seqpacket_accept
328+ # acl environ
329+ acl ptrace
330+ acl signal
331+ acl modify_policy
332+ # acl use_netlink_socket
333+ acl use_packet_socket
334+ acl use_reboot
335+ acl use_vhangup
336+ acl set_time
337+ acl set_priority
338+ acl set_hostname
339+ acl use_kernel_module
340+ acl use_new_kernel
341+ # acl auto_domain_transition
342+ acl manual_domain_transition
343+ */
344+ { NULL, NULL },
345+ };
346+ int fd_out = open("/proc/caitsith/policy", O_WRONLY);
347+ char *cp1;
348+ char *cp2;
349+ memset(buffer, 0, sizeof(buffer));
350+ if (fd_out == EOF) {
351+ fprintf(stderr, "Can't write /proc/caitsith/policy interface.\n");
352+ goto out;
353+ }
354+ cp1 = "POLICY_VERSION=20100903\n"
355+ "quota memory audit 16777216\n"
356+ "quota memory query 1048576\n"
357+ "quota audit[1] allowed=1024 denied=1024 unmatched=1024\n";
358+ i = strlen(cp1);
359+ if (write(fd_out, cp1, i) != i) {
360+ fprintf(stderr, "Can't write /proc/caitsith/policy interface.\n");
361+ goto out;
362+ }
363+ for (i = 0; testcases[i].action; i++) {
364+ int fd_in = open("/proc/caitsith/policy", O_RDONLY);
365+ if (fd_in == EOF) {
366+ fprintf(stderr,
367+ "Can't read /proc/caitsith/policy interface.\n");
368+ goto out;
369+ }
370+ snprintf(buffer, sizeof(buffer) - 1, "0 acl %s task.pid=%u\n"
371+ " audit 1\n", testcases[i].action, getpid());
372+ write(fd_out, buffer, strlen(buffer));
373+ testcases[i].func();
374+ cp2 = read_log("result=unmatched", testcases[i].action);
375+ if (!cp2)
376+ goto out;
377+ cp1 = "0 deny ";
378+ write(fd_out, cp1, strlen(cp1));
379+ write(fd_out, cp2, strlen(cp2));
380+ if (!check_policy(buffer, cp1, cp2))
381+ goto out;
382+ testcases[i].func();
383+ cp2 = read_log("result=denied", testcases[i].action);
384+ if (!cp2)
385+ goto out;
386+ snprintf(buffer, sizeof(buffer) - 1,
387+ "delete 0 acl %s task.pid=%u\n",
388+ testcases[i].action, getpid());
389+ write(fd_out, buffer, strlen(buffer));
390+ }
391+ return 0;
392+out:
393+ return 1;
394+}
--- trunk/caitsith-tools/kernel_test/Makefile (nonexistent)
+++ trunk/caitsith-tools/kernel_test/Makefile (revision 2)
@@ -0,0 +1,21 @@
1+ALL_FILES = ccs_param_test ccs_log_test
2+
3+all: $(ALL_FILES)
4+
5+CC=gcc
6+
7+CFLAGS=-Wall -O2
8+
9+#
10+# Tools for kernel testing.
11+#
12+
13+.c:
14+ $(CC) $(CFLAGS) -o $@ $<
15+
16+#
17+# Delete all test programs.
18+#
19+
20+clean:
21+ rm -f $(ALL_FILES)
--- trunk/caitsith-tools/usr_sbin/caitsithtools.h (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsithtools.h (revision 2)
@@ -0,0 +1,86 @@
1+/*
2+ * caitsithtools.h
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#define _FILE_OFFSET_BITS 64
24+#define _LARGEFILE_SOURCE
25+#define _LARGEFILE64_SOURCE
26+#define _GNU_SOURCE
27+#include <arpa/inet.h>
28+#include <asm/types.h>
29+#include <dirent.h>
30+#include <errno.h>
31+#include <fcntl.h>
32+#include <limits.h>
33+#include <stdio.h>
34+#include <stdlib.h>
35+#include <string.h>
36+#include <sys/file.h>
37+#include <sys/socket.h>
38+#include <sys/stat.h>
39+#include <sys/types.h>
40+#include <sys/un.h>
41+#include <time.h>
42+#include <unistd.h>
43+#include <stdarg.h>
44+
45+#define s8 __s8
46+#define u8 __u8
47+#define u16 __u16
48+#define u32 __u32
49+#define true 1
50+#define false 0
51+
52+/***** CONSTANTS DEFINITION START *****/
53+
54+#define CCS_PROC_POLICY_DIR "/proc/caitsith/"
55+#define CCS_PROC_POLICY_POLICY "/proc/caitsith/policy"
56+#define CCS_PROC_POLICY_AUDIT "/proc/caitsith/audit"
57+#define CCS_PROC_POLICY_PROCESS_STATUS "/proc/caitsith/.process_status"
58+#define CCS_PROC_POLICY_QUERY "/proc/caitsith/query"
59+
60+/***** CONSTANTS DEFINITION END *****/
61+
62+/***** STRUCTURES DEFINITION START *****/
63+
64+/***** STRUCTURES DEFINITION END *****/
65+
66+/***** PROTOTYPES DEFINITION START *****/
67+
68+FILE *ccs_open_read(const char *filename);
69+FILE *ccs_open_write(const char *filename);
70+_Bool ccs_check_remote_host(void);
71+_Bool ccs_decode(const char *ascii, char *bin);
72+_Bool ccs_str_starts(char *str, const char *begin);
73+char *ccs_freadline(FILE *fp);
74+char *ccs_strdup(const char *string);
75+int ccs_open_stream(const char *filename);
76+void *ccs_malloc(const size_t size);
77+void *ccs_realloc(void *ptr, const size_t size);
78+void ccs_get(void);
79+void ccs_normalize_line(char *buffer);
80+void ccs_put(void);
81+
82+extern _Bool ccs_network_mode;
83+extern u16 ccs_network_port;
84+extern u32 ccs_network_ip;
85+
86+/***** PROTOTYPES DEFINITION END *****/
--- trunk/caitsith-tools/usr_sbin/caitsith-queryd.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsith-queryd.c (revision 2)
@@ -0,0 +1,324 @@
1+/*
2+ * caitsith-queryd.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include "readline.h"
25+
26+/* Prototypes */
27+
28+static void ccs_printw(const char *fmt, ...)
29+ __attribute__ ((format(printf, 1, 2)));
30+static _Bool ccs_handle_query(unsigned int serial);
31+
32+/* Utility functions */
33+
34+static void ccs_printw(const char *fmt, ...)
35+{
36+ va_list args;
37+ int i;
38+ int len;
39+ char *buffer;
40+ va_start(args, fmt);
41+ len = vsnprintf((char *) &i, sizeof(i) - 1, fmt, args) + 16;
42+ va_end(args);
43+ buffer = ccs_malloc(len);
44+ va_start(args, fmt);
45+ len = vsnprintf(buffer, len, fmt, args);
46+ va_end(args);
47+ for (i = 0; i < len; i++) {
48+ addch(buffer[i]);
49+ refresh();
50+ }
51+ free(buffer);
52+}
53+
54+static void ccs_send_keepalive(void)
55+{
56+ static time_t previous = 0;
57+ time_t now = time(NULL);
58+ if (previous != now || !previous) {
59+ int ret_ignored;
60+ previous = now;
61+ ret_ignored = write(ccs_query_fd, "\n", 1);
62+ }
63+}
64+
65+/* Variables */
66+
67+static unsigned short int ccs_retries = 0;
68+
69+static FILE *ccs_policy_fp = NULL;
70+static int ccs_policy_fd = EOF;
71+#define CCS_MAX_READLINE_HISTORY 20
72+static const char **ccs_readline_history = NULL;
73+static int ccs_readline_history_count = 0;
74+static char ccs_buffer[32768];
75+
76+/* Main functions */
77+
78+static _Bool ccs_handle_query(unsigned int serial)
79+{
80+ int c = 0;
81+ int y;
82+ int x;
83+ int ret_ignored;
84+ char *line = NULL;
85+ static unsigned int prev_pid = 0;
86+ unsigned int pid;
87+ char qidbuf[128];
88+ char *cp = strstr(ccs_buffer, " global-pid=");
89+ if (!cp || sscanf(cp + 13, "%u", &pid) != 1) {
90+ ccs_printw("ERROR: Unsupported query.\n");
91+ return false;
92+ }
93+ cp = ccs_buffer + strlen(ccs_buffer);
94+ if (*(cp - 1) != '\n') {
95+ ccs_printw("ERROR: Unsupported query.\n");
96+ return false;
97+ }
98+ *(cp - 1) = '\0';
99+ if (pid != prev_pid) {
100+ if (prev_pid)
101+ ccs_printw("----------------------------------------"
102+ "\n");
103+ prev_pid = pid;
104+ }
105+ ccs_printw("%s\n", ccs_buffer);
106+ memset(qidbuf, 0, sizeof(qidbuf));
107+ snprintf(qidbuf, sizeof(qidbuf) - 1, "Q=%u\n", serial);
108+ ccs_printw("Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy "
109+ "and retry):");
110+ while (true) {
111+ c = ccs_getch2();
112+ if (c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == 'R' ||
113+ c == 'r' || c == 'A' || c == 'a' || c == 'S' || c == 's')
114+ break;
115+ ccs_send_keepalive();
116+ }
117+ ccs_printw("%c\n", c);
118+
119+ if (c == 'S' || c == 's') {
120+ if (ccs_network_mode) {
121+ fprintf(ccs_policy_fp, "%s", qidbuf);
122+ fputc(0, ccs_policy_fp);
123+ fflush(ccs_policy_fp);
124+ rewind(ccs_policy_fp);
125+ while (1) {
126+ char c;
127+ if (fread(&c, 1, 1, ccs_policy_fp) != 1 || !c)
128+ break;
129+ addch(c);
130+ refresh();
131+ ccs_send_keepalive();
132+ }
133+ } else {
134+ ret_ignored = write(ccs_policy_fd, qidbuf,
135+ strlen(qidbuf));
136+ while (1) {
137+ int i;
138+ int len = read(ccs_policy_fd, ccs_buffer,
139+ sizeof(ccs_buffer) - 1);
140+ if (len <= 0)
141+ break;
142+ for (i = 0; i < len; i++) {
143+ addch(ccs_buffer[i]);
144+ refresh();
145+ }
146+ ccs_send_keepalive();
147+ }
148+ }
149+ c = 'r';
150+ }
151+
152+ /* Append to policy. */
153+ if (c != 'A' && c != 'a')
154+ goto not_append;
155+ c = 'r';
156+ getyx(stdscr, y, x);
157+ cp = strstr(ccs_buffer, " / ");
158+ if (!cp++)
159+ return false;
160+ cp = strchr(cp + 2, ' ');
161+ if (!cp++)
162+ return false;
163+ cp = strchr(cp, ' ');
164+ if (!cp++)
165+ return false;
166+ ccs_initial_readline_data = NULL;
167+ ccs_readline_history_count =
168+ ccs_add_history(cp, ccs_readline_history,
169+ ccs_readline_history_count,
170+ CCS_MAX_READLINE_HISTORY);
171+ line = ccs_readline(y, 0, "Enter new entry> ", ccs_readline_history,
172+ ccs_readline_history_count, 128000, 8);
173+ scrollok(stdscr, TRUE);
174+ ccs_printw("\n");
175+ if (!line || !*line) {
176+ ccs_printw("None added.\n");
177+ goto not_append;
178+ }
179+ ccs_readline_history_count =
180+ ccs_add_history(line, ccs_readline_history,
181+ ccs_readline_history_count,
182+ CCS_MAX_READLINE_HISTORY);
183+ if (ccs_network_mode) {
184+ fprintf(ccs_policy_fp, "%s%s\n", qidbuf, line);
185+ fflush(ccs_policy_fp);
186+ } else {
187+ ret_ignored = write(ccs_policy_fd, qidbuf, strlen(qidbuf));
188+ ret_ignored = write(ccs_policy_fd, line, strlen(line));
189+ ret_ignored = write(ccs_policy_fd, "\n", 1);
190+ }
191+ ccs_printw("Added '%s'.\n", line);
192+not_append:
193+ free(line);
194+ /* Write answer. */
195+ if (c == 'Y' || c == 'y' || c == 'A' || c == 'a')
196+ c = 1;
197+ else if (c == 'R' || c == 'r')
198+ c = 3;
199+ else
200+ c = 2;
201+ snprintf(ccs_buffer, sizeof(ccs_buffer) - 1, "A%u=%u\n", serial, c);
202+ ret_ignored = write(ccs_query_fd, ccs_buffer, strlen(ccs_buffer));
203+ ccs_printw("\n");
204+ return true;
205+}
206+
207+int main(int argc, char *argv[])
208+{
209+ if (argc == 1)
210+ goto ok;
211+ {
212+ char *cp = strchr(argv[1], ':');
213+ if (cp) {
214+ *cp++ = '\0';
215+ ccs_network_ip = inet_addr(argv[1]);
216+ ccs_network_port = htons(atoi(cp));
217+ ccs_network_mode = true;
218+ if (!ccs_check_remote_host())
219+ return 1;
220+ goto ok;
221+ }
222+ }
223+ printf("Usage: %s [remote_ip:remote_port]\n\n", argv[0]);
224+ printf("This program is used for granting access requests manually."
225+ "\n");
226+ printf("This program shows access requests that are about to rejected "
227+ "by the kernel's decision.\n");
228+ printf("If you answer before the kernel's decision taken effect, your "
229+ "decision will take effect.\n");
230+ printf("You can use this program to respond to accidental access "
231+ "requests triggered by non-routine tasks (such as restarting "
232+ "daemons after updating).\n");
233+ printf("To terminate this program, use 'Ctrl-C'.\n");
234+ return 0;
235+ok:
236+ if (ccs_network_mode) {
237+ ccs_query_fd = ccs_open_stream("proc:query");
238+ ccs_policy_fp = ccs_open_write(CCS_PROC_POLICY_POLICY);
239+ } else {
240+ ccs_query_fd = open(CCS_PROC_POLICY_QUERY, O_RDWR);
241+ ccs_policy_fd = open(CCS_PROC_POLICY_POLICY, O_RDWR);
242+ }
243+ if (ccs_query_fd == EOF) {
244+ fprintf(stderr,
245+ "You can't run this utility for this kernel.\n");
246+ return 1;
247+ } else if (!ccs_network_mode && write(ccs_query_fd, "", 0) != 0) {
248+ fprintf(stderr, "You need to register this program to %s to "
249+ "run this program.\n", CCS_PROC_POLICY_POLICY);
250+ return 1;
251+ }
252+ ccs_readline_history = ccs_malloc(CCS_MAX_READLINE_HISTORY *
253+ sizeof(const char *));
254+ ccs_send_keepalive();
255+ initscr();
256+ cbreak();
257+ noecho();
258+ nonl();
259+ intrflush(stdscr, FALSE);
260+ keypad(stdscr, TRUE);
261+ clear();
262+ refresh();
263+ scrollok(stdscr, TRUE);
264+ if (ccs_network_mode) {
265+ const u32 ip = ntohl(ccs_network_ip);
266+ ccs_printw("Monitoring /proc/caitsith/query via %u.%u.%u.%u:%u.",
267+ (u8) (ip >> 24), (u8) (ip >> 16), (u8) (ip >> 8),
268+ (u8) ip, ntohs(ccs_network_port));
269+ } else
270+ ccs_printw("Monitoring /proc/caitsith/query .");
271+ ccs_printw(" Press Ctrl-C to terminate.\n\n");
272+ while (true) {
273+ unsigned int serial;
274+ char *cp;
275+ /* Wait for query and read query. */
276+ memset(ccs_buffer, 0, sizeof(ccs_buffer));
277+ if (ccs_network_mode) {
278+ int i;
279+ int ret_ignored;
280+ ret_ignored = write(ccs_query_fd, "", 1);
281+ for (i = 0; i < sizeof(ccs_buffer) - 1; i++) {
282+ if (read(ccs_query_fd, ccs_buffer + i, 1) != 1)
283+ break;
284+ if (!ccs_buffer[i])
285+ goto read_ok;
286+ }
287+ break;
288+ } else {
289+ fd_set rfds;
290+ FD_ZERO(&rfds);
291+ FD_SET(ccs_query_fd, &rfds);
292+ select(ccs_query_fd + 1, &rfds, NULL, NULL, NULL);
293+ if (!FD_ISSET(ccs_query_fd, &rfds))
294+ continue;
295+ if (read(ccs_query_fd, ccs_buffer,
296+ sizeof(ccs_buffer) - 1) <= 0)
297+ continue;
298+ }
299+read_ok:
300+ cp = strchr(ccs_buffer, '\n');
301+ if (!cp)
302+ continue;
303+ *cp = '\0';
304+
305+ /* Get query number. */
306+ if (sscanf(ccs_buffer, "Q%u-%hu", &serial, &ccs_retries) != 2)
307+ continue;
308+ memmove(ccs_buffer, cp + 1, strlen(cp + 1) + 1);
309+
310+ /* Clear pending input. */;
311+ timeout(0);
312+ while (true) {
313+ int c = ccs_getch2();
314+ if (c == EOF || c == ERR)
315+ break;
316+ }
317+ timeout(1000);
318+ if (ccs_handle_query(serial))
319+ continue;
320+ break;
321+ }
322+ endwin();
323+ return 0;
324+}
--- trunk/caitsith-tools/usr_sbin/caitsith-auditd.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsith-auditd.c (revision 2)
@@ -0,0 +1,464 @@
1+/*
2+ * caitsith-auditd.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include <signal.h>
25+#include <syslog.h>
26+#include <poll.h>
27+
28+#define CCS_AUDITD_CONF "/etc/caitsith/tools/auditd.conf"
29+
30+struct ccs_destination {
31+ const char *pathname;
32+ int fd;
33+};
34+
35+static struct ccs_destination *destination_list = NULL;
36+static unsigned int destination_list_len = 0;
37+
38+enum ccs_rule_types {
39+ CCS_SORT_RULE_HEADER,
40+ CCS_SORT_RULE_ACL,
41+ CCS_SORT_RULE_DESTINATION,
42+};
43+
44+enum ccs_operator_types {
45+ CCS_SORT_OPERATOR_CONTAINS,
46+ CCS_SORT_OPERATOR_EQUALS,
47+ CCS_SORT_OPERATOR_STARTS,
48+};
49+
50+struct ccs_sort_rules {
51+ enum ccs_rule_types type;
52+ enum ccs_operator_types operation;
53+ unsigned int index;
54+ const char *string;
55+ unsigned int string_len; /* strlen(string). */
56+};
57+
58+static struct ccs_sort_rules *rules = NULL;
59+static unsigned int rules_len = 0;
60+
61+static void ccs_auditd_init_rules(const char *filename)
62+{
63+ static _Bool first = 1;
64+ FILE *fp = fopen(filename, "r");
65+ unsigned int line_no = 0;
66+ unsigned int i;
67+ if (!first) {
68+ for (i = 0; i < rules_len; i++)
69+ free((void *) rules[i].string);
70+ rules_len = 0;
71+ for (i = 0; i < destination_list_len; i++) {
72+ free((void *) destination_list[i].pathname);
73+ close(destination_list[i].fd);
74+ }
75+ destination_list_len = 0;
76+ }
77+ if (!fp) {
78+ if (first)
79+ fprintf(stderr, "Can't open %s for reading.\n",
80+ filename);
81+ else
82+ syslog(LOG_WARNING, "Can't open %s for reading.\n",
83+ filename);
84+ exit(1);
85+ }
86+ ccs_get();
87+ while (true) {
88+ char *line = ccs_freadline(fp);
89+ struct ccs_sort_rules *ptr;
90+ unsigned char c;
91+ if (!line)
92+ break;
93+ line_no++;
94+ ccs_normalize_line(line);
95+ if (*line == '#' || !*line)
96+ continue;
97+ rules = ccs_realloc(rules, sizeof(struct ccs_sort_rules) *
98+ (rules_len + 1));
99+ ptr = &rules[rules_len++];
100+ memset(ptr, 0, sizeof(*ptr));
101+ if (ccs_str_starts(line, "destination ")) {
102+ if (*line != '/')
103+ goto invalid_rule;
104+ for (i = 0; i < destination_list_len; i++)
105+ if (!strcmp(destination_list[i].pathname,
106+ line))
107+ break;
108+ if (i < destination_list_len)
109+ goto store_destination;
110+ destination_list =
111+ ccs_realloc(destination_list,
112+ ++destination_list_len *
113+ sizeof(struct ccs_destination));
114+ if (!ccs_decode(line, line))
115+ goto invalid_rule;
116+ destination_list[i].pathname = ccs_strdup(line);
117+ destination_list[i].fd = EOF;
118+store_destination:
119+ ptr->type = CCS_SORT_RULE_DESTINATION;
120+ ptr->index = i;
121+ continue;
122+ }
123+ if (ccs_str_starts(line, "header"))
124+ ptr->type = CCS_SORT_RULE_HEADER;
125+ else if (ccs_str_starts(line, "acl"))
126+ ptr->type = CCS_SORT_RULE_ACL;
127+ else
128+ goto invalid_rule;
129+ switch (sscanf(line, "[%u%c", &ptr->index, &c)) {
130+ case 0:
131+ break;
132+ case 2:
133+ if (c == ']') {
134+ char *cp = strchr(line, ']') + 1;
135+ memmove(line, cp, strlen(cp) + 1);
136+ break;
137+ }
138+ default:
139+ goto invalid_rule;
140+ }
141+ if (ccs_str_starts(line, ".contains "))
142+ ptr->operation = CCS_SORT_OPERATOR_CONTAINS;
143+ else if (ccs_str_starts(line, ".equals "))
144+ ptr->operation = CCS_SORT_OPERATOR_EQUALS;
145+ else if (ccs_str_starts(line, ".starts "))
146+ ptr->operation = CCS_SORT_OPERATOR_STARTS;
147+ else
148+ goto invalid_rule;
149+ if (!*line)
150+ goto invalid_rule;
151+ line = ccs_strdup(line);
152+ ptr->string = line;
153+ ptr->string_len = strlen(line);
154+ }
155+ ccs_put();
156+ fclose(fp);
157+ if (!rules_len) {
158+ if (first)
159+ fprintf(stderr, "No rules defined in %s .\n",
160+ filename);
161+ else
162+ syslog(LOG_WARNING, "No rules defined in %s .\n",
163+ filename);
164+ exit(1);
165+ }
166+ for (i = 0; i < destination_list_len; i++) {
167+ struct ccs_destination *ptr = &destination_list[i];
168+ const char *path = ptr->pathname;
169+ /* This is OK because path is a strdup()ed string. */
170+ char *pos = (char *) path;
171+ while (*pos) {
172+ int ret_ignored;
173+ if (*pos++ != '/')
174+ continue;
175+ *(pos - 1) = '\0';
176+ ret_ignored = mkdir(path, 0700);
177+ *(pos - 1) = '/';
178+ }
179+ do {
180+ ptr->fd = open(path, O_WRONLY | O_APPEND | O_CREAT,
181+ 0600);
182+ } while (ptr->fd == EOF && errno == EINTR);
183+ if (ptr->fd == EOF) {
184+ if (first)
185+ fprintf(stderr, "Can't open %s for writing.\n",
186+ path);
187+ else
188+ syslog(LOG_WARNING,
189+ "Can't open %s for writing.\n", path);
190+ exit(1);
191+ }
192+ }
193+ first = 0;
194+ return;
195+invalid_rule:
196+ if (first)
197+ fprintf(stderr, "Invalid rule at line %u in %s .\n", line_no,
198+ filename);
199+ else
200+ syslog(LOG_WARNING, "Invalid rule at line %u in %s .\n",
201+ line_no, filename);
202+ exit(1);
203+}
204+
205+static int ccs_check_rules(char *header, char *acl)
206+{
207+ unsigned int i;
208+ _Bool matched = true;
209+ for (i = 0; i < rules_len; i++) {
210+ const struct ccs_sort_rules *ptr = &rules[i];
211+ char *line;
212+ unsigned int index = ptr->index;
213+ const char *find = ptr->string;
214+ unsigned int find_len = ptr->string_len;
215+ switch (ptr->type) {
216+ case CCS_SORT_RULE_HEADER:
217+ line = header;
218+ break;
219+ case CCS_SORT_RULE_ACL:
220+ line = acl;
221+ break;
222+ default: /* CCS_SORT_RULE_DESTINATION */
223+ if (matched)
224+ return ptr->index;
225+ matched = true;
226+ continue;
227+ }
228+ if (!matched)
229+ continue;
230+ if (!index) {
231+ switch (ptr->operation) {
232+ case CCS_SORT_OPERATOR_CONTAINS:
233+ while (1) {
234+ char *cp = strstr(line, find);
235+ if (!cp) {
236+ matched = false;
237+ break;
238+ }
239+ if ((cp == line || *(cp - 1) == ' ') &&
240+ (!cp[find_len] ||
241+ cp[find_len] == ' '))
242+ break;
243+ line = cp + 1;
244+ }
245+ break;
246+ case CCS_SORT_OPERATOR_EQUALS:
247+ matched = !strcmp(line, find);
248+ break;
249+ default: /* CCS_SORT_OPERATOR_STARTS */
250+ matched = !strncmp(line, find, find_len) &&
251+ (!line[find_len] ||
252+ line[find_len] == ' ');
253+ }
254+ } else {
255+ char *word = line;
256+ char *word_end;
257+ while (--index) {
258+ char *cp = strchr(word, ' ');
259+ if (!cp) {
260+ matched = false;
261+ break;
262+ }
263+ word = cp + 1;
264+ }
265+ if (!matched)
266+ continue;
267+ word_end = strchr(word, ' ');
268+ if (word_end)
269+ *word_end = '\0';
270+ switch (ptr->operation) {
271+ case CCS_SORT_OPERATOR_CONTAINS:
272+ matched = strstr(word, find) != NULL;
273+ break;
274+ case CCS_SORT_OPERATOR_EQUALS:
275+ matched = !strcmp(word, find);
276+ break;
277+ default: /* CCS_SORT_OPERATOR_STARTS */
278+ matched = !strncmp(word, find, find_len);
279+ break;
280+ }
281+ if (word_end)
282+ *word_end = ' ';
283+ }
284+ }
285+ return EOF;
286+}
287+
288+static _Bool ccs_write_log(const int i, char *buffer)
289+{
290+ int len = strlen(buffer);
291+ int ret;
292+ struct ccs_destination *ptr = &destination_list[i];
293+ /* Create destination file if needed. */
294+ if (access(ptr->pathname, F_OK)) {
295+ close(ptr->fd);
296+ do {
297+ ptr->fd = open(ptr->pathname,
298+ O_WRONLY | O_APPEND | O_CREAT, 0600);
299+ } while (ptr->fd == EOF && errno == EINTR);
300+ if (ptr->fd == EOF) {
301+ syslog(LOG_WARNING, "Can't open %s for writing.\n",
302+ ptr->pathname);
303+ return 0;
304+ }
305+ }
306+ do {
307+ ret = write(ptr->fd, buffer, len);
308+ if (ret == len)
309+ return 1;
310+ } while (ret == EOF && errno == EINTR);
311+ syslog(LOG_WARNING, "Can't write to %s .\n", ptr->pathname);
312+ return 0;
313+}
314+
315+static void block_sighup(const _Bool block)
316+{
317+ sigset_t sigset;
318+ sigemptyset(&sigset);
319+ sigaddset(&sigset, SIGHUP);
320+ sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigset, NULL);
321+}
322+
323+static void ccs_reload_config(int sig)
324+{
325+ block_sighup(1);
326+ syslog(LOG_WARNING, "Reloading configuration file.\n");
327+ ccs_auditd_init_rules(CCS_AUDITD_CONF);
328+ block_sighup(0);
329+}
330+
331+int main(int argc, char *argv[])
332+{
333+ unsigned int i;
334+ int fd_in;
335+ for (i = 1; i < argc; i++) {
336+ char *ptr = argv[i];
337+ char *cp = strchr(ptr, ':');
338+ if (!cp)
339+ goto usage;
340+ *cp++ = '\0';
341+ if (ccs_network_mode)
342+ goto usage;
343+ ccs_network_ip = inet_addr(ptr);
344+ ccs_network_port = htons(atoi(cp));
345+ ccs_network_mode = true;
346+ if (!ccs_check_remote_host())
347+ return 1;
348+ }
349+ ccs_auditd_init_rules(CCS_AUDITD_CONF);
350+ if (ccs_network_mode)
351+ goto start;
352+ if (access(CCS_PROC_POLICY_AUDIT, R_OK)) {
353+ fprintf(stderr, "You can't run this daemon for this kernel."
354+ "\n");
355+ return 1;
356+ }
357+ { /* Get exclusive lock. */
358+ int fd = open("/proc/self/exe", O_RDONLY);
359+ if (flock(fd, LOCK_EX | LOCK_NB) == EOF)
360+ return 0;
361+ }
362+start:
363+ if (ccs_network_mode)
364+ fd_in = ccs_open_stream("proc:audit");
365+ else
366+ fd_in = open(CCS_PROC_POLICY_AUDIT, O_RDONLY);
367+ if (fd_in == EOF) {
368+ fprintf(stderr, "Can't open %s for reading.\n",
369+ CCS_PROC_POLICY_AUDIT);
370+ return 1;
371+ }
372+ switch (fork()) {
373+ case 0:
374+ break;
375+ case -1:
376+ fprintf(stderr, "Can't fork()\n");
377+ return 1;
378+ default:
379+ return 0;
380+ }
381+ if (setsid() == EOF) {
382+ fprintf(stderr, "Can't setsid()\n");
383+ return 1;
384+ }
385+ switch (fork()) {
386+ case 0:
387+ break;
388+ case -1:
389+ fprintf(stderr, "Can't fork()\n");
390+ return 1;
391+ default:
392+ return 0;
393+ }
394+ if (chdir("/")) {
395+ fprintf(stderr, "Can't chdir()\n");
396+ return 1;
397+ }
398+ close(0);
399+ close(1);
400+ close(2);
401+ openlog("caitsith-auditd", 0, LOG_USER);
402+ syslog(LOG_WARNING, "Started.\n");
403+ signal(SIGHUP, ccs_reload_config);
404+ while (true) {
405+ static char buffer[32768];
406+ char *acl;
407+ char *tail;
408+ int ret;
409+ memset(buffer, 0, sizeof(buffer));
410+ if (ccs_network_mode) {
411+ int j;
412+ for (j = 0; j < sizeof(buffer) - 1; j++) {
413+ do {
414+ ret = read(fd_in, buffer + j, 1);
415+ } while (ret == EOF && errno == EINTR);
416+ if (ret != 1)
417+ goto out;
418+ if (!buffer[j])
419+ break;
420+ }
421+ if (j == sizeof(buffer) - 1)
422+ goto out;
423+ } else {
424+ while (read(fd_in, buffer, sizeof(buffer) - 1) <= 0) {
425+ /* Wait for data. */
426+ struct pollfd pfd = {
427+ .fd = fd_in,
428+ .events = POLLIN,
429+ };
430+ if (poll(&pfd, 1, -1) == EOF && errno != EINTR)
431+ goto out;
432+ }
433+ }
434+ /* Split into two parts. */
435+ acl = strstr(buffer, " / ");
436+ if (!acl)
437+ continue;
438+ *acl = '\0';
439+ acl += 3;
440+ tail = strchr(acl, '\n');
441+ if (!tail)
442+ continue;
443+ *tail = '\0';
444+ block_sighup(1);
445+ /* Check for filtering rules. */
446+ i = ccs_check_rules(buffer, acl);
447+ if (i != EOF) {
448+ *tail = '\n';
449+ *(acl - 3) = ' ';
450+ /* Write the audit log. */
451+ if (!ccs_write_log(i, buffer))
452+ break;
453+ }
454+ block_sighup(0);
455+ }
456+out:
457+ syslog(LOG_WARNING, "Terminated.\n");
458+ closelog();
459+ return 1;
460+usage:
461+ fprintf(stderr, "%s [remote_ip:remote_port]\n"
462+ " See %s for configuration.\n", argv[0], CCS_AUDITD_CONF);
463+ return 1;
464+}
--- trunk/caitsith-tools/usr_sbin/caitsith-notifyd.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsith-notifyd.c (revision 2)
@@ -0,0 +1,256 @@
1+/*
2+ * caitsith-notifyd.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+#include <sys/wait.h>
25+#include <signal.h>
26+#include <syslog.h>
27+#include <poll.h>
28+
29+#define CCS_NOTIFYD_CONF "/etc/caitsith/tools/notifyd.conf"
30+
31+static const char *proc_policy_query = "/proc/caitsith/query";
32+static int query_fd = EOF;
33+static int time_to_wait = 0;
34+static char **action_to_take = NULL;
35+static int minimal_interval = 0;
36+
37+static void ccs_notifyd_init_rules(const char *filename)
38+{
39+ static _Bool first = 1;
40+ FILE *fp = fopen(filename, "r");
41+ unsigned int line_no = 0;
42+ char *action = NULL;
43+ if (!first) {
44+ free(action_to_take);
45+ action_to_take = NULL;
46+ time_to_wait = 0;
47+ minimal_interval = 0;
48+ }
49+ if (!fp) {
50+ if (first)
51+ fprintf(stderr, "Can't open %s for reading.\n",
52+ filename);
53+ else
54+ syslog(LOG_WARNING, "Can't open %s for reading.\n",
55+ filename);
56+ exit(1);
57+ }
58+ ccs_get();
59+ while (true) {
60+ char *line = ccs_freadline(fp);
61+ if (!line)
62+ break;
63+ line_no++;
64+ ccs_normalize_line(line);
65+ if (*line == '#' || !*line)
66+ continue;
67+ if (sscanf(line, "time_to_wait %u", &time_to_wait) == 1 ||
68+ sscanf(line, "minimal_interval %u", &minimal_interval)
69+ == 1)
70+ continue;
71+ if (!ccs_str_starts(line, "action_to_take "))
72+ continue;
73+ if (!*line)
74+ goto invalid_rule;
75+ if (action)
76+ goto invalid_rule;
77+ action = ccs_strdup(line);
78+ }
79+ ccs_put();
80+ fclose(fp);
81+ if (!action) {
82+ if (first)
83+ fprintf(stderr, "No actions defined in %s .\n",
84+ filename);
85+ else
86+ syslog(LOG_WARNING, "No actions defined in %s .\n",
87+ filename);
88+ exit(1);
89+ }
90+ {
91+ int count = 0;
92+ char *sp = action;
93+ while (true) {
94+ char *cp = strsep(&sp, " ");
95+ action_to_take = ccs_realloc(action_to_take,
96+ sizeof(char *) * ++count);
97+ action_to_take[count - 1] = cp;
98+ if (!cp)
99+ break;
100+ if (!ccs_decode(cp, cp))
101+ goto invalid_rule;
102+ }
103+ }
104+ first = 0;
105+ return;
106+invalid_rule:
107+ if (first)
108+ fprintf(stderr, "Invalid rule at line %u in %s .\n", line_no,
109+ filename);
110+ else
111+ syslog(LOG_WARNING, "Invalid rule at line %u in %s .\n",
112+ line_no, filename);
113+ exit(1);
114+}
115+
116+static void block_sighup(const _Bool block)
117+{
118+ sigset_t sigset;
119+ sigemptyset(&sigset);
120+ sigaddset(&sigset, SIGHUP);
121+ sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigset, NULL);
122+}
123+
124+static void main_loop(void)
125+{
126+ static char buffer[32768];
127+ while (query_fd != EOF) {
128+ int pipe_fd[2];
129+ pid_t pid;
130+ memset(buffer, 0, sizeof(buffer));
131+ while (read(query_fd, buffer, sizeof(buffer) - 1) <= 0) {
132+ /* Wait for data. */
133+ struct pollfd pfd = {
134+ .fd = query_fd,
135+ .events = POLLIN,
136+ };
137+ if (poll(&pfd, 1, -1) == EOF && errno != EINTR)
138+ return;
139+ }
140+ if (pipe(pipe_fd) == EOF) {
141+ syslog(LOG_WARNING, "Can't create pipe.\n");
142+ return;
143+ }
144+ block_sighup(1);
145+ pid = fork();
146+ if (pid == -1) {
147+ syslog(LOG_WARNING, "Can't fork().\n");
148+ return;
149+ }
150+ if (!pid) {
151+ int ret_ignored;
152+ ret_ignored = close(query_fd);
153+ ret_ignored = close(pipe_fd[1]);
154+ ret_ignored = close(0);
155+ ret_ignored = dup2(pipe_fd[0], 0);
156+ ret_ignored = close(pipe_fd[0]);
157+ execvp(action_to_take[0], action_to_take);
158+ syslog(LOG_WARNING, "Can't execute %s\n",
159+ action_to_take[0]);
160+ closelog();
161+ _exit(1);
162+ } else {
163+ int ret_ignored;
164+ int len = strlen(buffer);
165+ close(pipe_fd[0]);
166+ /* This is OK because read() < sizeof(buffer). */
167+ buffer[len++] = '\n';
168+ ret_ignored = write(pipe_fd[1], buffer, len);
169+ close(pipe_fd[1]);
170+ }
171+ block_sighup(0);
172+ while (time_to_wait-- > 0) {
173+ int ret_ignored;
174+ sleep(1);
175+ ret_ignored = write(query_fd, "\n", 1);
176+ }
177+ close(query_fd);
178+ while (waitpid(pid, NULL, __WALL) == EOF && errno == EINTR);
179+ sleep(minimal_interval);
180+ do {
181+ query_fd = open(proc_policy_query, O_RDWR);
182+ } while (query_fd == EOF && errno == EINTR);
183+ }
184+}
185+
186+static void ccs_reload_config(int sig)
187+{
188+ block_sighup(1);
189+ syslog(LOG_WARNING, "Reloading configuration file.\n");
190+ ccs_notifyd_init_rules(CCS_NOTIFYD_CONF);
191+ block_sighup(0);
192+}
193+
194+int main(int argc, char *argv[])
195+{
196+ unsetenv("SHELLOPTS"); /* Make sure popen() executes commands. */
197+ if (argc != 1)
198+ goto usage;
199+ ccs_notifyd_init_rules(CCS_NOTIFYD_CONF);
200+ query_fd = open(proc_policy_query, O_RDWR);
201+ if (query_fd == EOF) {
202+ fprintf(stderr, "You can't run this daemon for this kernel."
203+ "\n");
204+ return 1;
205+ } else if (time_to_wait && write(query_fd, "", 0) != 0) {
206+ fprintf(stderr, "You need to give this program permission to "
207+ "modify policy.\n");
208+ return 1;
209+ }
210+ umask(0);
211+ switch (fork()) {
212+ case 0:
213+ break;
214+ case -1:
215+ fprintf(stderr, "Can't fork()\n");
216+ return 1;
217+ default:
218+ return 0;
219+ }
220+ if (setsid() == EOF) {
221+ fprintf(stderr, "Can't setsid()\n");
222+ return 1;
223+ }
224+ switch (fork()) {
225+ case 0:
226+ break;
227+ case -1:
228+ fprintf(stderr, "Can't fork()\n");
229+ return 1;
230+ default:
231+ return 0;
232+ }
233+ if (chdir("/")) {
234+ fprintf(stderr, "Can't chdir()\n");
235+ return 1;
236+ }
237+ { /* Get exclusive lock. */
238+ int fd = open("/proc/self/exe", O_RDONLY);
239+ if (flock(fd, LOCK_EX | LOCK_NB) == EOF)
240+ return 0;
241+ }
242+ close(0);
243+ close(1);
244+ close(2);
245+ openlog("caitsith-notifyd", 0, LOG_USER);
246+ syslog(LOG_WARNING, "Started.\n");
247+ signal(SIGHUP, ccs_reload_config);
248+ main_loop();
249+ syslog(LOG_WARNING, "Terminated.\n");
250+ closelog();
251+ return 1;
252+usage:
253+ fprintf(stderr, "%s\n See %s for configuration.\n", argv[0],
254+ CCS_NOTIFYD_CONF);
255+ return 1;
256+}
--- trunk/caitsith-tools/usr_sbin/caitsith-savepolicy.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsith-savepolicy.c (revision 2)
@@ -0,0 +1,177 @@
1+/*
2+ * caitsith-savepolicy.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+/**
26+ * ccs_move_proc_to_file - Save /proc/caitsith/ to /etc/caitsith/ .
27+ *
28+ * @src: Filename to save from.
29+ * @dest: Filename to save to.
30+ *
31+ * Returns true on success, false otherwise.
32+ */
33+static _Bool ccs_move_proc_to_file(const char *src, const char *dest)
34+{
35+ FILE *proc_fp = ccs_open_read(src);
36+ FILE *file_fp;
37+ _Bool result = true;
38+ if (!proc_fp) {
39+ fprintf(stderr, "Can't open %s for reading.\n", src);
40+ return false;
41+ }
42+ file_fp = dest ? fopen(dest, "w") : stdout;
43+ if (!file_fp) {
44+ fprintf(stderr, "Can't open %s for writing.\n", dest);
45+ fclose(proc_fp);
46+ return false;
47+ }
48+ while (true) {
49+ const int c = fgetc(proc_fp);
50+ if (ccs_network_mode && !c)
51+ break;
52+ if (c == EOF)
53+ break;
54+ if (fputc(c, file_fp) == EOF)
55+ result = false;
56+ }
57+ fclose(proc_fp);
58+ if (file_fp != stdout)
59+ if (fclose(file_fp) == EOF)
60+ result = false;
61+ return result;
62+}
63+
64+static const char *ccs_policy_dir = NULL;
65+
66+static _Bool ccs_cat_file(const char *path)
67+{
68+ FILE *fp = ccs_open_read(path);
69+ _Bool result = true;
70+ if (!fp) {
71+ fprintf(stderr, "Can't open %s\n", path);
72+ return false;
73+ }
74+ while (true) {
75+ int c = fgetc(fp);
76+ if (ccs_network_mode && !c)
77+ break;
78+ if (c == EOF)
79+ break;
80+ if (putchar(c) == EOF)
81+ result = false;
82+ }
83+ fclose(fp);
84+ return result;
85+}
86+
87+static _Bool ccs_save_policy(void)
88+{
89+ time_t now = time(NULL);
90+ char stamp[32] = { };
91+ while (1) {
92+ struct tm *tm = localtime(&now);
93+ snprintf(stamp, sizeof(stamp) - 1,
94+ "%02d-%02d-%02d.%02d:%02d:%02d",
95+ tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
96+ tm->tm_hour, tm->tm_min, tm->tm_sec);
97+ if (access(stamp, F_OK))
98+ break;
99+ else if (errno == EEXIST)
100+ now++;
101+ else {
102+ fprintf(stderr, "Can't create %s/policy/%s .\n",
103+ ccs_policy_dir, stamp);
104+ return false;
105+ }
106+ }
107+ if (!ccs_move_proc_to_file(CCS_PROC_POLICY_POLICY, stamp) ||
108+ (rename("current", "previous") && errno != ENOENT) ||
109+ symlink(stamp, "current")) {
110+ fprintf(stderr, "Failed to save policy.\n");
111+ return false;
112+ }
113+ return true;
114+}
115+
116+int main(int argc, char *argv[])
117+{
118+ _Bool use_stdout = false;
119+ int i;
120+ for (i = 1; i < argc; i++) {
121+ char *ptr = argv[i];
122+ char *cp = strchr(ptr, ':');
123+ if (*ptr == '/') {
124+ if (ccs_policy_dir || use_stdout)
125+ goto usage;
126+ ccs_policy_dir = ptr;
127+ } else if (cp) {
128+ *cp++ = '\0';
129+ ccs_network_ip = inet_addr(ptr);
130+ ccs_network_port = htons(atoi(cp));
131+ if (ccs_network_mode) {
132+ fprintf(stderr, "You cannot specify multiple "
133+ "%s at the same time.\n\n",
134+ "remote agents");
135+ goto usage;
136+ }
137+ ccs_network_mode = true;
138+ } else if (*ptr++ == '-' && !*ptr) {
139+ if (ccs_policy_dir || use_stdout)
140+ goto usage;
141+ use_stdout = true;
142+ } else
143+ goto usage;
144+ }
145+ if (ccs_network_mode) {
146+ if (!ccs_check_remote_host())
147+ return 1;
148+ } else if (access(CCS_PROC_POLICY_DIR, F_OK)) {
149+ fprintf(stderr,
150+ "You can't run this program for this kernel.\n");
151+ return 1;
152+ }
153+ if (use_stdout)
154+ return !ccs_cat_file(CCS_PROC_POLICY_POLICY);
155+ if (!ccs_policy_dir) {
156+ if (ccs_network_mode && !use_stdout) {
157+ fprintf(stderr, "You need to specify %s.\n\n",
158+ "policy directory");
159+ goto usage;
160+ }
161+ ccs_policy_dir = "/etc/caitsith/";
162+ }
163+ if (chdir(ccs_policy_dir) || chdir("policy/")) {
164+ fprintf(stderr, "Directory %s/policy/ doesn't exist.\n",
165+ ccs_policy_dir);
166+ return 1;
167+ }
168+ return !ccs_save_policy();
169+usage:
170+ printf("%s [policy_dir|-] [remote_ip:remote_port]]\n\n"
171+ "policy_dir : Use policy_dir rather than /etc/caitsith/ directory.\n"
172+ "- : Print /proc/caitsith/policy to stdout.\n"
173+ "remote_ip:remote_port : Read from caitsith-agent "
174+ "listening at remote_ip:remote_port rather than /proc/caitsith/ "
175+ "directory.\n", argv[0]);
176+ return 1;
177+}
--- trunk/caitsith-tools/usr_sbin/caitsith-loadpolicy.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsith-loadpolicy.c (revision 2)
@@ -0,0 +1,105 @@
1+/*
2+ * caitsith-loadpolicy.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+/**
26+ * ccs_close_write - Close stream opened by ccs_open_write().
27+ *
28+ * @fp: Pointer to "FILE".
29+ *
30+ * Returns true on success, false otherwise.
31+ */
32+static _Bool ccs_close_write(FILE *fp)
33+{
34+ _Bool result = true;
35+ if (ccs_network_mode) {
36+ if (fputc(0, fp) == EOF)
37+ result = false;
38+ if (fflush(fp) == EOF)
39+ result = false;
40+ if (fgetc(fp) == EOF)
41+ result = false;
42+ }
43+ if (fclose(fp) == EOF)
44+ result = false;
45+ return result;
46+}
47+
48+static _Bool ccs_move_file_to_proc(const char *dest)
49+{
50+ FILE *proc_fp = ccs_open_write(dest);
51+ _Bool result = true;
52+ if (!proc_fp) {
53+ fprintf(stderr, "Can't open %s for writing.\n", dest);
54+ return false;
55+ }
56+ ccs_get();
57+ while (true) {
58+ char *line = ccs_freadline(stdin);
59+ if (!line)
60+ break;
61+ if (line[0])
62+ if (fprintf(proc_fp, "%s\n", line) < 0)
63+ result = false;
64+ }
65+ ccs_put();
66+ if (!ccs_close_write(proc_fp))
67+ result = false;
68+ return result;
69+}
70+
71+int main(int argc, char *argv[])
72+{
73+ int i;
74+ for (i = 1; i < argc; i++) {
75+ char *ptr = argv[i];
76+ char *cp = strchr(ptr, ':');
77+ if (!cp)
78+ goto usage;
79+ *cp++ = '\0';
80+ ccs_network_ip = inet_addr(ptr);
81+ ccs_network_port = htons(atoi(cp));
82+ if (ccs_network_mode) {
83+ fprintf(stderr, "You cannot specify multiple "
84+ "%s at the same time.\n\n",
85+ "remote agents");
86+ goto usage;
87+ }
88+ ccs_network_mode = true;
89+ }
90+ if (ccs_network_mode) {
91+ if (!ccs_check_remote_host())
92+ return 1;
93+ } else if (access(CCS_PROC_POLICY_DIR, F_OK)) {
94+ fprintf(stderr,
95+ "You can't run this program for this kernel.\n");
96+ return 1;
97+ }
98+ return !ccs_move_file_to_proc(CCS_PROC_POLICY_POLICY);
99+usage:
100+ printf("%s [remote_ip:remote_port]\n\n"
101+ "remote_ip:remote_port : Write to caitsith-agent listening at "
102+ "remote_ip:remote_port rather than /proc/caitsith/ "
103+ "directory.\n", argv[0]);
104+ return 1;
105+}
--- trunk/caitsith-tools/usr_sbin/caitsith-pstree.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsith-pstree.c (revision 2)
@@ -0,0 +1,383 @@
1+/*
2+ * caitsith-pstree.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+struct ccs_task_entry {
26+ pid_t pid;
27+ pid_t ppid;
28+ char *name;
29+ char *domain;
30+ _Bool selected;
31+ int index;
32+ int depth;
33+};
34+
35+/* The list of processes currently running. */
36+static struct ccs_task_entry *ccs_task_list = NULL;
37+/* The length of ccs_task_list . */
38+static int ccs_task_list_len = 0;
39+
40+/* Serial number for sorting ccs_task_list . */
41+static int ccs_dump_index = 0;
42+
43+/**
44+ * ccs_sort_process_entry - Sort ccs_tasklist list.
45+ *
46+ * @pid: Pid to search.
47+ * @depth: Depth of the process for printing like pstree command.
48+ *
49+ * Returns nothing.
50+ */
51+static void ccs_sort_process_entry(const pid_t pid, const int depth)
52+{
53+ int i;
54+ for (i = 0; i < ccs_task_list_len; i++) {
55+ if (pid != ccs_task_list[i].pid)
56+ continue;
57+ ccs_task_list[i].index = ccs_dump_index++;
58+ ccs_task_list[i].depth = depth;
59+ ccs_task_list[i].selected = true;
60+ }
61+ for (i = 0; i < ccs_task_list_len; i++) {
62+ if (pid != ccs_task_list[i].ppid)
63+ continue;
64+ ccs_sort_process_entry(ccs_task_list[i].pid, depth + 1);
65+ }
66+}
67+
68+/**
69+ * ccs_task_entry_compare - Compare routine for qsort() callback.
70+ *
71+ * @a: Pointer to "void".
72+ * @b: Pointer to "void".
73+ *
74+ * Returns index diff value.
75+ */
76+static int ccs_task_entry_compare(const void *a, const void *b)
77+{
78+ const struct ccs_task_entry *a0 = (struct ccs_task_entry *) a;
79+ const struct ccs_task_entry *b0 = (struct ccs_task_entry *) b;
80+ return a0->index - b0->index;
81+}
82+
83+/**
84+ * ccs_add_process_entry - Add entry for running processes.
85+ *
86+ * @line: A line containing PID and domainname.
87+ * @ppid: Parent PID.
88+ * @name: Comm name (allocated by strdup()).
89+ *
90+ * Returns nothing.
91+ *
92+ * @name is free()d on failure.
93+ */
94+static void ccs_add_process_entry(const char *line, const pid_t ppid,
95+ char *name)
96+{
97+ int index;
98+ unsigned int pid = 0;
99+ char *domain;
100+ if (!line || sscanf(line, "%u", &pid) != 1) {
101+ free(name);
102+ return;
103+ }
104+ domain = strchr(line, ' ');
105+ if (domain++)
106+ domain = ccs_strdup(domain);
107+ else
108+ domain = ccs_strdup("<UNKNOWN>");
109+ index = ccs_task_list_len++;
110+ ccs_task_list = ccs_realloc(ccs_task_list, ccs_task_list_len *
111+ sizeof(struct ccs_task_entry));
112+ memset(&ccs_task_list[index], 0, sizeof(ccs_task_list[0]));
113+ ccs_task_list[index].pid = pid;
114+ ccs_task_list[index].ppid = ppid;
115+ ccs_task_list[index].name = name;
116+ ccs_task_list[index].domain = domain;
117+}
118+
119+/**
120+ * ccs_get_ppid - Get PPID of the given PID.
121+ *
122+ * @pid: A pid_t value.
123+ *
124+ * Returns PPID value.
125+ */
126+static pid_t ccs_get_ppid(const pid_t pid)
127+{
128+ char buffer[1024];
129+ FILE *fp;
130+ pid_t ppid = 1;
131+ memset(buffer, 0, sizeof(buffer));
132+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/status", pid);
133+ fp = fopen(buffer, "r");
134+ if (fp) {
135+ while (memset(buffer, 0, sizeof(buffer)) &&
136+ fgets(buffer, sizeof(buffer) - 1, fp)) {
137+ if (sscanf(buffer, "PPid: %u", &ppid) == 1)
138+ break;
139+ }
140+ fclose(fp);
141+ }
142+ return ppid;
143+}
144+
145+/**
146+ * ccs_get_name - Get comm name of the given PID.
147+ *
148+ * @pid: A pid_t value.
149+ *
150+ * Returns comm name using on success, NULL otherwise.
151+ *
152+ * The caller must free() the returned pointer.
153+ */
154+static char *ccs_get_name(const pid_t pid)
155+{
156+ char buffer[1024];
157+ FILE *fp;
158+ memset(buffer, 0, sizeof(buffer));
159+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/status", pid);
160+ fp = fopen(buffer, "r");
161+ if (fp) {
162+ static const int offset = sizeof(buffer) / 6;
163+ while (memset(buffer, 0, sizeof(buffer)) &&
164+ fgets(buffer, sizeof(buffer) - 1, fp)) {
165+ if (!strncmp(buffer, "Name:\t", 6)) {
166+ char *cp = buffer + 6;
167+ memmove(buffer, cp, strlen(cp) + 1);
168+ cp = strchr(buffer, '\n');
169+ if (cp)
170+ *cp = '\0';
171+ break;
172+ }
173+ }
174+ fclose(fp);
175+ if (buffer[0] && strlen(buffer) < offset - 1) {
176+ const char *src = buffer;
177+ char *dest = buffer + offset;
178+ while (1) {
179+ unsigned char c = *src++;
180+ if (!c) {
181+ *dest = '\0';
182+ break;
183+ }
184+ if (c == '\\') {
185+ c = *src++;
186+ if (c == '\\') {
187+ memmove(dest, "\\134", 4);
188+ dest += 4;
189+ } else if (c == 'n') {
190+ memmove(dest, "\\012", 4);
191+ dest += 4;
192+ } else {
193+ break;
194+ }
195+ } else if (c > ' ' && c <= 126) {
196+ *dest++ = c;
197+ } else {
198+ *dest++ = '\\';
199+ *dest++ = (c >> 6) + '0';
200+ *dest++ = ((c >> 3) & 7) + '0';
201+ *dest++ = (c & 7) + '0';
202+ }
203+ }
204+ return strdup(buffer + offset);
205+ }
206+ }
207+ return NULL;
208+}
209+
210+/**
211+ * ccs_read_process_list - Read all process's information.
212+ *
213+ * @show_all: Ture if kernel threads should be included, false otherwise.
214+ *
215+ * Returns nothing.
216+ */
217+static void ccs_read_process_list(_Bool show_all)
218+{
219+ int i;
220+ while (ccs_task_list_len) {
221+ ccs_task_list_len--;
222+ free((void *) ccs_task_list[ccs_task_list_len].name);
223+ free((void *) ccs_task_list[ccs_task_list_len].domain);
224+ }
225+ ccs_dump_index = 0;
226+ if (ccs_network_mode) {
227+ FILE *fp = ccs_open_write(show_all ?
228+ "proc:all_process_status" :
229+ "proc:process_status");
230+ if (!fp)
231+ return;
232+ ccs_get();
233+ while (true) {
234+ char *line = ccs_freadline(fp);
235+ unsigned int pid = 0;
236+ unsigned int ppid = 0;
237+ char *name;
238+ if (!line)
239+ break;
240+ sscanf(line, "PID=%u PPID=%u", &pid, &ppid);
241+ name = strstr(line, "NAME=");
242+ if (name)
243+ name = ccs_strdup(name + 5);
244+ else
245+ name = ccs_strdup("<UNKNOWN>");
246+ line = ccs_freadline(fp);
247+ ccs_add_process_entry(line, ppid, name);
248+ }
249+ ccs_put();
250+ fclose(fp);
251+ } else {
252+ static const int line_len = 8192;
253+ char *line;
254+ int status_fd = open(CCS_PROC_POLICY_PROCESS_STATUS, O_RDWR);
255+ DIR *dir = opendir("/proc/");
256+ if (status_fd == EOF || !dir) {
257+ if (status_fd != EOF)
258+ close(status_fd);
259+ if (dir)
260+ closedir(dir);
261+ return;
262+ }
263+ line = ccs_malloc(line_len);
264+ while (1) {
265+ char *name;
266+ int ret_ignored;
267+ unsigned int pid = 0;
268+ char buffer[128];
269+ char test[16];
270+ struct dirent *dent = readdir(dir);
271+ if (!dent)
272+ break;
273+ if (dent->d_type != DT_DIR ||
274+ sscanf(dent->d_name, "%u", &pid) != 1 || !pid)
275+ continue;
276+ memset(buffer, 0, sizeof(buffer));
277+ if (!show_all) {
278+ snprintf(buffer, sizeof(buffer) - 1,
279+ "/proc/%u/exe", pid);
280+ if (readlink(buffer, test, sizeof(test)) <= 0)
281+ continue;
282+ }
283+ name = ccs_get_name(pid);
284+ if (!name)
285+ name = ccs_strdup("<UNKNOWN>");
286+ snprintf(buffer, sizeof(buffer) - 1, "%u\n", pid);
287+ ret_ignored = write(status_fd, buffer, strlen(buffer));
288+ memset(line, 0, line_len);
289+ ret_ignored = read(status_fd, line, line_len - 1);
290+ ccs_add_process_entry(line, ccs_get_ppid(pid), name);
291+ }
292+ free(line);
293+ closedir(dir);
294+ close(status_fd);
295+ }
296+ ccs_sort_process_entry(1, 0);
297+ for (i = 0; i < ccs_task_list_len; i++) {
298+ if (ccs_task_list[i].selected) {
299+ ccs_task_list[i].selected = false;
300+ continue;
301+ }
302+ ccs_task_list[i].index = ccs_dump_index++;
303+ ccs_task_list[i].depth = 0;
304+ }
305+ qsort(ccs_task_list, ccs_task_list_len, sizeof(struct ccs_task_entry),
306+ ccs_task_entry_compare);
307+}
308+
309+static void ccs_dump(const pid_t pid, const int depth)
310+{
311+ int i;
312+ for (i = 0; i < ccs_task_list_len; i++) {
313+ int j;
314+ if (pid != ccs_task_list[i].pid)
315+ continue;
316+ for (j = 0; j < depth - 1; j++)
317+ printf(" ");
318+ for (; j < depth; j++)
319+ printf(" +-");
320+ printf(" %s (%u) %s\n", ccs_task_list[i].name,
321+ ccs_task_list[i].pid, ccs_task_list[i].domain);
322+ ccs_task_list[i].selected = true;
323+ }
324+ for (i = 0; i < ccs_task_list_len; i++) {
325+ if (pid != ccs_task_list[i].ppid)
326+ continue;
327+ ccs_dump(ccs_task_list[i].pid, depth + 1);
328+ }
329+}
330+
331+int main(int argc, char *argv[])
332+{
333+ static _Bool show_all = false;
334+ int i;
335+ for (i = 1; i < argc; i++) {
336+ char *ptr = argv[i];
337+ char *cp = strchr(ptr, ':');
338+ if (cp) {
339+ *cp++ = '\0';
340+ if (ccs_network_mode)
341+ goto usage;
342+ ccs_network_ip = inet_addr(ptr);
343+ ccs_network_port = htons(atoi(cp));
344+ ccs_network_mode = true;
345+ if (!ccs_check_remote_host())
346+ return 1;
347+ } else if (!strcmp(ptr, "-a")) {
348+ show_all = true;
349+ } else {
350+usage:
351+ fprintf(stderr, "Usage: %s "
352+ "[-a] [remote_ip:remote_port]\n", argv[0]);
353+ return 0;
354+ }
355+ }
356+ ccs_read_process_list(show_all);
357+ if (!ccs_task_list_len) {
358+ if (ccs_network_mode) {
359+ fprintf(stderr, "Can't connect.\n");
360+ return 1;
361+ } else {
362+ fprintf(stderr, "You can't use this command "
363+ "for this kernel.\n");
364+ return 1;
365+ }
366+ }
367+ ccs_dump(1, 0);
368+ for (i = 0; i < ccs_task_list_len; i++) {
369+ if (ccs_task_list[i].selected)
370+ continue;
371+ printf(" %s (%u) %s\n", ccs_task_list[i].name,
372+ ccs_task_list[i].pid, ccs_task_list[i].domain);
373+ ccs_task_list[i].selected = true;
374+ }
375+ while (ccs_task_list_len) {
376+ ccs_task_list_len--;
377+ free((void *) ccs_task_list[ccs_task_list_len].name);
378+ free((void *) ccs_task_list[ccs_task_list_len].domain);
379+ }
380+ free(ccs_task_list);
381+ ccs_task_list = NULL;
382+ return 0;
383+}
--- trunk/caitsith-tools/usr_sbin/readline.h (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/readline.h (revision 2)
@@ -0,0 +1,303 @@
1+/*
2+ * readline.h
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include <ncurses.h>
24+
25+static int ccs_getch0(void)
26+{
27+ static int enter_key = EOF;
28+ int c;
29+again:
30+ c = getch();
31+ if (c == 127 || c == 8)
32+ c = KEY_BACKSPACE;
33+ /* syslog(LOG_INFO, "ccs_getch0='%c' (%d)\n", c, c); */
34+ if (c == '\r' || c == '\n') {
35+ if (enter_key == EOF)
36+ enter_key = c;
37+ else if (c != enter_key)
38+ goto again;
39+ }
40+ return c;
41+}
42+
43+static int ccs_getch2(void)
44+{
45+ static int c0 = 0;
46+ static int c1 = 0;
47+ static int c2 = 0;
48+ static int c3 = 0;
49+ static int len = 0;
50+ if (len > 0) {
51+ c0 = c1;
52+ c1 = c2;
53+ c2 = c3;
54+ len--;
55+ return c0;
56+ }
57+ c0 = ccs_getch0();
58+ if (c0 != 0x1B)
59+ return c0;
60+ c1 = ccs_getch0();
61+ if (c1 != '[') {
62+ len = 1;
63+ return c0;
64+ }
65+ c2 = ccs_getch0();
66+ if (c2 < '1' || c2 > '6') {
67+ len = 2;
68+ return c0;
69+ }
70+ c3 = ccs_getch0();
71+ if (c3 != '~') {
72+ len = 3;
73+ return c0;
74+ }
75+ /* syslog(LOG_INFO, "ccs_getch2='%c'\n", c2); */
76+ switch (c2) {
77+ case '1':
78+ return KEY_HOME;
79+ case '2':
80+ return KEY_IC;
81+ case '3':
82+ return KEY_DC;
83+ case '4':
84+ return KEY_END;
85+ case '5':
86+ return KEY_PPAGE;
87+ case '6':
88+ return KEY_NPAGE;
89+ }
90+ return 0;
91+}
92+
93+static int ccs_add_history(const char *buffer, const char **history,
94+ const int history_count, const int max_history)
95+{
96+ char *cp = buffer ? strdup(buffer) : NULL;
97+ if (!cp)
98+ return history_count;
99+ if (history_count && !strcmp(history[history_count - 1], cp)) {
100+ free(cp);
101+ return history_count;
102+ }
103+ if (history_count < max_history) {
104+ history[history_count] = cp;
105+ return history_count + 1;
106+ } else if (max_history) {
107+ int i;
108+ free((char *) history[0]);
109+ for (i = 0; i < history_count - 1; i++)
110+ history[i] = history[i + 1];
111+ history[history_count - 1] = cp;
112+ return history_count;
113+ }
114+ return 0;
115+}
116+
117+static int ccs_query_fd = EOF;
118+static char *ccs_initial_readline_data = NULL;
119+
120+static char *ccs_readline(const int start_y, const int start_x,
121+ const char *prompt, const char *history[],
122+ const int history_count, const int max_length,
123+ const int scroll_width)
124+{
125+ const int prompt_len = prompt ? strlen(prompt) : 0;
126+ int buffer_len = 0;
127+ int line_pos = 0;
128+ int cur_pos = 0;
129+ int history_pos = 0;
130+ _Bool tmp_saved = false;
131+ static char *buffer = NULL;
132+ static char *tmp_buffer = NULL;
133+ {
134+ int i;
135+ for (i = 0; i < history_count; i++)
136+ if (!history[i])
137+ return NULL;
138+ }
139+ {
140+ char *tmp;
141+ tmp = realloc(buffer, max_length + 1);
142+ if (!tmp)
143+ return NULL;
144+ buffer = tmp;
145+ tmp = realloc(tmp_buffer, max_length + 1);
146+ if (!tmp)
147+ return NULL;
148+ tmp_buffer = tmp;
149+ memset(buffer, 0, max_length + 1);
150+ memset(tmp_buffer, 0, max_length + 1);
151+ }
152+ move(start_y, start_x);
153+ history_pos = history_count;
154+ if (ccs_initial_readline_data) {
155+ strncpy(buffer, ccs_initial_readline_data, max_length);
156+ buffer_len = strlen(buffer);
157+ ungetch(KEY_END);
158+ }
159+ while (true) {
160+ int window_width;
161+ int window_height;
162+ int c;
163+ int x;
164+ int y;
165+ int i;
166+ int ret_ignored;
167+ getmaxyx(stdscr, window_height, window_width);
168+ window_width -= prompt_len;
169+ getyx(stdscr, y, x);
170+ move(y, 0);
171+ while (cur_pos > window_width - 1) {
172+ cur_pos--;
173+ line_pos++;
174+ }
175+ if (prompt_len)
176+ printw("%s", prompt);
177+ for (i = line_pos; i < line_pos + window_width; i++) {
178+ if (i < buffer_len)
179+ addch(buffer[i]);
180+ else
181+ break;
182+ }
183+ clrtoeol();
184+ move(y, cur_pos + prompt_len);
185+ refresh();
186+ c = ccs_getch2();
187+ if (ccs_query_fd != EOF)
188+ ret_ignored = write(ccs_query_fd, "\n", 1);
189+ if (c == 4) { /* Ctrl-D */
190+ if (!buffer_len)
191+ buffer_len = -1;
192+ break;
193+ } else if (c == KEY_IC) {
194+ scrollok(stdscr, TRUE);
195+ printw("\n");
196+ for (i = 0; i < history_count; i++)
197+ printw("%d: '%s'\n", i, history[i]);
198+ scrollok(stdscr, FALSE);
199+ } else if (c >= 0x20 && c <= 0x7E &&
200+ buffer_len < max_length - 1) {
201+ for (i = buffer_len - 1; i >= line_pos + cur_pos; i--)
202+ buffer[i + 1] = buffer[i];
203+ buffer[line_pos + cur_pos] = c;
204+ buffer[++buffer_len] = '\0';
205+ if (cur_pos < window_width - 1)
206+ cur_pos++;
207+ else
208+ line_pos++;
209+ } else if (c == '\r' || c == '\n') {
210+ break;
211+ } else if (c == KEY_BACKSPACE) {
212+ if (line_pos + cur_pos) {
213+ buffer_len--;
214+ for (i = line_pos + cur_pos - 1;
215+ i < buffer_len; i++)
216+ buffer[i] = buffer[i + 1];
217+ buffer[buffer_len] = '\0';
218+ if (line_pos >= scroll_width && cur_pos == 0) {
219+ line_pos -= scroll_width;
220+ cur_pos += scroll_width - 1;
221+ } else if (cur_pos) {
222+ cur_pos--;
223+ } else if (line_pos) {
224+ line_pos--;
225+ }
226+ }
227+ } else if (c == KEY_DC) {
228+ if (line_pos + cur_pos < buffer_len) {
229+ buffer_len--;
230+ for (i = line_pos + cur_pos; i < buffer_len;
231+ i++)
232+ buffer[i] = buffer[i + 1];
233+ buffer[buffer_len] = '\0';
234+ }
235+ } else if (c == KEY_UP) {
236+ if (history_pos) {
237+ if (!tmp_saved) {
238+ tmp_saved = true;
239+ strncpy(tmp_buffer, buffer,
240+ max_length);
241+ }
242+ history_pos--;
243+ strncpy(buffer, history[history_pos],
244+ max_length);
245+ buffer_len = strlen(buffer);
246+ goto end_key;
247+ }
248+ } else if (c == KEY_DOWN) {
249+ if (history_pos < history_count - 1) {
250+ history_pos++;
251+ strncpy(buffer, history[history_pos],
252+ max_length);
253+ buffer_len = strlen(buffer);
254+ goto end_key;
255+ } else if (tmp_saved) {
256+ tmp_saved = false;
257+ history_pos = history_count;
258+ strncpy(buffer, tmp_buffer, max_length);
259+ buffer_len = strlen(buffer);
260+ goto end_key;
261+ }
262+ } else if (c == KEY_HOME) {
263+ cur_pos = 0;
264+ line_pos = 0;
265+ } else if (c == KEY_END) {
266+ goto end_key;
267+ } else if (c == KEY_LEFT) {
268+ if (line_pos >= scroll_width && cur_pos == 0) {
269+ line_pos -= scroll_width;
270+ cur_pos += scroll_width - 1;
271+ } else if (cur_pos) {
272+ cur_pos--;
273+ } else if (line_pos) {
274+ line_pos--;
275+ }
276+ } else if (c == KEY_RIGHT) {
277+ if (line_pos + cur_pos < buffer_len) {
278+ if (cur_pos < window_width - 1)
279+ cur_pos++;
280+ else if (line_pos + cur_pos <
281+ buffer_len - scroll_width &&
282+ cur_pos >= scroll_width - 1) {
283+ cur_pos -= scroll_width - 1;
284+ line_pos += scroll_width;
285+ } else {
286+ line_pos++;
287+ }
288+ }
289+ }
290+ continue;
291+end_key:
292+ cur_pos = buffer_len;
293+ line_pos = 0;
294+ if (cur_pos > window_width - 1) {
295+ line_pos = buffer_len - (window_width - 1);
296+ cur_pos = window_width - 1;
297+ }
298+ }
299+ if (buffer_len == -1)
300+ return NULL;
301+ ccs_normalize_line(buffer);
302+ return strdup(buffer);
303+}
--- trunk/caitsith-tools/usr_sbin/caitsithtools.c (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/caitsithtools.c (revision 2)
@@ -0,0 +1,372 @@
1+/*
2+ * caitsithtools.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include "caitsithtools.h"
24+
25+/* Use caitsith-agent process? */
26+_Bool ccs_network_mode = false;
27+/* The IPv4 address of the remote host running the caitsith-agent . */
28+u32 ccs_network_ip = INADDR_NONE;
29+/* The port number of the remote host running the caitsith-agent . */
30+u16 ccs_network_port = 0;
31+
32+/* Prototypes */
33+
34+/* Utility functions */
35+
36+/**
37+ * ccs_out_of_memory - Print error message and abort.
38+ *
39+ * This function does not return.
40+ */
41+static void ccs_out_of_memory(void)
42+{
43+ fprintf(stderr, "Out of memory. Aborted.\n");
44+ exit(1);
45+}
46+
47+/**
48+ * ccs_strdup - strdup() with abort on error.
49+ *
50+ * @string: String to duplicate.
51+ *
52+ * Returns copy of @string on success, abort otherwise.
53+ */
54+char *ccs_strdup(const char *string)
55+{
56+ char *cp = strdup(string);
57+ if (!cp)
58+ ccs_out_of_memory();
59+ return cp;
60+}
61+
62+/**
63+ * ccs_realloc - realloc() with abort on error.
64+ *
65+ * @ptr: Pointer to void.
66+ * @size: New size.
67+ *
68+ * Returns return value of realloc() on success, abort otherwise.
69+ */
70+void *ccs_realloc(void *ptr, const size_t size)
71+{
72+ void *vp = realloc(ptr, size);
73+ if (!vp)
74+ ccs_out_of_memory();
75+ return vp;
76+}
77+
78+/**
79+ * ccs_malloc - malloc() with abort on error.
80+ *
81+ * @size: Size to allocate.
82+ *
83+ * Returns return value of malloc() on success, abort otherwise.
84+ *
85+ * Allocated memory is cleared with 0.
86+ */
87+void *ccs_malloc(const size_t size)
88+{
89+ void *vp = malloc(size);
90+ if (!vp)
91+ ccs_out_of_memory();
92+ memset(vp, 0, size);
93+ return vp;
94+}
95+
96+/**
97+ * ccs_str_starts - Check whether the given string starts with the given keyword.
98+ *
99+ * @str: Pointer to "char *".
100+ * @begin: Pointer to "const char *".
101+ *
102+ * Returns true if @str starts with @begin, false otherwise.
103+ *
104+ * Note that @begin will be removed from @str before returning true. Therefore,
105+ * @str must not be "const char *".
106+ *
107+ * Note that this function in kernel source has different arguments and behaves
108+ * differently.
109+ */
110+_Bool ccs_str_starts(char *str, const char *begin)
111+{
112+ const int len = strlen(begin);
113+ if (strncmp(str, begin, len))
114+ return false;
115+ memmove(str, str + len, strlen(str + len) + 1);
116+ return true;
117+}
118+
119+/**
120+ * ccs_normalize_line - Format string.
121+ *
122+ * @buffer: The line to normalize.
123+ *
124+ * Returns nothing.
125+ *
126+ * Leading and trailing whitespaces are removed.
127+ * Multiple whitespaces are packed into single space.
128+ */
129+void ccs_normalize_line(char *buffer)
130+{
131+ unsigned char *sp = (unsigned char *) buffer;
132+ unsigned char *dp = (unsigned char *) buffer;
133+ _Bool first = true;
134+ while (*sp && (*sp <= ' ' || 127 <= *sp))
135+ sp++;
136+ while (*sp) {
137+ if (!first)
138+ *dp++ = ' ';
139+ first = false;
140+ while (' ' < *sp && *sp < 127)
141+ *dp++ = *sp++;
142+ while (*sp && (*sp <= ' ' || 127 <= *sp))
143+ sp++;
144+ }
145+ *dp = '\0';
146+}
147+
148+/**
149+ * ccs_decode - Decode a string in CaitSith's rule to a string in C.
150+ *
151+ * @ascii: Pointer to "const char".
152+ * @bin: Pointer to "char". Must not contain wildcards nor '\000'.
153+ *
154+ * Returns true if @ascii was successfully decoded, false otherwise.
155+ *
156+ * Note that it is legal to pass @ascii == @bin if the caller want to decode
157+ * a string in a temporary buffer.
158+ */
159+_Bool ccs_decode(const char *ascii, char *bin)
160+{
161+ while (true) {
162+ char c = *ascii++;
163+ *bin++ = c;
164+ if (!c)
165+ break;
166+ if (c == '\\') {
167+ char d;
168+ char e;
169+ u8 f;
170+ c = *ascii++;
171+ switch (c) {
172+ case '0': /* "\ooo" */
173+ case '1':
174+ case '2':
175+ case '3':
176+ d = *ascii++;
177+ if (d < '0' || d > '7')
178+ break;
179+ e = *ascii++;
180+ if (e < '0' || e > '7')
181+ break;
182+ f = (u8) ((c - '0') << 6) +
183+ (((u8) (d - '0')) << 3) +
184+ (((u8) (e - '0')));
185+ if (f <= ' ' || f >= 127 || f == '\\') {
186+ *(bin - 1) = f;
187+ continue;
188+ }
189+ }
190+ return false;
191+ } else if (c <= ' ' || c >= 127) {
192+ return false;
193+ }
194+ }
195+ return true;
196+}
197+
198+/**
199+ * ccs_open_read - Open a file for reading.
200+ *
201+ * @filename: String to send to remote caitsith-agent program if using
202+ * network mode, file to open for reading otherwise.
203+ *
204+ * Returns pointer to "FILE" on success, NULL otherwise.
205+ */
206+FILE *ccs_open_read(const char *filename)
207+{
208+ if (ccs_network_mode) {
209+ FILE *fp = ccs_open_write(filename);
210+ if (fp) {
211+ fputc(0, fp);
212+ fflush(fp);
213+ }
214+ return fp;
215+ } else {
216+ return fopen(filename, "r");
217+ }
218+}
219+
220+/**
221+ * ccs_open_stream - Establish IP connection.
222+ *
223+ * @filename: String to send to remote caitsith-agent program.
224+ *
225+ * Retruns file descriptor on success, EOF otherwise.
226+ */
227+int ccs_open_stream(const char *filename)
228+{
229+ const int fd = socket(AF_INET, SOCK_STREAM, 0);
230+ struct sockaddr_in addr;
231+ char c;
232+ int len = strlen(filename) + 1;
233+ memset(&addr, 0, sizeof(addr));
234+ addr.sin_family = AF_INET;
235+ addr.sin_addr.s_addr = ccs_network_ip;
236+ addr.sin_port = ccs_network_port;
237+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) ||
238+ write(fd, filename, len) != len || read(fd, &c, 1) != 1 || c) {
239+ close(fd);
240+ return EOF;
241+ }
242+ return fd;
243+}
244+
245+/**
246+ * ccs_open_write - Open a file for writing.
247+ *
248+ * @filename: String to send to remote caitsith-agent program if using
249+ * network mode, file to open for writing otherwise.
250+ *
251+ * Returns pointer to "FILE" on success, NULL otherwise.
252+ */
253+FILE *ccs_open_write(const char *filename)
254+{
255+ if (ccs_network_mode) {
256+ const int fd = socket(AF_INET, SOCK_STREAM, 0);
257+ struct sockaddr_in addr;
258+ FILE *fp;
259+ memset(&addr, 0, sizeof(addr));
260+ addr.sin_family = AF_INET;
261+ addr.sin_addr.s_addr = ccs_network_ip;
262+ addr.sin_port = ccs_network_port;
263+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr))) {
264+ close(fd);
265+ return NULL;
266+ }
267+ fp = fdopen(fd, "r+");
268+ /* setbuf(fp, NULL); */
269+ fprintf(fp, "%s", filename);
270+ fputc(0, fp);
271+ fflush(fp);
272+ if (fgetc(fp) != 0) {
273+ fclose(fp);
274+ return NULL;
275+ }
276+ return fp;
277+ } else {
278+ return fdopen(open(filename, O_WRONLY), "w");
279+ }
280+}
281+
282+/* Is the shared buffer for ccs_freadline() owned? */
283+static _Bool ccs_buffer_locked = false;
284+
285+/**
286+ * ccs_get - Mark the shared buffer for ccs_freadline() owned.
287+ *
288+ * Returns nothing.
289+ *
290+ * This is for avoiding accidental overwriting.
291+ * ccs_freadline() have their own memory buffer.
292+ */
293+void ccs_get(void)
294+{
295+ if (ccs_buffer_locked)
296+ ccs_out_of_memory();
297+ ccs_buffer_locked = true;
298+}
299+
300+/**
301+ * ccs_put - Mark the shared buffer for ccs_freadline() no longer owned.
302+ *
303+ * Returns nothing.
304+ *
305+ * This is for avoiding accidental overwriting.
306+ * ccs_freadline() have their own memory buffer.
307+ */
308+void ccs_put(void)
309+{
310+ if (!ccs_buffer_locked)
311+ ccs_out_of_memory();
312+ ccs_buffer_locked = false;
313+}
314+
315+/**
316+ * ccs_freadline - Read a line from file to dynamically allocated buffer.
317+ *
318+ * @fp: Pointer to "FILE".
319+ *
320+ * Returns pointer to dynamically allocated buffer on success, NULL otherwise.
321+ *
322+ * The caller must not free() the returned pointer.
323+ */
324+char *ccs_freadline(FILE *fp)
325+{
326+ static char *policy = NULL;
327+ int pos = 0;
328+ while (true) {
329+ static int max_policy_len = 0;
330+ const int c = fgetc(fp);
331+ if (c == EOF)
332+ return NULL;
333+ if (ccs_network_mode && !c)
334+ return NULL;
335+ if (pos == max_policy_len) {
336+ max_policy_len += 4096;
337+ policy = ccs_realloc(policy, max_policy_len);
338+ }
339+ policy[pos++] = (char) c;
340+ if (c == '\n') {
341+ policy[--pos] = '\0';
342+ break;
343+ }
344+ }
345+ ccs_normalize_line(policy);
346+ return policy;
347+}
348+
349+/**
350+ * ccs_check_remote_host - Check whether the remote host is running with the CaitSith 0.1 kernel or not.
351+ *
352+ * Returns true if running with CaitSith 0.1 kernel, false otherwise.
353+ */
354+_Bool ccs_check_remote_host(void)
355+{
356+ int major = 0;
357+ int minor = 0;
358+ FILE *fp = ccs_open_read("version");
359+ if (!fp ||
360+ fscanf(fp, "%u.%u", &major, &minor) < 2 ||
361+ major != 0 || minor != 1) {
362+ const u32 ip = ntohl(ccs_network_ip);
363+ fprintf(stderr, "Can't connect to %u.%u.%u.%u:%u\n",
364+ (u8) (ip >> 24), (u8) (ip >> 16),
365+ (u8) (ip >> 8), (u8) ip, ntohs(ccs_network_port));
366+ if (fp)
367+ fclose(fp);
368+ return false;
369+ }
370+ fclose(fp);
371+ return true;
372+}
--- trunk/caitsith-tools/usr_sbin/Makefile (nonexistent)
+++ trunk/caitsith-tools/usr_sbin/Makefile (revision 2)
@@ -0,0 +1,38 @@
1+include ../Include.make
2+
3+BUILD_FILES := caitsith-auditd caitsith-loadpolicy caitsith-notifyd caitsith-pstree caitsith-queryd \
4+ caitsith-savepolicy
5+
6+all: libcaitsithtools.so $(BUILD_FILES)
7+
8+$(BUILD_FILES): libcaitsithtools.so
9+
10+/usr/include/curses.h:
11+ @echo "/usr/include/curses.h is missing."
12+ @echo "Run 'yum install ncurses-devel' or 'apt-get install libncurses-dev'"
13+ sleep 10
14+
15+libcaitsithtools.so: caitsithtools.c caitsithtools.h
16+ $(CC) $(CFLAGS) -fPIC caitsithtools.c -shared -Wl,-soname,libcaitsithtools.so.1 -o libcaitsithtools.so.1.0.0
17+ ln -sf libcaitsithtools.so.1.0.0 libcaitsithtools.so
18+
19+.c:
20+ $(CC) $(CFLAGS) -o $@ $< -lcaitsithtools -L.
21+
22+caitsith-queryd: caitsithtools.h caitsith-queryd.c readline.h /usr/include/curses.h libcaitsithtools.so
23+ $(CC) $(CFLAGS) -o caitsith-queryd caitsith-queryd.c -lncurses -lcaitsithtools -L.
24+
25+install: all
26+ mkdir -p -m 0755 $(INSTALLDIR)$(USRLIBDIR)
27+ $(INSTALL) -m 0755 libcaitsithtools.so.1.0.0 $(INSTALLDIR)$(USRLIBDIR)
28+ ln -sf libcaitsithtools.so.1.0.0 $(INSTALLDIR)$(USRLIBDIR)/libcaitsithtools.so.4
29+ifeq ($(INSTALLDIR),)
30+ ldconfig || true
31+endif
32+ mkdir -p -m 0755 $(INSTALLDIR)$(USRSBINDIR)
33+ $(INSTALL) -m 0755 $(BUILD_FILES) $(INSTALLDIR)$(USRSBINDIR)
34+
35+clean:
36+ rm -f -- $(BUILD_FILES) libcaitsithtools.so*
37+
38+.PHONY: clean install
--- trunk/caitsith-tools/usr_lib_caitsith/init_policy.c (nonexistent)
+++ trunk/caitsith-tools/usr_lib_caitsith/init_policy.c (revision 2)
@@ -0,0 +1,713 @@
1+/*
2+ * init_policy.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#define _FILE_OFFSET_BITS 64
24+#define _LARGEFILE_SOURCE
25+#define _LARGEFILE64_SOURCE
26+#include <stdio.h>
27+#include <string.h>
28+#include <stdlib.h>
29+#include <sys/types.h>
30+#include <sys/stat.h>
31+#include <unistd.h>
32+#include <dirent.h>
33+#include <limits.h>
34+#include <sys/vfs.h>
35+#include <time.h>
36+#include <errno.h>
37+
38+#if defined(__GLIBC__)
39+/**
40+ * get_realpath - Wrapper for realpath(3).
41+ *
42+ * @path: Pathname to resolve.
43+ *
44+ * Returns realpath of @path on success, NULL otherwise.
45+ *
46+ * Caller must free() the returned pointer if this function did not return
47+ * NULL.
48+ */
49+static inline char *get_realpath(const char *path)
50+{
51+ return realpath(path, NULL);
52+}
53+#else
54+/**
55+ * get_realpath - Fallback routine for realpath(3).
56+ *
57+ * @path: Pathname to resolve.
58+ *
59+ * Returns realpath of @path on success, NULL otherwise.
60+ *
61+ * realpath(@path, NULL) works on GLIBC, but will SIGSEGV on others.
62+ *
63+ * Caller must free() the returned pointer if this function did not return
64+ * NULL.
65+ */
66+static char *get_realpath(const char *path)
67+{
68+ struct stat buf;
69+ static const int pwd_len = PATH_MAX * 2;
70+ char *dir = strdup(path);
71+ char *pwd = malloc(pwd_len);
72+ char *basename = NULL;
73+ int len;
74+ if (!dir || !pwd)
75+ goto out;
76+ if (stat(dir, &buf))
77+ goto out;
78+ len = strlen(dir);
79+ while (len > 1 && dir[len - 1] == '/')
80+ dir[--len] = '\0';
81+ while (!lstat(dir, &buf) && S_ISLNK(buf.st_mode)) {
82+ char *new_dir;
83+ char *old_dir = dir;
84+ memset(pwd, 0, pwd_len);
85+ if (readlink(dir, pwd, pwd_len - 1) < 1)
86+ goto out;
87+ if (pwd[0] == '/') {
88+ dir[0] = '\0';
89+ } else {
90+ char *cp = strrchr(dir, '/');
91+ if (cp)
92+ *cp = '\0';
93+ }
94+ len = strlen(dir) + strlen(pwd) + 4;
95+ new_dir = malloc(len);
96+ if (new_dir)
97+ snprintf(new_dir, len - 1, "%s/%s", dir, pwd);
98+ dir = new_dir;
99+ free(old_dir);
100+ if (!dir)
101+ goto out;
102+ }
103+ if (!dir)
104+ goto out;
105+ basename = strrchr(dir, '/');
106+ if (basename)
107+ *basename++ = '\0';
108+ else
109+ basename = "";
110+ if (chdir(dir))
111+ goto out;
112+ memset(pwd, 0, pwd_len);
113+ if (!getcwd(pwd, pwd_len - 1))
114+ goto out;
115+ if (strcmp(pwd, "/"))
116+ len = strlen(pwd);
117+ else
118+ len = 0;
119+ snprintf(pwd + len, pwd_len - len - 1, "/%s", basename);
120+ free(dir);
121+ return pwd;
122+out:
123+ free(dir);
124+ free(pwd);
125+ return NULL;
126+}
127+#endif
128+
129+#define elementof(x) (sizeof(x) / sizeof(x[0]))
130+
131+/**
132+ * scandir_file_filter - Callback for scandir().
133+ *
134+ * @buf: Pointer to "const struct dirent".
135+ *
136+ * Returns non 0 if @buf seems to be a file, 0 otherwise.
137+ *
138+ * Since several kernels have a bug that leaves @buf->d_type == DT_UNKNOWN,
139+ * we allow it for now and recheck it later.
140+ */
141+static int scandir_file_filter(const struct dirent *buf)
142+{
143+ return (buf->d_type == DT_REG || buf->d_type == DT_UNKNOWN) &&
144+ strcmp(buf->d_name, ".") && strcmp(buf->d_name, "..");
145+}
146+
147+/**
148+ * revalidate_path - Recheck file's attribute.
149+ *
150+ * @path: Pathname to check.
151+ *
152+ * Returns type of @path.
153+ *
154+ * This is needed by buggy kernels that report DT_UNKNOWN upon scandir().
155+ */
156+static unsigned char revalidate_path(const char *path)
157+{
158+ struct stat buf;
159+ unsigned char type = DT_UNKNOWN;
160+ if (!lstat(path, &buf)) {
161+ if (S_ISREG(buf.st_mode))
162+ type = DT_REG;
163+ else if (S_ISDIR(buf.st_mode))
164+ type = DT_DIR;
165+ else if (S_ISLNK(buf.st_mode))
166+ type = DT_LNK;
167+ }
168+ return type;
169+}
170+
171+/* File handle to /etc/caitsith/policy/current . */
172+static FILE *filp = NULL;
173+
174+/**
175+ * printf_encoded - Print a word to the policy file, with escaping as needed.
176+ *
177+ * @str: Word to print. Needn't to follow CaitSith's escape rules.
178+ *
179+ * Returns nothing.
180+ *
181+ * If @str starts with "/proc/", it is converted with "proc:/".
182+ */
183+static void printf_encoded(const char *str)
184+{
185+ if (!strncmp(str, "/proc/", 6)) {
186+ fprintf(filp, "proc:");
187+ str += 5;
188+ }
189+ while (1) {
190+ const char c = *str++;
191+ if (!c)
192+ break;
193+ if (c > ' ' && c < 127 && c != '\\')
194+ fputc(c, filp);
195+ else
196+ fprintf(filp, "\\%c%c%c", (c >> 6) + '0',
197+ ((c >> 3) & 7) + '0', (c & 7) + '0');
198+ }
199+}
200+
201+static void make_default_domain_transition(const char *path)
202+{
203+ fprintf(filp, " 10 allow path=\"");
204+ printf_encoded(path);
205+ fprintf(filp, "\" transition=\"");
206+ printf_encoded(path);
207+ fprintf(filp, "\"\n");
208+}
209+
210+
211+/* Shared buffer for scandir(). */
212+static char path[8192];
213+
214+/**
215+ * scan_executable_files - Find executable files in the specific directory.
216+ *
217+ * @dir: Directory name to scan.
218+ *
219+ * Returns nothing.
220+ */
221+static void scan_executable_files(const char *dir)
222+{
223+ struct dirent **namelist;
224+ int n = scandir(dir, &namelist, scandir_file_filter, 0);
225+ int i;
226+ if (n < 0)
227+ return;
228+ for (i = 0; i < n; i++) {
229+ unsigned char type = namelist[i]->d_type;
230+ snprintf(path, sizeof(path) - 1, "%s/%s", dir,
231+ namelist[i]->d_name);
232+ if (type == DT_UNKNOWN)
233+ type = revalidate_path(path);
234+ if (type == DT_REG && !access(path, X_OK))
235+ make_default_domain_transition(path);
236+ free(namelist[i]);
237+ }
238+ free(namelist);
239+}
240+
241+/**
242+ * scan_modprobe_and_hotplug - Mark modprobe and hotplug as domain_transition entries.
243+ *
244+ * Returns nothing.
245+ */
246+static void scan_modprobe_and_hotplug(void)
247+{
248+ static const char * const files[2] = {
249+ "/proc/sys/kernel/modprobe", "/proc/sys/kernel/hotplug"
250+ };
251+ int i;
252+ for (i = 0; i < elementof(files); i++) {
253+ char *ret_ignored;
254+ char buffer[PATH_MAX + 1];
255+ char *cp;
256+ FILE *fp = fopen(files[i], "r");
257+ if (!fp)
258+ continue;
259+ memset(buffer, 0, sizeof(buffer));
260+ ret_ignored = fgets(buffer, sizeof(buffer) - 1, fp);
261+ fclose(fp);
262+ cp = strrchr(buffer, '\n');
263+ if (cp)
264+ *cp = '\0';
265+ if (!buffer[0])
266+ continue;
267+ cp = get_realpath(buffer);
268+ if (!cp)
269+ continue;
270+ /* We ignore /bin/true if /proc/sys/kernel/modprobe said so. */
271+ if (strcmp(cp, "/bin/true") && !access(cp, X_OK))
272+ make_default_domain_transition(cp);
273+ free(cp);
274+ }
275+}
276+
277+/**
278+ * scan_init_dir - Mark programs under /etc/init.d/ directory as default domain transition entries.
279+ *
280+ * Returns nothing.
281+ */
282+static void scan_init_dir(void)
283+{
284+ char *dir = get_realpath("/etc/init.d/");
285+ if (!dir)
286+ return;
287+ scan_executable_files(dir);
288+ free(dir);
289+}
290+
291+/**
292+ * scan_daemons - Mark daemon programs as default domain transition entries.
293+ *
294+ * Returns nothing.
295+ */
296+static void scan_daemons(void)
297+{
298+ static const char * const files[] = {
299+ "/sbin/cardmgr",
300+ "/sbin/getty",
301+ "/sbin/init",
302+ "/sbin/klogd",
303+ "/sbin/mingetty",
304+ "/sbin/portmap",
305+ "/sbin/rpc.statd",
306+ "/sbin/syslogd",
307+ "/sbin/udevd",
308+ "/usr/X11R6/bin/xfs",
309+ "/usr/bin/dbus-daemon",
310+ "/usr/bin/dbus-daemon-1",
311+ "/usr/bin/jserver",
312+ "/usr/bin/mDNSResponder",
313+ "/usr/bin/nifd",
314+ "/usr/bin/spamd",
315+ "/usr/sbin/acpid",
316+ "/usr/sbin/afpd",
317+ "/usr/sbin/anacron",
318+ "/usr/sbin/apache2",
319+ "/usr/sbin/apmd",
320+ "/usr/sbin/atalkd",
321+ "/usr/sbin/atd",
322+ "/usr/sbin/cannaserver",
323+ "/usr/sbin/cpuspeed",
324+ "/usr/sbin/cron",
325+ "/usr/sbin/crond",
326+ "/usr/sbin/cupsd",
327+ "/usr/sbin/dhcpd",
328+ "/usr/sbin/exim4",
329+ "/usr/sbin/gpm",
330+ "/usr/sbin/hald",
331+ "/usr/sbin/htt",
332+ "/usr/sbin/httpd",
333+ "/usr/sbin/inetd",
334+ "/usr/sbin/logrotate",
335+ "/usr/sbin/lpd",
336+ "/usr/sbin/nmbd",
337+ "/usr/sbin/papd",
338+ "/usr/sbin/rpc.idmapd",
339+ "/usr/sbin/rpc.mountd",
340+ "/usr/sbin/rpc.rquotad",
341+ "/usr/sbin/sendmail.sendmail",
342+ "/usr/sbin/smartd",
343+ "/usr/sbin/smbd",
344+ "/usr/sbin/squid",
345+ "/usr/sbin/sshd",
346+ "/usr/sbin/vmware-guestd",
347+ "/usr/sbin/vsftpd",
348+ "/usr/sbin/xinetd"
349+ };
350+ int i;
351+ for (i = 0; i < elementof(files); i++) {
352+ char *cp = get_realpath(files[i]);
353+ if (!cp)
354+ continue;
355+ if (!access(cp, X_OK))
356+ make_default_domain_transition(cp);
357+ free(cp);
358+ }
359+}
360+
361+/**
362+ * mkdir2 - mkdir() with ignoring EEXIST error.
363+ *
364+ * @dir: Directory to create.
365+ * @mode: Create mode.
366+ *
367+ * Returns 0 on success, EOF otehrwise.
368+ */
369+static int mkdir2(const char *dir, int mode)
370+{
371+ return mkdir(dir, mode) == 0 || errno == EEXIST ? 0 : EOF;
372+}
373+
374+/* Policy directory. Default is "/etc/caitsith/". */
375+static char *policy_dir = NULL;
376+
377+/**
378+ * make_policy_dir - Create policy directories and tools directories.
379+ *
380+ * Returns nothing.
381+ */
382+static void make_policy_dir(void)
383+{
384+ char *dir = policy_dir;
385+ const time_t now = time(NULL);
386+ struct tm *tm = localtime(&now);
387+ char stamp[20] = { };
388+ snprintf(stamp, sizeof(stamp) - 1, "%02d-%02d-%02d.%02d:%02d:%02d",
389+ tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
390+ tm->tm_min, tm->tm_sec);
391+ if (!chdir(policy_dir) && !chdir("policy"))
392+ goto tools_dir;
393+ fprintf(stderr, "Creating policy directory... ");
394+ while (1) {
395+ const char c = *dir++;
396+ if (!c)
397+ break;
398+ if (c != '/')
399+ continue;
400+ *(dir - 1) = '\0';
401+ mkdir(policy_dir, 0700);
402+ *(dir - 1) = '/';
403+ }
404+ if (mkdir2(policy_dir, 0700) || chdir(policy_dir) ||
405+ mkdir2("policy", 0700) || chdir("policy")) {
406+ fprintf(stderr, "failed.\n");
407+ exit(1);
408+ } else {
409+ fprintf(stderr, "OK\n");
410+ }
411+tools_dir:
412+ if (!chdir(policy_dir) && !chdir("tools"))
413+ return;
414+ fprintf(stderr, "Creating configuration directory... ");
415+ mkdir("tools", 0700);
416+ if (!chdir("tools"))
417+ fprintf(stderr, "OK\n");
418+ else {
419+ fprintf(stderr, "failed.\n");
420+ exit(1);
421+ }
422+}
423+
424+/**
425+ * chdir_policy - Change to policy directory.
426+ *
427+ * Returns 1 on success, 0 otherwise.
428+ */
429+static _Bool chdir_policy(void)
430+{
431+ if (chdir(policy_dir) || chdir("policy")) {
432+ fprintf(stderr, "ERROR: Can't chdir to %s/policy/ "
433+ "directory.\n", policy_dir);
434+ return 0;
435+ }
436+ return 1;
437+}
438+
439+/**
440+ * close_file - Close file and rename.
441+ *
442+ * @fp: Pointer to "FILE".
443+ * @condition: Preconditions before rename().
444+ * @old: Temporary file's pathname.
445+ * @new: Final file's pathname.
446+ *
447+ * Returns nothing.
448+ */
449+static void close_file(FILE *fp, _Bool condition, const char *old,
450+ const char *new)
451+{
452+ if (fsync(fileno(fp)) || fclose(fp) || !condition || rename(old, new))
453+ fprintf(stderr, "failed.\n");
454+ else
455+ fprintf(stderr, "OK.\n");
456+}
457+
458+/**
459+ * make_policy - Make /etc/caitsith/policy/current .
460+ *
461+ * Returns nothing.
462+ */
463+static void make_policy(void)
464+{
465+ if (!chdir_policy())
466+ return;
467+ if (!access("current", R_OK))
468+ return;
469+ filp = fopen("current.tmp", "w");
470+ if (!filp) {
471+ fprintf(stderr, "ERROR: Can't create policy.\n");
472+ return;
473+ }
474+ fprintf(stderr, "Creating default policy... ");
475+ fprintf(filp, "POLICY_VERSION=20120401\n");
476+ fprintf(filp, "\n");
477+ fprintf(filp, "quota memory audit 16777216\n");
478+ fprintf(filp, "quota memory query 1048576\n");
479+ fprintf(filp, "quota audit[1] allowed=0 denied=1024 unmatched=1024\n");
480+ fprintf(filp, "\n");
481+ fprintf(filp, "10000 acl execute\n"
482+ " audit 0\n");
483+ scan_modprobe_and_hotplug();
484+ scan_daemons();
485+ scan_init_dir();
486+ fprintf(filp, "\n");
487+ {
488+ char *tools_dir = get_realpath("/usr/sbin");
489+ fprintf(filp, "0 acl modify_policy\n"
490+ " audit 1\n"
491+ " 1 deny task.uid!=0\n"
492+ " 1 deny task.euid!=0\n"
493+ " 100 allow task.exe=\"%s/caitsith-loadpolicy\"\n"
494+ " 100 allow task.exe=\"%s/caitsith-queryd\"\n"
495+ " 10000 deny\n", tools_dir, tools_dir);
496+ }
497+ close_file(filp, chdir_policy(), "current.tmp", "current");
498+ filp = NULL;
499+}
500+
501+/* The name of loadable kernel module to load. */
502+static const char *module_name = "caitsith";
503+
504+/**
505+ * make_module_loader - Make /etc/caitsith/caitsith-load-module .
506+ *
507+ * Returns nothing.
508+ */
509+static void make_module_loader(void)
510+{
511+ FILE *fp;
512+ if (chdir(policy_dir) || !access("caitsith-load-module", X_OK)
513+ || !module_name[0])
514+ return;
515+ fp = fopen("caitsith-load-module.tmp", "w");
516+ if (!fp) {
517+ fprintf(stderr, "ERROR: Can't create module loader.\n");
518+ return;
519+ }
520+ fprintf(stderr, "Creating module loader... ");
521+ fprintf(fp, "#! /bin/sh\n");
522+ fprintf(fp, "export PATH=$PATH:/sbin:/bin\n");
523+ fprintf(fp, "exec modprobe %s\n", module_name);
524+ close_file(fp, !chmod("caitsith-load-module.tmp", 0700),
525+ "caitsith-load-module.tmp", "caitsith-load-module");
526+}
527+
528+/* Content of /etc/caitsith/tools/auditd.conf . */
529+static const char auditd_data[] =
530+"# This file contains sorting rules used by caitsith-auditd command.\n"
531+"\n"
532+"# An audit log consists with two parts delimited by \" / \" sequence.\n"
533+"# You can refer the former part using 'header' keyword, the latter part\n"
534+"# using 'acl' keyword.\n"
535+"#\n"
536+"# Words in each part are separated by a space character. Therefore, you can\n"
537+"# use 'header[index]', 'acl[index]' for referring index'th word of the\n"
538+"# part.\n"
539+"# The index starts from 1, and 0 refers the whole line\n"
540+"# (i.e. 'header[0]' = 'header', 'acl[0]' = 'acl').\n"
541+"#\n"
542+"# Three operators are provided for conditional sorting.\n"
543+"# '.contains' is for 'fgrep keyword' match.\n"
544+"# '.equals' is for 'grep ^keyword$' match.\n"
545+"# '.starts' is for 'grep ^keyword' match.\n"
546+"#\n"
547+"# Sorting rules are defined using multi-lined chunks. A chunk is terminated\n"
548+"# by a 'destination' line which specifies the pathname to write the audit\n"
549+"# log. A 'destination' line is processed only when all preceding 'header'\n"
550+"# and 'acl' lines in that chunk have matched.\n"
551+"# Evaluation stops at the first processed 'destination' line.\n"
552+"# Therefore, no audit logs are written more than once.\n"
553+"#\n"
554+"# More specific matches should be placed before less specific matches.\n"
555+"# For example:\n"
556+"#\n"
557+"# header.contains result=denied\n"
558+"# acl.contains task.domain=\"/usr/sbin/httpd\"\n"
559+"# destination /var/log/caitsith/httpd_denied.log\n"
560+"#\n"
561+"# This chunk should be placed before the chunk that matches logs with\n"
562+"# result=denied. If placed after, the audit logs for /usr/sbin/httpd will\n"
563+"# be sent to /var/log/caitsith/denied.log .\n"
564+"\n"
565+"# Please use CaitSith's escape rule (e.g. '\\040' rather than '\\ ' for\n"
566+"# representing a ' ' in a word).\n"
567+"\n"
568+"# Send all allowed logs to /dev/null.\n"
569+"header.contains result=allowed\n"
570+"destination /dev/null\n"
571+"\n"
572+"# Send all unmatched logs to /var/log/caitsith/unmatched.log\n"
573+"header.contains result=unmatched\n"
574+"destination /var/log/caitsith/unmatched.log\n"
575+"\n"
576+"# Send all denied logs to /var/log/caitsith/denied.log\n"
577+"header.contains result=denied\n"
578+"destination /var/log/caitsith/denied.log\n"
579+"\n";
580+
581+/**
582+ * make_auditd_conf - Make /etc/caitsith/tools/auditd.conf .
583+ *
584+ * Returns nothing.
585+ */
586+static void make_auditd_conf(void)
587+{
588+ FILE *fp;
589+ if (chdir(policy_dir) || chdir("tools") ||
590+ !access("auditd.conf", R_OK))
591+ return;
592+ fp = fopen("auditd.tmp", "w");
593+ if (!fp) {
594+ fprintf(stderr, "ERROR: Can't create configuration file.\n");
595+ return;
596+ }
597+ fprintf(stderr, "Creating configuration file for caitsith-auditd ... ");
598+ fprintf(fp, "%s", auditd_data);
599+ close_file(fp, !chmod("auditd.tmp", 0644), "auditd.tmp",
600+ "auditd.conf");
601+}
602+
603+/* Content of /etc/caitsith/tools/notifyd.conf . */
604+static const char notifyd_data[] =
605+"# This file contains configuration used by caitsith-notifyd command.\n"
606+"\n"
607+"# caitsith-notifyd is a daemon that notifies the occurrence of policy violation\n"
608+"# in enforcing mode.\n"
609+"#\n"
610+"# time_to_wait is grace time in second before rejecting the request that\n"
611+"# caused policy violation in enforcing mode. For example, if you specify\n"
612+"# 30, you will be given 30 seconds for starting caitsith-queryd command and\n"
613+"# responding to the policy violation event.\n"
614+"# If you specify non 0 value, you need to register caitsith-notifyd command to\n"
615+"# /proc/caitsith/policy as well as caitsith-queryd command, for caitsith-notifyd needs to\n"
616+"# behave as if caitsith-queryd command is running.\n"
617+"# Also, you should avoid specifying too large value (e.g. 3600) because\n"
618+"# the request will remain pending for that period if you can't respond.\n"
619+"#\n"
620+"# action_to_take is a command line you want to use for notification.\n"
621+"# The command specified by this parameter must read the policy violation\n"
622+"# notification from standard input. For example, mail, curl and xmessage\n"
623+"# commands can read from standard input.\n"
624+"# This parameter is passed to execve(). Thus, please use a wrapper program\n"
625+"# if you need shell processing (e.g. wildcard expansion, environment\n"
626+"# variables).\n"
627+"#\n"
628+"# minimal_interval is grace time in second before re-notifying the next\n"
629+"# occurrence of policy violation. You can specify 60 to limit notification\n"
630+"# to once per a minute, 3600 to limit notification to once per an hour.\n"
631+"# You can specify 0 to unlimit, but notifying of every policy violation\n"
632+"# events (e.g. sending a mail) might annoy you because policy violation\n"
633+"# can occur in clusters if once occurred.\n"
634+"\n"
635+"# Please use CaitSith's escape rule (e.g. '\\040' rather than '\\ ' for\n"
636+"# representing a ' ' in a word).\n"
637+"\n"
638+"# Examples:\n"
639+"#\n"
640+"# time_to_wait 180\n"
641+"# action_to_take mail admin@example.com\n"
642+"#\n"
643+"# Wait for 180 seconds before rejecting the request.\n"
644+"# The occurrence is notified by sending mail to admin@example.com\n"
645+"# (if SMTP service is available).\n"
646+"#\n"
647+"# time_to_wait 0\n"
648+"# action_to_take curl --data-binary @- https://your.server/path_to_cgi\n"
649+"#\n"
650+"# Reject the request immediately.\n"
651+"# The occurrence is notified by executing curl command.\n"
652+"#\n"
653+"time_to_wait 0\n"
654+"action_to_take mail -s Notification\\040from\\040caitsith-notifyd root@localhost\n"
655+"minimal_interval 60\n"
656+"\n";
657+
658+/**
659+ * make_notifyd_conf - Make /etc/caitsith/tools/notifyd.conf .
660+ *
661+ * Returns nothing.
662+ */
663+static void make_notifyd_conf(void)
664+{
665+ FILE *fp;
666+ if (chdir(policy_dir) || chdir("tools") ||
667+ !access("notifyd.conf", R_OK))
668+ return;
669+ fp = fopen("notifyd.tmp", "w");
670+ if (!fp) {
671+ fprintf(stderr, "ERROR: Can't create configuration file.\n");
672+ return;
673+ }
674+ fprintf(stderr, "Creating configuration file for caitsith-notifyd ... ");
675+ fprintf(fp, "%s", notifyd_data);
676+ close_file(fp, !chmod("notifyd.tmp", 0644), "notifyd.tmp",
677+ "notifyd.conf");
678+}
679+
680+int main(int argc, char *argv[])
681+{
682+ int i;
683+ const char *dir = NULL;
684+ for (i = 1; i < argc; i++) {
685+ char *arg = argv[i];
686+ if (*arg == '-' && *(arg + 1) == '-')
687+ arg += 2;
688+ if (!strncmp(arg, "root=", 5)) {
689+ if (chroot(arg + 5) || chdir("/")) {
690+ fprintf(stderr, "Can't chroot to '%s'\n",
691+ arg + 5);
692+ return 1;
693+ }
694+ } else if (!strncmp(arg, "policy_dir=", 11)) {
695+ dir = arg + 11;
696+ } else if (!strncmp(arg, "module_name=", 12)) {
697+ module_name = arg + 12;
698+ } else {
699+ fprintf(stderr, "Unknown option: '%s'\n", argv[i]);
700+ return 1;
701+ }
702+ }
703+ if (!dir)
704+ dir = "/etc/caitsith";
705+ policy_dir = strdup(dir);
706+ memset(path, 0, sizeof(path));
707+ make_policy_dir();
708+ make_policy();
709+ make_module_loader();
710+ make_auditd_conf();
711+ make_notifyd_conf();
712+ return 0;
713+}
--- trunk/caitsith-tools/usr_lib_caitsith/caitsith-agent.c (nonexistent)
+++ trunk/caitsith-tools/usr_lib_caitsith/caitsith-agent.c (revision 2)
@@ -0,0 +1,378 @@
1+/*
2+ * caitsith-agent.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include <stdio.h>
24+#include <string.h>
25+#include <stdlib.h>
26+#include <sys/types.h>
27+#include <sys/socket.h>
28+#include <netinet/in.h>
29+#include <arpa/inet.h>
30+#include <sys/stat.h>
31+#include <fcntl.h>
32+#include <unistd.h>
33+#include <poll.h>
34+#include <signal.h>
35+#include <dirent.h>
36+
37+static _Bool wait_data(const int fd)
38+{
39+ struct pollfd pfd = { .fd = fd, .events = POLLIN};
40+ poll(&pfd, 1, -1);
41+ return 1;
42+}
43+
44+static void show_tasklist(FILE *fp, const _Bool show_all)
45+{
46+ int status_fd = open(".process_status", O_RDWR);
47+ DIR *dir = opendir("/proc/");
48+ if (status_fd == EOF || !dir) {
49+ if (status_fd != EOF)
50+ close(status_fd);
51+ if (dir)
52+ closedir(dir);
53+ return;
54+ }
55+ fputc(0, fp);
56+ while (1) {
57+ int ret_ignored;
58+ FILE *status_fp;
59+ pid_t ppid = 1;
60+ char *name = NULL;
61+ char buffer[1024];
62+ char test[16];
63+ unsigned int pid;
64+ struct dirent *dent = readdir(dir);
65+ if (!dent)
66+ break;
67+ if (dent->d_type != DT_DIR ||
68+ sscanf(dent->d_name, "%u", &pid) != 1 || !pid)
69+ continue;
70+ memset(buffer, 0, sizeof(buffer));
71+ if (!show_all) {
72+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/exe",
73+ pid);
74+ if (readlink(buffer, test, sizeof(test)) <= 0)
75+ continue;
76+ }
77+ snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/status", pid);
78+ status_fp = fopen(buffer, "r");
79+ if (status_fp) {
80+ while (memset(buffer, 0, sizeof(buffer)) &&
81+ fgets(buffer, sizeof(buffer) - 1, status_fp)) {
82+ if (!strncmp(buffer, "Name:\t", 6)) {
83+ char *cp = buffer + 6;
84+ memmove(buffer, cp, strlen(cp) + 1);
85+ cp = strchr(buffer, '\n');
86+ if (cp)
87+ *cp = '\0';
88+ name = strdup(buffer);
89+ }
90+ if (sscanf(buffer, "PPid: %u", &ppid) == 1)
91+ break;
92+ }
93+ fclose(status_fp);
94+ }
95+ snprintf(buffer, sizeof(buffer) - 1, "%u\n", pid);
96+ ret_ignored = write(status_fd, buffer, strlen(buffer));
97+ memset(buffer, 0, sizeof(buffer));
98+ ret_ignored = read(status_fd, buffer, sizeof(buffer));
99+ if (!buffer[0])
100+ continue;
101+ fprintf(fp, "PID=%u PPID=%u NAME=", pid, ppid);
102+ if (name) {
103+ const char *cp = name;
104+ while (1) {
105+ unsigned char c = *cp++;
106+ if (!c)
107+ break;
108+ if (c == '\\') {
109+ c = *cp++;
110+ if (c == '\\')
111+ fprintf(fp, "\\\\");
112+ else if (c == 'n')
113+ fprintf(fp, "\\012");
114+ else
115+ break;
116+ } else if (c > ' ' && c <= 126) {
117+ fputc(c, fp);
118+ } else {
119+ fprintf(fp, "\\%c%c%c",
120+ (c >> 6) + '0',
121+ ((c >> 3) & 7) + '0',
122+ (c & 7) + '0');
123+ }
124+ }
125+ free(name);
126+ } else {
127+ fprintf(fp, "<UNKNOWN>");
128+ }
129+ fputc('\n', fp);
130+ ret_ignored = fwrite(buffer, strlen(buffer), 1, fp);
131+ while (1) {
132+ int len = read(status_fd, buffer, sizeof(buffer));
133+ if (len <= 0)
134+ break;
135+ ret_ignored = fwrite(buffer, len, 1, fp);
136+ }
137+ fputc('\n', fp);
138+ }
139+ fputc(0, fp);
140+ closedir(dir);
141+ close(status_fd);
142+ fflush(fp);
143+}
144+
145+static void handle_audit(const int client)
146+{
147+ int ret_ignored;
148+ const int fd = open("audit", O_RDONLY);
149+ if (fd == EOF)
150+ return;
151+ /* Return \0 to indicate success. */
152+ ret_ignored = write(client, "", 1);
153+ while (wait_data(fd)) {
154+ char buffer[4096];
155+ const int len = read(fd, buffer, sizeof(buffer));
156+ if (!len)
157+ continue;
158+ if (len == EOF || write(client, buffer, len) != len)
159+ break;
160+ }
161+ close(fd);
162+}
163+
164+static void handle_query(const int client)
165+{
166+ int ret_ignored;
167+ const int fd = open("query", O_RDWR);
168+ if (fd == EOF)
169+ return;
170+ /* Return \0 to indicate success. */
171+ ret_ignored = write(client, "", 1);
172+ while (wait_data(client)) {
173+ char buffer[4096];
174+ int len = recv(client, buffer, sizeof(buffer), MSG_DONTWAIT);
175+ int nonzero_len;
176+ if (len <= 0)
177+ break;
178+restart:
179+ for (nonzero_len = 0 ; nonzero_len < len; nonzero_len++)
180+ if (!buffer[nonzero_len])
181+ break;
182+ if (nonzero_len) {
183+ if (write(fd, buffer, nonzero_len) != nonzero_len)
184+ break;
185+ } else {
186+ while (wait_data(fd)) {
187+ char buffer2[4096];
188+ const int len = read(fd, buffer2,
189+ sizeof(buffer2));
190+ if (!len)
191+ continue;
192+ if (len == EOF ||
193+ write(client, buffer2, len) != len) {
194+ shutdown(client, SHUT_RDWR);
195+ break;
196+ }
197+ if (!buffer2[len - 1])
198+ break;
199+ }
200+ nonzero_len = 1;
201+ }
202+ len -= nonzero_len;
203+ memmove(buffer, buffer + nonzero_len, len);
204+ if (len)
205+ goto restart;
206+ }
207+ close(fd);
208+}
209+
210+static _Bool verbose = 0;
211+
212+static void handle_policy(const int client, const char *filename)
213+{
214+ int ret_ignored;
215+ char *cp = strrchr(filename, '/');
216+ int fd = open(cp ? cp + 1 : filename, O_RDWR);
217+ if (fd == EOF)
218+ goto out;
219+ /* Return \0 to indicate success. */
220+ if (write(client, "", 1) != 1)
221+ goto out;
222+ if (verbose) {
223+ ret_ignored = write(2, "opened ", 7);
224+ ret_ignored = write(2, filename, strlen(filename));
225+ ret_ignored = write(2, "\n", 1);
226+ }
227+ while (wait_data(client)) {
228+ char buffer[4096];
229+ int len = recv(client, buffer, sizeof(buffer), MSG_DONTWAIT);
230+ int nonzero_len;
231+ if (len <= 0)
232+ break;
233+restart:
234+ for (nonzero_len = 0 ; nonzero_len < len; nonzero_len++)
235+ if (!buffer[nonzero_len])
236+ break;
237+ if (nonzero_len) {
238+ if (write(fd, buffer, nonzero_len) != nonzero_len)
239+ break;
240+ if (verbose)
241+ ret_ignored = write(1, buffer, nonzero_len);
242+ } else {
243+ while (1) {
244+ char buffer2[4096];
245+ const int len = read(fd, buffer2,
246+ sizeof(buffer2));
247+ if (len == 0)
248+ break;
249+ /* Don't send \0 because it is EOF marker. */
250+ if (len < 0 || memchr(buffer2, '\0', len) ||
251+ write(client, buffer2, len) != len)
252+ goto out;
253+ }
254+ /* Return \0 to indicate EOF. */
255+ if (write(client, "", 1) != 1)
256+ goto out;
257+ nonzero_len = 1;
258+ }
259+ len -= nonzero_len;
260+ memmove(buffer, buffer + nonzero_len, len);
261+ if (len)
262+ goto restart;
263+ }
264+out:
265+ if (verbose)
266+ ret_ignored = write(2, "disconnected\n", 13);
267+}
268+
269+static void do_child(const int client)
270+{
271+ int i;
272+ char buffer[1024];
273+ /* Read filename. */
274+ for (i = 0; i < sizeof(buffer); i++) {
275+ if (read(client, buffer + i, 1) != 1)
276+ goto out;
277+ if (!buffer[i])
278+ break;
279+ }
280+ if (!memchr(buffer, '\0', sizeof(buffer)))
281+ goto out;
282+ if (!strcmp(buffer, "proc:query"))
283+ handle_query(client);
284+ else if (!strcmp(buffer, "proc:audit"))
285+ handle_audit(client);
286+ else if (!strncmp(buffer, "proc:", 5)) {
287+ /* Open /proc/\$/ for reading. */
288+ FILE *fp = fdopen(client, "w");
289+ if (fp) {
290+ show_tasklist(fp, !strcmp(buffer + 5,
291+ "all_process_status"));
292+ fclose(fp);
293+ }
294+ } else
295+ handle_policy(client, buffer);
296+out:
297+ close(client);
298+}
299+
300+int main(int argc, char *argv[])
301+{
302+ const int listener = socket(AF_INET, SOCK_STREAM, 0);
303+ struct sockaddr_in addr;
304+ socklen_t size = sizeof(addr);
305+ char *port;
306+ if (chdir("/proc/caitsith/"))
307+ return 1;
308+ {
309+ int i;
310+ for (i = 1; i < argc; i++) {
311+ if (strcmp(argv[i], "--verbose"))
312+ continue;
313+ verbose = 1;
314+ argc--;
315+ for (; i < argc; i++)
316+ argv[i] = argv[i + 1];
317+ break;
318+ }
319+ }
320+ if (argc != 2) {
321+usage:
322+ fprintf(stderr, "%s listen_address:listen_port\n", argv[0]);
323+ return 1;
324+ }
325+ port = strchr(argv[1], ':');
326+ if (!port)
327+ goto usage;
328+ *port++ = '\0';
329+ memset(&addr, 0, sizeof(addr));
330+ addr.sin_family = AF_INET;
331+ addr.sin_addr.s_addr = inet_addr(argv[1]);
332+ addr.sin_port = htons(atoi(port));
333+ if (bind(listener, (struct sockaddr *) &addr, sizeof(addr)) ||
334+ listen(listener, 5) ||
335+ getsockname(listener, (struct sockaddr *) &addr, &size)) {
336+ close(listener);
337+ return 1;
338+ }
339+ {
340+ const unsigned int ip = ntohl(addr.sin_addr.s_addr);
341+ printf("Listening at %u.%u.%u.%u:%u\n",
342+ (unsigned char) (ip >> 24), (unsigned char) (ip >> 16),
343+ (unsigned char) (ip >> 8), (unsigned char) ip,
344+ ntohs(addr.sin_port));
345+ fflush(stdout);
346+ }
347+ close(0);
348+ if (!verbose) {
349+ close(1);
350+ close(2);
351+ }
352+ signal(SIGCHLD, SIG_IGN);
353+ while (1) {
354+ socklen_t size = sizeof(addr);
355+ const int client = accept(listener, (struct sockaddr *) &addr,
356+ &size);
357+ if (client == EOF) {
358+ if (verbose)
359+ fprintf(stderr, "accept() failed\n");
360+ continue;
361+ }
362+ switch (fork()) {
363+ case 0:
364+ close(listener);
365+ do_child(client);
366+ _exit(0);
367+ case -1:
368+ if (verbose)
369+ fprintf(stderr, "fork() failed\n");
370+ close(client);
371+ break;
372+ default:
373+ close(client);
374+ }
375+ }
376+ close(listener);
377+ return 1;
378+}
--- trunk/caitsith-tools/usr_lib_caitsith/audit-exec-param.c (nonexistent)
+++ trunk/caitsith-tools/usr_lib_caitsith/audit-exec-param.c (revision 2)
@@ -0,0 +1,87 @@
1+/*
2+ * audit-exec-param.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is free software; you can redistribute it and/or modify it
11+ * under the terms of the GNU General Public License v2 as published by the
12+ * Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful, but WITHOUT
15+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17+ * more details.
18+ *
19+ * You should have received a copy of the GNU General Public License along with
20+ * this program; if not, write to the Free Software Foundation, Inc.,
21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22+ */
23+#include <stdio.h>
24+#include <stdlib.h>
25+#include <unistd.h>
26+#include <syslog.h>
27+#include <string.h>
28+#include <sys/types.h>
29+#include <sys/stat.h>
30+#include <fcntl.h>
31+#include <errno.h>
32+
33+int main(int raw_argc, char *raw_argv[])
34+{
35+ int i;
36+ int argc;
37+ int envc;
38+ char *filename;
39+ char **argv;
40+ char **envp;
41+ if (1) {
42+ int fd = open("/proc/caitsith/.execute_handler", 0);
43+ close(fd);
44+ if (fd == EOF && errno != ENOENT) {
45+ fprintf(stderr, "FATAL: I'm not execute_handler.\n");
46+ return 1;
47+ }
48+ }
49+ if (raw_argc < 7)
50+ return 1;
51+ filename = raw_argv[4];
52+ argc = atoi(raw_argv[5]);
53+ envc = atoi(raw_argv[6]);
54+ if (raw_argc != argc + envc + 7)
55+ return 1;
56+ for (i = 5; i < argc + 5; i++)
57+ raw_argv[i] = raw_argv[i + 2];
58+ raw_argv[argc + 5] = NULL;
59+ for (i = argc + 6; i < argc + envc + 6; i++)
60+ raw_argv[i] = raw_argv[i + 1];
61+ raw_argv[argc + envc + 6] = NULL;
62+ argv = raw_argv + 5;
63+ envp = raw_argv + argc + 6;
64+ /*
65+ * Check parameters passed to execve() request.
66+ */
67+ if (1) {
68+ openlog(raw_argv[0], LOG_NDELAY, LOG_USER);
69+ syslog(LOG_INFO, "Domain = %s\n", raw_argv[1]);
70+ syslog(LOG_INFO, "Caller Program = %s\n", raw_argv[2]);
71+ syslog(LOG_INFO, "Process Status = %s\n", raw_argv[3]);
72+ syslog(LOG_INFO, "Requested Program = %s\n", filename);
73+ syslog(LOG_INFO, "argc=%d\n", argc);
74+ syslog(LOG_INFO, "envc=%d\n", envc);
75+ for (i = 0; i < argc; i++)
76+ syslog(LOG_INFO, "argv[%d] = %s\n", i, argv[i]);
77+ for (i = 0; i < envc; i++)
78+ syslog(LOG_INFO, "envp[%d] = %s\n", i, envp[i]);
79+ closelog();
80+ }
81+ /*
82+ * Continue if filename and argv[] and envp[] are appropriate.
83+ */
84+ if (1)
85+ execve(filename, argv, envp);
86+ return 1;
87+}
--- trunk/caitsith-tools/usr_lib_caitsith/Makefile (nonexistent)
+++ trunk/caitsith-tools/usr_lib_caitsith/Makefile (revision 2)
@@ -0,0 +1,18 @@
1+include ../Include.make
2+
3+BUILD_FILES = audit-exec-param caitsith-agent init_policy
4+
5+all: $(BUILD_FILES)
6+
7+install: all
8+ mkdir -p -m 0755 $(INSTALLDIR)/$(USRLIBDIR)/caitsith
9+ $(INSTALL) -m 0755 $(BUILD_FILES) $(INSTALLDIR)/$(USRLIBDIR)/caitsith/
10+ $(INSTALL) -m 0644 ../README.caitsith ../COPYING.caitsith $(INSTALLDIR)/$(USRLIBDIR)/caitsith/
11+
12+.c:
13+ $(CC) $(CFLAGS) -o $@ $<
14+
15+clean:
16+ rm -f -- $(BUILD_FILES)
17+
18+.PHONY: clean install
--- trunk/caitsith-tools/sbin/caitsith-init.c (nonexistent)
+++ trunk/caitsith-tools/sbin/caitsith-init.c (revision 2)
@@ -0,0 +1,192 @@
1+/*
2+ * caitsith-init.c
3+ *
4+ * CaitSith's utilities.
5+ *
6+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
7+ *
8+ * Version: 0.1 2012/04/01
9+ *
10+ * This program is executed automatically by kernel
11+ * when execution of /sbin/init is requested.
12+ *
13+ * This program is free software; you can redistribute it and/or modify it
14+ * under the terms of the GNU General Public License v2 as published by the
15+ * Free Software Foundation.
16+ *
17+ * This program is distributed in the hope that it will be useful, but WITHOUT
18+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20+ * more details.
21+ *
22+ * You should have received a copy of the GNU General Public License along with
23+ * this program; if not, write to the Free Software Foundation, Inc.,
24+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25+ */
26+#define _FILE_OFFSET_BITS 64
27+#define _LARGEFILE_SOURCE
28+#define _LARGEFILE64_SOURCE
29+#include <stdio.h>
30+#include <string.h>
31+#include <stdlib.h>
32+#include <sys/types.h>
33+#include <sys/stat.h>
34+#include <sys/wait.h>
35+#include <sys/mount.h>
36+#include <fcntl.h>
37+#include <unistd.h>
38+#include <dirent.h>
39+#include <limits.h>
40+#include <sys/vfs.h>
41+#include <errno.h>
42+
43+static void panic(void)
44+{
45+ printf("Fatal error while loading policy.\n");
46+ fflush(stdout);
47+ while (1)
48+ sleep(100);
49+}
50+
51+#define policy_dir "/etc/caitsith/policy"
52+#define proc_policy "/proc/caitsith/policy"
53+static _Bool proc_unmount = 0;
54+
55+static char buffer[8192];
56+
57+static void copy_files(const char *src, const char *dest)
58+{
59+ int sfd;
60+ int dfd = open(dest, O_WRONLY);
61+ if (dfd == EOF) {
62+ if (errno != ENOENT)
63+ panic();
64+ return;
65+ }
66+ sfd = open(src, O_RDONLY);
67+ if (sfd != EOF) {
68+ while (1) {
69+ int ret_ignored;
70+ int len = read(sfd, buffer, sizeof(buffer));
71+ if (len <= 0)
72+ break;
73+ ret_ignored = write(dfd, buffer, len);
74+ }
75+ close(sfd);
76+ }
77+ close(dfd);
78+}
79+
80+static void show_stat(void)
81+{
82+ unsigned int acl = 0;
83+ unsigned int size = -1;
84+ FILE *fp = fopen(proc_policy, "r");
85+ if (!fp)
86+ return;
87+ while (memset(buffer, 0, sizeof(buffer)) &&
88+ fgets(buffer, sizeof(buffer) - 1, fp)) {
89+ if (!strncmp(buffer, "acl ", 4))
90+ acl++;
91+ else if (size == -1)
92+ sscanf(buffer, "stat Memory used by policy: %u",
93+ &size);
94+ }
95+ fclose(fp);
96+ printf("%u ACL entr%s.\n", acl, acl > 1 ? "ies" : "y");
97+ if (size != -1)
98+ printf("%u KB used by policy.\n", (size + 1023) / 1024);
99+}
100+
101+int main(int argc, char *argv[])
102+{
103+ struct stat buf;
104+
105+ /* Mount /proc if not mounted. */
106+ if (lstat("/proc/self/", &buf) || !S_ISDIR(buf.st_mode))
107+ proc_unmount = !mount("/proc", "/proc/", "proc", 0, NULL);
108+
109+ /*
110+ * Open /dev/console if stdio are not connected.
111+ *
112+ * WARNING: Don't let this program be invoked implicitly
113+ * if you are not operating from console.
114+ * Otherwise, you will get unable to respond to prompt
115+ * if something went wrong.
116+ */
117+ if (access("/proc/self/fd/0", R_OK)) {
118+ close(0);
119+ close(1);
120+ close(2);
121+ open("/dev/console", O_RDONLY);
122+ open("/dev/console", O_WRONLY);
123+ open("/dev/console", O_WRONLY);
124+ }
125+
126+ /* Load kernel module if needed. */
127+ if (lstat("/proc/caitsith/", &buf) || !S_ISDIR(buf.st_mode)) {
128+ if (!access("/etc/caitsith/caitsith-load-module", X_OK)) {
129+ const pid_t pid = fork();
130+ switch (pid) {
131+ case 0:
132+ execl("/etc/caitsith/caitsith-load-module",
133+ "/etc/caitsith/caitsith-load-module", NULL);
134+ _exit(0);
135+ case -1:
136+ panic();
137+ }
138+ while (waitpid(pid, NULL, __WALL) == EOF &&
139+ errno == EINTR);
140+ }
141+ }
142+
143+ /* Stop if policy interface doesn't exist. */
144+ if (lstat("/proc/caitsith/", &buf) || !S_ISDIR(buf.st_mode)) {
145+ printf("FATAL: Policy interface does not exist.\n");
146+ fflush(stdout);
147+ while (1)
148+ sleep(100);
149+ }
150+
151+ /*
152+ * Unmount /proc and execute /sbin/init if this program was executed by
153+ * passing init=/sbin/caitsith-init . The kernel will try to execute this
154+ * program again with getpid() != 1 when /sbin/init starts.
155+ */
156+ if (getpid() == 1) {
157+ if (proc_unmount)
158+ umount("/proc/");
159+ argv[0] = "/sbin/init";
160+ execv(argv[0], argv);
161+ printf("FATAL: Failed to execute %s\n", argv[0]);
162+ fflush(stdout);
163+ while (1)
164+ sleep(100);
165+ }
166+
167+ /* Load policy. */
168+ if (!chdir(policy_dir))
169+ copy_files("current", proc_policy);
170+
171+ /* Do additional initialization. */
172+ if (!access("/etc/caitsith/caitsith-post-init", X_OK)) {
173+ const pid_t pid = fork();
174+ switch (pid) {
175+ case 0:
176+ execl("/etc/caitsith/caitsith-post-init",
177+ "/etc/caitsith/caitsith-post-init", NULL);
178+ _exit(0);
179+ case -1:
180+ panic();
181+ }
182+ while (waitpid(pid, NULL, __WALL) == EOF &&
183+ errno == EINTR);
184+ }
185+
186+ show_stat();
187+
188+ if (proc_unmount)
189+ umount("/proc");
190+
191+ return 0;
192+}
--- trunk/caitsith-tools/sbin/Makefile (nonexistent)
+++ trunk/caitsith-tools/sbin/Makefile (revision 2)
@@ -0,0 +1,17 @@
1+include ../Include.make
2+
3+BUILD_FILES = caitsith-init
4+
5+all: $(BUILD_FILES)
6+
7+install: all
8+ mkdir -p -m 0755 $(INSTALLDIR)$(SBINDIR)
9+ $(INSTALL) -m 0700 $(BUILD_FILES) $(INSTALLDIR)$(SBINDIR)
10+
11+.c:
12+ $(CC) $(CFLAGS) -o $@ $<
13+
14+clean:
15+ rm -f -- $(BUILD_FILES)
16+
17+.PHONY: clean install
--- trunk/caitsith-tools/Makefile (nonexistent)
+++ trunk/caitsith-tools/Makefile (revision 2)
@@ -0,0 +1,21 @@
1+all:
2+ $(MAKE) -C sbin all
3+ $(MAKE) -C usr_sbin all
4+ $(MAKE) -C usr_lib_caitsith all
5+
6+install: all
7+ $(MAKE) -C sbin install
8+ $(MAKE) -C usr_sbin install
9+ $(MAKE) -C usr_lib_caitsith install
10+
11+clean:
12+##
13+## I don't enable "find" line because older versions does not support -delete
14+## action.
15+##
16+# find -name '*~' -delete
17+ $(MAKE) -C sbin clean
18+ $(MAKE) -C usr_sbin clean
19+ $(MAKE) -C usr_lib_caitsith clean
20+
21+.PHONY: clean install
旧リポジトリブラウザで表示