• R/O
  • SSH
  • HTTPS

akari: 提交


Commit MetaInfo

修订版502 (tree)
时间2015-04-21 20:49:23
作者kumaneko

Log Message

1.0.33

更改概述

差异

--- tags/patches/1.0.33/load_policy.c (nonexistent)
+++ tags/patches/1.0.33/load_policy.c (revision 502)
@@ -0,0 +1,353 @@
1+/*
2+ * security/ccsecurity/load_policy.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
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+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
15+#include <linux/kmod.h>
16+/*
17+ * Regarding 2.4 kernels, we need to define __KERNEL_SYSCALLS__ in order to use
18+ * waitpid() because call_usermodehelper() does not support UMH_WAIT_PROC.
19+ */
20+#define __KERNEL_SYSCALLS__
21+#include <linux/unistd.h>
22+#else
23+#include <linux/fs.h>
24+#include <linux/namei.h>
25+#endif
26+#ifndef LOOKUP_POSITIVE
27+#define LOOKUP_POSITIVE 0
28+#endif
29+
30+/*
31+ * TOMOYO specific part start.
32+ */
33+
34+#include "internal.h"
35+
36+#if 0
37+/**
38+ * ccs_setup - Set enable/disable upon boot.
39+ *
40+ * @str: "off" to disable, "on" to enable.
41+ *
42+ * Returns 0.
43+ */
44+static int __init ccs_setup(char *str)
45+{
46+ if (!strcmp(str, "off"))
47+ ccsecurity_ops.disabled = 1;
48+ else if (!strcmp(str, "on"))
49+ ccsecurity_ops.disabled = 0;
50+ return 0;
51+}
52+
53+__setup("ccsecurity=", ccs_setup);
54+#endif
55+
56+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
57+
58+/* Path to the policy loader. (default = CONFIG_CCSECURITY_POLICY_LOADER) */
59+static const char *ccs_loader;
60+
61+#if 0
62+/**
63+ * ccs_loader_setup - Set policy loader.
64+ *
65+ * @str: Program to use as a policy loader (e.g. /sbin/ccs-init ).
66+ *
67+ * Returns 0.
68+ */
69+static int __init ccs_loader_setup(char *str)
70+{
71+ ccs_loader = str;
72+ return 0;
73+}
74+
75+__setup("CCS_loader=", ccs_loader_setup);
76+#endif
77+
78+/**
79+ * ccs_policy_loader_exists - Check whether /sbin/ccs-init exists.
80+ *
81+ * Returns true if /sbin/ccs-init exists, false otherwise.
82+ */
83+static _Bool ccs_policy_loader_exists(void)
84+{
85+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
86+ struct path path;
87+ if (!ccs_loader)
88+ ccs_loader = CONFIG_CCSECURITY_POLICY_LOADER;
89+ if (kern_path(ccs_loader, LOOKUP_FOLLOW | LOOKUP_POSITIVE,
90+ &path) == 0) {
91+ path_put(&path);
92+ return 1;
93+ }
94+#else
95+ struct nameidata nd;
96+ if (!ccs_loader)
97+ ccs_loader = CONFIG_CCSECURITY_POLICY_LOADER;
98+ if (path_lookup(ccs_loader, LOOKUP_FOLLOW | LOOKUP_POSITIVE,
99+ &nd) == 0) {
100+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
101+ path_put(&nd.path);
102+#else
103+ path_release(&nd);
104+#endif
105+ return 1;
106+ }
107+#endif
108+ printk(KERN_INFO "Not activating Mandatory Access Control "
109+ "as %s does not exist.\n", ccs_loader);
110+ return 0;
111+}
112+
113+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
114+
115+/**
116+ * ccs_run_loader - Start /sbin/ccs-init.
117+ *
118+ * @unused: Not used.
119+ *
120+ * Returns PID of /sbin/ccs-init on success, negative value otherwise.
121+ */
122+static int ccs_run_loader(void *unused)
123+{
124+ char *argv[2];
125+ char *envp[3];
126+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
127+ ccs_loader);
128+ argv[0] = (char *) ccs_loader;
129+ argv[1] = NULL;
130+ envp[0] = "HOME=/";
131+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
132+ envp[2] = NULL;
133+ return exec_usermodehelper(argv[0], argv, envp);
134+}
135+
136+#endif
137+
138+/* Path to the trigger. (default = CONFIG_CCSECURITY_ACTIVATION_TRIGGER) */
139+static const char *ccs_trigger;
140+
141+#if 0
142+/**
143+ * ccs_trigger_setup - Set trigger for activation.
144+ *
145+ * @str: Program to use as an activation trigger (e.g. /sbin/init ).
146+ *
147+ * Returns 0.
148+ */
149+static int __init ccs_trigger_setup(char *str)
150+{
151+ ccs_trigger = str;
152+ return 0;
153+}
154+
155+__setup("CCS_trigger=", ccs_trigger_setup);
156+#endif
157+
158+/**
159+ * ccs_load_policy - Run external policy loader to load policy.
160+ *
161+ * @filename: The program about to start.
162+ *
163+ * Returns nothing.
164+ *
165+ * This function checks whether @filename is /sbin/init, and if so
166+ * invoke /sbin/ccs-init and wait for the termination of /sbin/ccs-init
167+ * and then continues invocation of /sbin/init.
168+ * /sbin/ccs-init reads policy files in /etc/ccs/ directory and
169+ * writes to /proc/ccs/ interfaces.
170+ */
171+void ccs_load_policy(const char *filename)
172+{
173+ static _Bool done;
174+ if (ccsecurity_ops.disabled || done)
175+ return;
176+ if (!ccs_trigger)
177+ ccs_trigger = CONFIG_CCSECURITY_ACTIVATION_TRIGGER;
178+ if (strcmp(filename, ccs_trigger))
179+ return;
180+ if (!ccs_policy_loader_exists())
181+ return;
182+ done = 1;
183+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
184+ {
185+ char *argv[2];
186+ char *envp[3];
187+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
188+ ccs_loader);
189+ argv[0] = (char *) ccs_loader;
190+ argv[1] = NULL;
191+ envp[0] = "HOME=/";
192+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
193+ envp[2] = NULL;
194+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) || defined(UMH_WAIT_PROC)
195+ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
196+#else
197+ call_usermodehelper(argv[0], argv, envp, 1);
198+#endif
199+ }
200+#elif defined(TASK_DEAD)
201+ {
202+ /* Copied from kernel/kmod.c */
203+ struct task_struct *task = current;
204+ pid_t pid = kernel_thread(ccs_run_loader, NULL, 0);
205+ sigset_t tmpsig;
206+ spin_lock_irq(&task->sighand->siglock);
207+ tmpsig = task->blocked;
208+ siginitsetinv(&task->blocked,
209+ sigmask(SIGKILL) | sigmask(SIGSTOP));
210+ recalc_sigpending();
211+ spin_unlock_irq(&task->sighand->siglock);
212+ if (pid >= 0)
213+ waitpid(pid, NULL, __WCLONE);
214+ spin_lock_irq(&task->sighand->siglock);
215+ task->blocked = tmpsig;
216+ recalc_sigpending();
217+ spin_unlock_irq(&task->sighand->siglock);
218+ }
219+#else
220+ {
221+ /* Copied from kernel/kmod.c */
222+ struct task_struct *task = current;
223+ pid_t pid = kernel_thread(ccs_run_loader, NULL, 0);
224+ sigset_t tmpsig;
225+ spin_lock_irq(&task->sigmask_lock);
226+ tmpsig = task->blocked;
227+ siginitsetinv(&task->blocked,
228+ sigmask(SIGKILL) | sigmask(SIGSTOP));
229+ recalc_sigpending(task);
230+ spin_unlock_irq(&task->sigmask_lock);
231+ if (pid >= 0)
232+ waitpid(pid, NULL, __WCLONE);
233+ spin_lock_irq(&task->sigmask_lock);
234+ task->blocked = tmpsig;
235+ recalc_sigpending(task);
236+ spin_unlock_irq(&task->sigmask_lock);
237+ }
238+#endif
239+ if (ccsecurity_ops.check_profile)
240+ ccsecurity_ops.check_profile();
241+ else
242+ panic("Failed to load policy.");
243+}
244+
245+#endif
246+
247+#if 0
248+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
249+
250+/**
251+ * __ccs_search_binary_handler - Load policy before calling search_binary_handler().
252+ *
253+ * @bprm: Pointer to "struct linux_binprm".
254+ *
255+ * Returns 0 on success, negative value otherwise.
256+ */
257+static int __ccs_search_binary_handler(struct linux_binprm *bprm)
258+{
259+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
260+ ccs_load_policy(bprm->filename);
261+#endif
262+ /*
263+ * ccs_load_policy() executes /sbin/ccs-init if bprm->filename is
264+ * /sbin/init. /sbin/ccs-init executes /etc/ccs/ccs-load-module to
265+ * load loadable kernel module. The loadable kernel module modifies
266+ * "struct ccsecurity_ops". Thus, we need to transfer control to
267+ * __ccs_search_binary_handler() in security/ccsecurity/permission.c
268+ * if "struct ccsecurity_ops" was modified.
269+ */
270+ if (ccsecurity_ops.search_binary_handler
271+ != __ccs_search_binary_handler)
272+ return ccsecurity_ops.search_binary_handler(bprm);
273+ return search_binary_handler(bprm);
274+}
275+
276+#else
277+
278+/**
279+ * __ccs_search_binary_handler - Load policy before calling search_binary_handler().
280+ *
281+ * @bprm: Pointer to "struct linux_binprm".
282+ * @regs: Pointer to "struct pt_regs".
283+ *
284+ * Returns 0 on success, negative value otherwise.
285+ */
286+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
287+ struct pt_regs *regs)
288+{
289+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
290+ ccs_load_policy(bprm->filename);
291+#endif
292+ /*
293+ * ccs_load_policy() executes /sbin/ccs-init if bprm->filename is
294+ * /sbin/init. /sbin/ccs-init executes /etc/ccs/ccs-load-module to
295+ * load loadable kernel module. The loadable kernel module modifies
296+ * "struct ccsecurity_ops". Thus, we need to transfer control to
297+ * __ccs_search_binary_handler() in security/ccsecurity/permission.c
298+ * if "struct ccsecurity_ops" was modified.
299+ */
300+ if (ccsecurity_ops.search_binary_handler
301+ != __ccs_search_binary_handler)
302+ return ccsecurity_ops.search_binary_handler(bprm, regs);
303+ return search_binary_handler(bprm, regs);
304+}
305+
306+#endif
307+
308+/*
309+ * Some exports for loadable kernel module part.
310+ *
311+ * Although scripts/checkpatch.pl complains about use of "extern" in C file,
312+ * we don't put these into security/ccsecurity/internal.h because we want to
313+ * split built-in part and loadable kernel module part.
314+ */
315+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
316+extern spinlock_t vfsmount_lock;
317+#endif
318+
319+/* For exporting variables and functions. */
320+const struct ccsecurity_exports ccsecurity_exports = {
321+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
322+ .load_policy = ccs_load_policy,
323+#endif
324+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
325+ .d_absolute_path = d_absolute_path,
326+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
327+ .__d_path = __d_path,
328+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
329+ .vfsmount_lock = &vfsmount_lock,
330+#endif
331+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
332+ .find_task_by_vpid = find_task_by_vpid,
333+ .find_task_by_pid_ns = find_task_by_pid_ns,
334+#endif
335+};
336+#ifdef CONFIG_CCSECURITY_LKM
337+/* Only ccsecurity module need to access this struct. */
338+EXPORT_SYMBOL_GPL(ccsecurity_exports);
339+#endif
340+
341+/* Members are updated by loadable kernel module. */
342+struct ccsecurity_operations ccsecurity_ops = {
343+ .search_binary_handler = __ccs_search_binary_handler,
344+#ifdef CONFIG_CCSECURITY_DISABLE_BY_DEFAULT
345+ .disabled = 1,
346+#endif
347+};
348+/*
349+ * Non-GPL modules might need to access this struct via inlined functions
350+ * embedded into include/linux/security.h and include/net/ip.h
351+ */
352+EXPORT_SYMBOL(ccsecurity_ops);
353+#endif
--- tags/patches/1.0.33/realpath.c (nonexistent)
+++ tags/patches/1.0.33/realpath.c (revision 502)
@@ -0,0 +1,767 @@
1+/*
2+ * security/ccsecurity/realpath.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
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+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
21+#define s_fs_info u.generic_sbp
22+#endif
23+
24+/***** SECTION2: Structure definition *****/
25+
26+/***** SECTION3: Prototype definition section *****/
27+
28+char *ccs_encode(const char *str);
29+char *ccs_encode2(const char *str, int str_len);
30+char *ccs_realpath(const struct path *path);
31+const char *ccs_get_exe(void);
32+void ccs_fill_path_info(struct ccs_path_info *ptr);
33+
34+static char *ccs_get_absolute_path(const struct path *path,
35+ char * const buffer, const int buflen);
36+static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
37+ const int buflen);
38+static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
39+ const int buflen);
40+static char *ccs_get_socket_name(const struct path *path, char * const buffer,
41+ const int buflen);
42+static int ccs_const_part_length(const char *filename);
43+
44+/***** SECTION4: Standalone functions section *****/
45+
46+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
47+
48+/**
49+ * SOCKET_I - Get "struct socket".
50+ *
51+ * @inode: Pointer to "struct inode".
52+ *
53+ * Returns pointer to "struct socket".
54+ *
55+ * This is for compatibility with older kernels.
56+ */
57+static inline struct socket *SOCKET_I(struct inode *inode)
58+{
59+ return inode->i_sock ? &inode->u.socket_i : NULL;
60+}
61+
62+#endif
63+
64+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
65+
66+/**
67+ * ccs_realpath_lock - Take locks for __d_path().
68+ *
69+ * Returns nothing.
70+ */
71+static inline void ccs_realpath_lock(void)
72+{
73+ /* dcache_lock is locked by __d_path(). */
74+ /* vfsmount_lock is locked by __d_path(). */
75+}
76+
77+/**
78+ * ccs_realpath_unlock - Release locks for __d_path().
79+ *
80+ * Returns nothing.
81+ */
82+static inline void ccs_realpath_unlock(void)
83+{
84+ /* vfsmount_lock is unlocked by __d_path(). */
85+ /* dcache_lock is unlocked by __d_path(). */
86+}
87+
88+#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 36)
89+
90+/**
91+ * ccs_realpath_lock - Take locks for __d_path().
92+ *
93+ * Returns nothing.
94+ */
95+static inline void ccs_realpath_lock(void)
96+{
97+ spin_lock(&dcache_lock);
98+ /* vfsmount_lock is locked by __d_path(). */
99+}
100+
101+/**
102+ * ccs_realpath_unlock - Release locks for __d_path().
103+ *
104+ * Returns nothing.
105+ */
106+static inline void ccs_realpath_unlock(void)
107+{
108+ /* vfsmount_lock is unlocked by __d_path(). */
109+ spin_unlock(&dcache_lock);
110+}
111+
112+#elif defined(D_PATH_DISCONNECT) && !defined(CONFIG_SUSE_KERNEL)
113+
114+/**
115+ * ccs_realpath_lock - Take locks for __d_path().
116+ *
117+ * Returns nothing.
118+ *
119+ * Original unambiguous-__d_path.diff in patches.apparmor.tar.bz2 inversed the
120+ * order of holding dcache_lock and vfsmount_lock. That patch was applied on
121+ * (at least) SUSE 11.1 and Ubuntu 8.10 and Ubuntu 9.04 kernels.
122+ *
123+ * However, that patch was updated to use original order and the updated patch
124+ * is applied to (as far as I know) only SUSE kernels.
125+ *
126+ * Therefore, I need to use original order for SUSE 11.1 kernels and inversed
127+ * order for other kernels. I detect it by checking D_PATH_DISCONNECT and
128+ * CONFIG_SUSE_KERNEL. I don't know whether other distributions are using the
129+ * updated patch or not. If you got deadlock, check fs/dcache.c for locking
130+ * order, and add " && 0" to this "#elif " block if fs/dcache.c uses original
131+ * order.
132+ */
133+static inline void ccs_realpath_lock(void)
134+{
135+ spin_lock(ccsecurity_exports.vfsmount_lock);
136+ spin_lock(&dcache_lock);
137+}
138+
139+/**
140+ * ccs_realpath_unlock - Release locks for __d_path().
141+ *
142+ * Returns nothing.
143+ */
144+static inline void ccs_realpath_unlock(void)
145+{
146+ spin_unlock(&dcache_lock);
147+ spin_unlock(ccsecurity_exports.vfsmount_lock);
148+}
149+
150+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
151+
152+/**
153+ * ccs_realpath_lock - Take locks for __d_path().
154+ *
155+ * Returns nothing.
156+ */
157+static inline void ccs_realpath_lock(void)
158+{
159+ spin_lock(&dcache_lock);
160+ spin_lock(ccsecurity_exports.vfsmount_lock);
161+}
162+
163+/**
164+ * ccs_realpath_unlock - Release locks for __d_path().
165+ *
166+ * Returns nothing.
167+ */
168+static inline void ccs_realpath_unlock(void)
169+{
170+ spin_unlock(ccsecurity_exports.vfsmount_lock);
171+ spin_unlock(&dcache_lock);
172+}
173+
174+#else
175+
176+/**
177+ * ccs_realpath_lock - Take locks for __d_path().
178+ *
179+ * Returns nothing.
180+ */
181+static inline void ccs_realpath_lock(void)
182+{
183+ spin_lock(&dcache_lock);
184+}
185+
186+/**
187+ * ccs_realpath_unlock - Release locks for __d_path().
188+ *
189+ * Returns nothing.
190+ */
191+static inline void ccs_realpath_unlock(void)
192+{
193+ spin_unlock(&dcache_lock);
194+}
195+
196+#endif
197+
198+/***** SECTION5: Variables definition section *****/
199+
200+/***** SECTION6: Dependent functions section *****/
201+
202+/**
203+ * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
204+ *
205+ * @path: Pointer to "struct path".
206+ * @buffer: Pointer to buffer to return value in.
207+ * @buflen: Sizeof @buffer.
208+ *
209+ * Returns the buffer on success, an error code otherwise.
210+ *
211+ * Caller holds the dcache_lock and vfsmount_lock.
212+ * Based on __d_path() in fs/dcache.c
213+ *
214+ * If dentry is a directory, trailing '/' is appended.
215+ */
216+static char *ccs_get_absolute_path(const struct path *path,
217+ char * const buffer, const int buflen)
218+{
219+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
220+ char *pos = ERR_PTR(-ENOMEM);
221+ if (buflen >= 256) {
222+ pos = ccsecurity_exports.d_absolute_path(path, buffer,
223+ buflen - 1);
224+ if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
225+ struct inode *inode = path->dentry->d_inode;
226+ if (inode && S_ISDIR(inode->i_mode)) {
227+ buffer[buflen - 2] = '/';
228+ buffer[buflen - 1] = '\0';
229+ }
230+ }
231+ }
232+ return pos;
233+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
234+ /*
235+ * __d_path() will start returning NULL by backporting commit 02125a82
236+ * "fix apparmor dereferencing potentially freed dentry, sanitize
237+ * __d_path() API".
238+ *
239+ * Unfortunately, __d_path() after applying that commit always returns
240+ * NULL when root is empty. d_absolute_path() is provided for TOMOYO
241+ * 2.x and AppArmor but TOMOYO 1.x does not use it, for TOMOYO 1.x
242+ * might be built as a loadable kernel module and there is no warrantee
243+ * that TOMOYO 1.x is recompiled after applying that commit. Also,
244+ * I don't want to search /proc/kallsyms for d_absolute_path() because
245+ * I want to keep TOMOYO 1.x architecture independent. Thus, supply
246+ * non empty root like AppArmor's d_namespace_path() did.
247+ */
248+ char *pos = ERR_PTR(-ENOMEM);
249+ if (buflen >= 256) {
250+ static bool ccs_no_empty;
251+ if (!ccs_no_empty) {
252+ struct path root = { };
253+ pos = ccsecurity_exports.__d_path(path, &root, buffer,
254+ buflen - 1);
255+ } else {
256+ pos = NULL;
257+ }
258+ if (!pos) {
259+ struct task_struct *task = current;
260+ struct path root;
261+ struct path tmp;
262+ spin_lock(&task->fs->lock);
263+ root.mnt = task->nsproxy->mnt_ns->root;
264+ root.dentry = root.mnt->mnt_root;
265+ path_get(&root);
266+ spin_unlock(&task->fs->lock);
267+ tmp = root;
268+ pos = ccsecurity_exports.__d_path(path, &tmp, buffer,
269+ buflen - 1);
270+ path_put(&root);
271+ if (!pos)
272+ return ERR_PTR(-EINVAL);
273+ /* Remember if __d_path() needs non empty root. */
274+ ccs_no_empty = true;
275+ }
276+ if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
277+ struct inode *inode = path->dentry->d_inode;
278+ if (inode && S_ISDIR(inode->i_mode)) {
279+ buffer[buflen - 2] = '/';
280+ buffer[buflen - 1] = '\0';
281+ }
282+ }
283+ }
284+ return pos;
285+#else
286+ char *pos = buffer + buflen - 1;
287+ struct dentry *dentry = path->dentry;
288+ struct vfsmount *vfsmnt = path->mnt;
289+ const char *name;
290+ int len;
291+
292+ if (buflen < 256)
293+ goto out;
294+
295+ *pos = '\0';
296+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
297+ *--pos = '/';
298+ for (;;) {
299+ struct dentry *parent;
300+ if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
301+ if (vfsmnt->mnt_parent == vfsmnt)
302+ break;
303+ dentry = vfsmnt->mnt_mountpoint;
304+ vfsmnt = vfsmnt->mnt_parent;
305+ continue;
306+ }
307+ parent = dentry->d_parent;
308+ name = dentry->d_name.name;
309+ len = dentry->d_name.len;
310+ pos -= len;
311+ if (pos <= buffer)
312+ goto out;
313+ memmove(pos, name, len);
314+ *--pos = '/';
315+ dentry = parent;
316+ }
317+ if (*pos == '/')
318+ pos++;
319+ len = dentry->d_name.len;
320+ pos -= len;
321+ if (pos < buffer)
322+ goto out;
323+ memmove(pos, dentry->d_name.name, len);
324+ return pos;
325+out:
326+ return ERR_PTR(-ENOMEM);
327+#endif
328+}
329+
330+/**
331+ * ccs_get_dentry_path - Get the path of a dentry.
332+ *
333+ * @dentry: Pointer to "struct dentry".
334+ * @buffer: Pointer to buffer to return value in.
335+ * @buflen: Sizeof @buffer.
336+ *
337+ * Returns the buffer on success, an error code otherwise.
338+ *
339+ * Based on dentry_path() in fs/dcache.c
340+ *
341+ * If dentry is a directory, trailing '/' is appended.
342+ */
343+static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
344+ const int buflen)
345+{
346+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
347+ char *pos = ERR_PTR(-ENOMEM);
348+ if (buflen >= 256) {
349+ pos = dentry_path_raw(dentry, buffer, buflen - 1);
350+ if (!IS_ERR(pos) && *pos == '/' && pos[1] &&
351+ d_is_dir(dentry)) {
352+ buffer[buflen - 2] = '/';
353+ buffer[buflen - 1] = '\0';
354+ }
355+ }
356+ return pos;
357+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
358+ char *pos = ERR_PTR(-ENOMEM);
359+ if (buflen >= 256) {
360+ /* rename_lock is locked/unlocked by dentry_path_raw(). */
361+ pos = dentry_path_raw(dentry, buffer, buflen - 1);
362+ if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
363+ struct inode *inode = dentry->d_inode;
364+ if (inode && S_ISDIR(inode->i_mode)) {
365+ buffer[buflen - 2] = '/';
366+ buffer[buflen - 1] = '\0';
367+ }
368+ }
369+ }
370+ return pos;
371+#else
372+ char *pos = buffer + buflen - 1;
373+ if (buflen < 256)
374+ return ERR_PTR(-ENOMEM);
375+ *pos = '\0';
376+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
377+ *--pos = '/';
378+ spin_lock(&dcache_lock);
379+ while (!IS_ROOT(dentry)) {
380+ struct dentry *parent = dentry->d_parent;
381+ const char *name = dentry->d_name.name;
382+ const int len = dentry->d_name.len;
383+ pos -= len;
384+ if (pos <= buffer) {
385+ pos = ERR_PTR(-ENOMEM);
386+ break;
387+ }
388+ memmove(pos, name, len);
389+ *--pos = '/';
390+ dentry = parent;
391+ }
392+ spin_unlock(&dcache_lock);
393+ return pos;
394+#endif
395+}
396+
397+/**
398+ * ccs_get_local_path - Get the path of a dentry.
399+ *
400+ * @dentry: Pointer to "struct dentry".
401+ * @buffer: Pointer to buffer to return value in.
402+ * @buflen: Sizeof @buffer.
403+ *
404+ * Returns the buffer on success, an error code otherwise.
405+ */
406+static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
407+ const int buflen)
408+{
409+ struct super_block *sb = dentry->d_sb;
410+ char *pos = ccs_get_dentry_path(dentry, buffer, buflen);
411+ if (IS_ERR(pos))
412+ return pos;
413+ /* Convert from $PID to self if $PID is current thread. */
414+ if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
415+ char *ep;
416+ const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
417+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
418+ if (*ep == '/' && pid && pid ==
419+ task_tgid_nr_ns(current, sb->s_fs_info)) {
420+ pos = ep - 5;
421+ if (pos < buffer)
422+ goto out;
423+ memmove(pos, "/self", 5);
424+ }
425+#else
426+ if (*ep == '/' && pid == ccs_sys_getpid()) {
427+ pos = ep - 5;
428+ if (pos < buffer)
429+ goto out;
430+ memmove(pos, "/self", 5);
431+ }
432+#endif
433+ goto prepend_filesystem_name;
434+ }
435+ /* Use filesystem name for unnamed devices. */
436+ if (!MAJOR(sb->s_dev))
437+ goto prepend_filesystem_name;
438+ {
439+ struct inode *inode = sb->s_root->d_inode;
440+ /*
441+ * Use filesystem name if filesystems does not support rename()
442+ * operation.
443+ */
444+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
445+ if (inode->i_op && !inode->i_op->rename)
446+ goto prepend_filesystem_name;
447+#else
448+ if (!inode->i_op->rename && !inode->i_op->rename2)
449+ goto prepend_filesystem_name;
450+#endif
451+ }
452+ /* Prepend device name. */
453+ {
454+ char name[64];
455+ int name_len;
456+ const dev_t dev = sb->s_dev;
457+ name[sizeof(name) - 1] = '\0';
458+ snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
459+ MINOR(dev));
460+ name_len = strlen(name);
461+ pos -= name_len;
462+ if (pos < buffer)
463+ goto out;
464+ memmove(pos, name, name_len);
465+ return pos;
466+ }
467+ /* Prepend filesystem name. */
468+prepend_filesystem_name:
469+ {
470+ const char *name = sb->s_type->name;
471+ const int name_len = strlen(name);
472+ pos -= name_len + 1;
473+ if (pos < buffer)
474+ goto out;
475+ memmove(pos, name, name_len);
476+ pos[name_len] = ':';
477+ }
478+ return pos;
479+out:
480+ return ERR_PTR(-ENOMEM);
481+}
482+
483+/**
484+ * ccs_get_socket_name - Get the name of a socket.
485+ *
486+ * @path: Pointer to "struct path".
487+ * @buffer: Pointer to buffer to return value in.
488+ * @buflen: Sizeof @buffer.
489+ *
490+ * Returns the buffer.
491+ */
492+static char *ccs_get_socket_name(const struct path *path, char * const buffer,
493+ const int buflen)
494+{
495+ struct inode *inode = path->dentry->d_inode;
496+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
497+ struct sock *sk = sock ? sock->sk : NULL;
498+ if (sk) {
499+ snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
500+ "protocol=%u]", sk->sk_family, sk->sk_type,
501+ sk->sk_protocol);
502+ } else {
503+ snprintf(buffer, buflen, "socket:[unknown]");
504+ }
505+ return buffer;
506+}
507+
508+#define SOCKFS_MAGIC 0x534F434B
509+
510+/**
511+ * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root.
512+ *
513+ * @path: Pointer to "struct path".
514+ *
515+ * Returns the realpath of the given @path on success, NULL otherwise.
516+ *
517+ * This function uses kzalloc(), so caller must kfree() if this function
518+ * didn't return NULL.
519+ */
520+char *ccs_realpath(const struct path *path)
521+{
522+ char *buf = NULL;
523+ char *name = NULL;
524+ unsigned int buf_len = PAGE_SIZE / 2;
525+ struct dentry *dentry = path->dentry;
526+ struct super_block *sb;
527+ if (!dentry)
528+ return NULL;
529+ sb = dentry->d_sb;
530+ while (1) {
531+ char *pos;
532+ struct inode *inode;
533+ buf_len <<= 1;
534+ kfree(buf);
535+ buf = kmalloc(buf_len, CCS_GFP_FLAGS);
536+ if (!buf)
537+ break;
538+ /* To make sure that pos is '\0' terminated. */
539+ buf[buf_len - 1] = '\0';
540+ /* Get better name for socket. */
541+ if (sb->s_magic == SOCKFS_MAGIC) {
542+ pos = ccs_get_socket_name(path, buf, buf_len - 1);
543+ goto encode;
544+ }
545+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
546+ /* For "pipe:[\$]". */
547+ if (dentry->d_op && dentry->d_op->d_dname) {
548+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
549+ goto encode;
550+ }
551+#endif
552+ inode = sb->s_root->d_inode;
553+ /*
554+ * Use local name for "filesystems without rename() operation"
555+ * or "path without vfsmount" or "absolute name is unavailable"
556+ * cases.
557+ */
558+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
559+ if (!path->mnt || (inode->i_op && !inode->i_op->rename))
560+ pos = ERR_PTR(-EINVAL);
561+ else {
562+ /* Get absolute name for the rest. */
563+ ccs_realpath_lock();
564+ pos = ccs_get_absolute_path(path, buf, buf_len - 1);
565+ ccs_realpath_unlock();
566+ }
567+ if (pos == ERR_PTR(-EINVAL))
568+ pos = ccs_get_local_path(path->dentry, buf,
569+ buf_len - 1);
570+#else
571+ if (!path->mnt ||
572+ (!inode->i_op->rename && !inode->i_op->rename2))
573+ pos = ccs_get_local_path(path->dentry, buf,
574+ buf_len - 1);
575+ else
576+ pos = ccs_get_absolute_path(path, buf, buf_len - 1);
577+#endif
578+encode:
579+ if (IS_ERR(pos))
580+ continue;
581+ name = ccs_encode(pos);
582+ break;
583+ }
584+ kfree(buf);
585+ if (!name)
586+ ccs_warn_oom(__func__);
587+ return name;
588+}
589+
590+/**
591+ * ccs_encode2 - Encode binary string to ascii string.
592+ *
593+ * @str: String in binary format.
594+ * @str_len: Size of @str in byte.
595+ *
596+ * Returns pointer to @str in ascii format on success, NULL otherwise.
597+ *
598+ * This function uses kzalloc(), so caller must kfree() if this function
599+ * didn't return NULL.
600+ */
601+char *ccs_encode2(const char *str, int str_len)
602+{
603+ int i;
604+ int len = 0;
605+ const char *p = str;
606+ char *cp;
607+ char *cp0;
608+ if (!p)
609+ return NULL;
610+ for (i = 0; i < str_len; i++) {
611+ const unsigned char c = p[i];
612+ if (c == '\\')
613+ len += 2;
614+ else if (c > ' ' && c < 127)
615+ len++;
616+ else
617+ len += 4;
618+ }
619+ len++;
620+ /* Reserve space for appending "/". */
621+ cp = kzalloc(len + 10, CCS_GFP_FLAGS);
622+ if (!cp)
623+ return NULL;
624+ cp0 = cp;
625+ p = str;
626+ for (i = 0; i < str_len; i++) {
627+ const unsigned char c = p[i];
628+ if (c == '\\') {
629+ *cp++ = '\\';
630+ *cp++ = '\\';
631+ } else if (c > ' ' && c < 127) {
632+ *cp++ = c;
633+ } else {
634+ *cp++ = '\\';
635+ *cp++ = (c >> 6) + '0';
636+ *cp++ = ((c >> 3) & 7) + '0';
637+ *cp++ = (c & 7) + '0';
638+ }
639+ }
640+ return cp0;
641+}
642+
643+/**
644+ * ccs_encode - Encode binary string to ascii string.
645+ *
646+ * @str: String in binary format.
647+ *
648+ * Returns pointer to @str in ascii format on success, NULL otherwise.
649+ *
650+ * This function uses kzalloc(), so caller must kfree() if this function
651+ * didn't return NULL.
652+ */
653+char *ccs_encode(const char *str)
654+{
655+ return str ? ccs_encode2(str, strlen(str)) : NULL;
656+}
657+
658+/**
659+ * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
660+ *
661+ * @filename: The string to evaluate.
662+ *
663+ * Returns the initial length without a pattern in @filename.
664+ */
665+static int ccs_const_part_length(const char *filename)
666+{
667+ char c;
668+ int len = 0;
669+ if (!filename)
670+ return 0;
671+ while (1) {
672+ c = *filename++;
673+ if (!c)
674+ break;
675+ if (c != '\\') {
676+ len++;
677+ continue;
678+ }
679+ c = *filename++;
680+ switch (c) {
681+ case '\\': /* "\\" */
682+ len += 2;
683+ continue;
684+ case '0': /* "\ooo" */
685+ case '1':
686+ case '2':
687+ case '3':
688+ c = *filename++;
689+ if (c < '0' || c > '7')
690+ break;
691+ c = *filename++;
692+ if (c < '0' || c > '7')
693+ break;
694+ len += 4;
695+ continue;
696+ }
697+ break;
698+ }
699+ return len;
700+}
701+
702+/**
703+ * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
704+ *
705+ * @ptr: Pointer to "struct ccs_path_info" to fill in.
706+ *
707+ * The caller sets "struct ccs_path_info"->name.
708+ */
709+void ccs_fill_path_info(struct ccs_path_info *ptr)
710+{
711+ const char *name = ptr->name;
712+ const int len = strlen(name);
713+ ptr->total_len = len;
714+ ptr->const_len = ccs_const_part_length(name);
715+ ptr->is_dir = len && (name[len - 1] == '/');
716+ ptr->is_patterned = (ptr->const_len < len);
717+ ptr->hash = full_name_hash(name, len);
718+}
719+
720+/**
721+ * ccs_get_exe - Get ccs_realpath() of current process.
722+ *
723+ * Returns the ccs_realpath() of current process on success, NULL otherwise.
724+ *
725+ * This function uses kzalloc(), so the caller must kfree()
726+ * if this function didn't return NULL.
727+ */
728+const char *ccs_get_exe(void)
729+{
730+ struct mm_struct *mm = current->mm;
731+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
732+ struct vm_area_struct *vma;
733+#endif
734+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
735+ struct path path;
736+#endif
737+ struct file *exe_file = NULL;
738+ const char *cp;
739+ if (!mm)
740+ return NULL;
741+ down_read(&mm->mmap_sem);
742+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
743+ /* Not using get_mm_exe_file() as it is not exported. */
744+ exe_file = mm->exe_file;
745+#else
746+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
747+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
748+ exe_file = vma->vm_file;
749+ break;
750+ }
751+ }
752+#endif
753+ if (exe_file)
754+ get_file(exe_file);
755+ up_read(&mm->mmap_sem);
756+ if (!exe_file)
757+ return NULL;
758+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
759+ cp = ccs_realpath(&exe_file->f_path);
760+#else
761+ path.mnt = exe_file->f_vfsmnt;
762+ path.dentry = exe_file->f_dentry;
763+ cp = ccs_realpath(&path);
764+#endif
765+ fput(exe_file);
766+ return cp;
767+}
--- tags/patches/1.0.33/memory.c (nonexistent)
+++ tags/patches/1.0.33/memory.c (revision 502)
@@ -0,0 +1,361 @@
1+/*
2+ * security/ccsecurity/memory.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
7+ */
8+
9+#include "internal.h"
10+
11+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
12+/* Use functions in lsm.c */
13+#undef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
14+#endif
15+
16+/***** SECTION1: Constants definition *****/
17+
18+/***** SECTION2: Structure definition *****/
19+
20+/***** SECTION3: Prototype definition section *****/
21+
22+bool ccs_memory_ok(const void *ptr, const unsigned int size);
23+const struct ccs_path_info *ccs_get_name(const char *name);
24+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
25+struct ccs_security *ccs_find_task_security(const struct task_struct *task);
26+#endif
27+void *ccs_commit_ok(void *data, const unsigned int size);
28+void __init ccs_mm_init(void);
29+void ccs_warn_oom(const char *function);
30+
31+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
32+static int __ccs_alloc_task_security(const struct task_struct *task);
33+static void __ccs_free_task_security(const struct task_struct *task);
34+static void ccs_add_task_security(struct ccs_security *ptr,
35+ struct list_head *list);
36+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
37+static void ccs_rcu_free(struct rcu_head *rcu);
38+#else
39+static void ccs_rcu_free(void *arg);
40+#endif
41+#endif
42+
43+/***** SECTION4: Standalone functions section *****/
44+
45+/***** SECTION5: Variables definition section *****/
46+
47+/* Memoy currently used by policy/audit log/query. */
48+unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
49+
50+/* Memory quota for "policy"/"audit log"/"query". */
51+unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
52+
53+/* The list for "struct ccs_name". */
54+struct list_head ccs_name_list[CCS_MAX_HASH];
55+
56+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
57+
58+/* Dummy security context for avoiding NULL pointer dereference. */
59+struct ccs_security ccs_oom_security = {
60+ .ccs_domain_info = &ccs_kernel_domain
61+};
62+
63+/* Dummy security context for avoiding NULL pointer dereference. */
64+struct ccs_security ccs_default_security = {
65+ .ccs_domain_info = &ccs_kernel_domain
66+};
67+
68+/* List of "struct ccs_security". */
69+struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
70+/* Lock for protecting ccs_task_security_list[]. */
71+static DEFINE_SPINLOCK(ccs_task_security_list_lock);
72+
73+#endif
74+
75+/***** SECTION6: Dependent functions section *****/
76+
77+/**
78+ * ccs_warn_oom - Print out of memory warning message.
79+ *
80+ * @function: Function's name.
81+ *
82+ * Returns nothing.
83+ */
84+void ccs_warn_oom(const char *function)
85+{
86+ /* Reduce error messages. */
87+ static pid_t ccs_last_pid;
88+ const pid_t pid = current->pid;
89+ if (ccs_last_pid != pid) {
90+ printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
91+ function);
92+ ccs_last_pid = pid;
93+ }
94+ if (!ccs_policy_loaded)
95+ panic("MAC Initialization failed.\n");
96+}
97+
98+/**
99+ * ccs_memory_ok - Check memory quota.
100+ *
101+ * @ptr: Pointer to allocated memory. Maybe NULL.
102+ * @size: Size in byte. Not used if @ptr is NULL.
103+ *
104+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
105+ *
106+ * Caller holds ccs_policy_lock mutex.
107+ */
108+bool ccs_memory_ok(const void *ptr, const unsigned int size)
109+{
110+ if (ptr) {
111+ const size_t s = ccs_round2(size);
112+ ccs_memory_used[CCS_MEMORY_POLICY] += s;
113+ if (!ccs_memory_quota[CCS_MEMORY_POLICY] ||
114+ ccs_memory_used[CCS_MEMORY_POLICY] <=
115+ ccs_memory_quota[CCS_MEMORY_POLICY])
116+ return true;
117+ ccs_memory_used[CCS_MEMORY_POLICY] -= s;
118+ }
119+ ccs_warn_oom(__func__);
120+ return false;
121+}
122+
123+/**
124+ * ccs_commit_ok - Allocate memory and check memory quota.
125+ *
126+ * @data: Data to copy from.
127+ * @size: Size in byte.
128+ *
129+ * Returns pointer to allocated memory on success, NULL otherwise.
130+ * @data is zero-cleared on success.
131+ *
132+ * Caller holds ccs_policy_lock mutex.
133+ */
134+void *ccs_commit_ok(void *data, const unsigned int size)
135+{
136+ void *ptr = kmalloc(size, CCS_GFP_FLAGS);
137+ if (ccs_memory_ok(ptr, size)) {
138+ memmove(ptr, data, size);
139+ memset(data, 0, size);
140+ return ptr;
141+ }
142+ kfree(ptr);
143+ return NULL;
144+}
145+
146+/**
147+ * ccs_get_name - Allocate memory for string data.
148+ *
149+ * @name: The string to store into the permernent memory.
150+ *
151+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
152+ */
153+const struct ccs_path_info *ccs_get_name(const char *name)
154+{
155+ struct ccs_name *ptr;
156+ unsigned int hash;
157+ int len;
158+ int allocated_len;
159+ struct list_head *head;
160+
161+ if (!name)
162+ return NULL;
163+ len = strlen(name) + 1;
164+ hash = full_name_hash((const unsigned char *) name, len - 1);
165+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(RHEL_MAJOR)
166+ head = &ccs_name_list[hash_long(hash, CCS_HASH_BITS)];
167+#else
168+ head = &ccs_name_list[hash % CCS_MAX_HASH];
169+#endif
170+ if (mutex_lock_interruptible(&ccs_policy_lock))
171+ return NULL;
172+ list_for_each_entry(ptr, head, head.list) {
173+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
174+ atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
175+ continue;
176+ atomic_inc(&ptr->head.users);
177+ goto out;
178+ }
179+ allocated_len = sizeof(*ptr) + len;
180+ ptr = kzalloc(allocated_len, CCS_GFP_FLAGS);
181+ if (ccs_memory_ok(ptr, allocated_len)) {
182+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
183+ memmove((char *) ptr->entry.name, name, len);
184+ atomic_set(&ptr->head.users, 1);
185+ ccs_fill_path_info(&ptr->entry);
186+ ptr->size = allocated_len;
187+ list_add_tail(&ptr->head.list, head);
188+ } else {
189+ kfree(ptr);
190+ ptr = NULL;
191+ }
192+out:
193+ mutex_unlock(&ccs_policy_lock);
194+ return ptr ? &ptr->entry : NULL;
195+}
196+
197+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
198+
199+/**
200+ * ccs_add_task_security - Add "struct ccs_security" to list.
201+ *
202+ * @ptr: Pointer to "struct ccs_security".
203+ * @list: Pointer to "struct list_head".
204+ *
205+ * Returns nothing.
206+ */
207+static void ccs_add_task_security(struct ccs_security *ptr,
208+ struct list_head *list)
209+{
210+ unsigned long flags;
211+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
212+ list_add_rcu(&ptr->list, list);
213+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
214+}
215+
216+/**
217+ * __ccs_alloc_task_security - Allocate memory for new tasks.
218+ *
219+ * @task: Pointer to "struct task_struct".
220+ *
221+ * Returns 0 on success, negative value otherwise.
222+ */
223+static int __ccs_alloc_task_security(const struct task_struct *task)
224+{
225+ struct ccs_security *old_security = ccs_current_security();
226+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
227+ GFP_KERNEL);
228+ struct list_head *list = &ccs_task_security_list
229+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
230+ if (!new_security)
231+ return -ENOMEM;
232+ new_security->task = task;
233+ new_security->ccs_domain_info = old_security->ccs_domain_info;
234+ new_security->ccs_flags = old_security->ccs_flags;
235+ ccs_add_task_security(new_security, list);
236+ return 0;
237+}
238+
239+/**
240+ * ccs_find_task_security - Find "struct ccs_security" for given task.
241+ *
242+ * @task: Pointer to "struct task_struct".
243+ *
244+ * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
245+ * out of memory, &ccs_default_security otherwise.
246+ *
247+ * If @task is current thread and "struct ccs_security" for current thread was
248+ * not found, I try to allocate it. But if allocation failed, current thread
249+ * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
250+ * won't work.
251+ */
252+struct ccs_security *ccs_find_task_security(const struct task_struct *task)
253+{
254+ struct ccs_security *ptr;
255+ struct list_head *list = &ccs_task_security_list
256+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
257+ /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
258+ while (!list->next);
259+ rcu_read_lock();
260+ list_for_each_entry_rcu(ptr, list, list) {
261+ if (ptr->task != task)
262+ continue;
263+ rcu_read_unlock();
264+ return ptr;
265+ }
266+ rcu_read_unlock();
267+ if (task != current)
268+ return &ccs_default_security;
269+ /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
270+ ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
271+ if (!ptr) {
272+ printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
273+ task->pid);
274+ send_sig(SIGKILL, current, 0);
275+ return &ccs_oom_security;
276+ }
277+ *ptr = ccs_default_security;
278+ ptr->task = task;
279+ ccs_add_task_security(ptr, list);
280+ return ptr;
281+}
282+
283+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
284+
285+/**
286+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
287+ *
288+ * @rcu: Pointer to "struct rcu_head".
289+ *
290+ * Returns nothing.
291+ */
292+static void ccs_rcu_free(struct rcu_head *rcu)
293+{
294+ struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
295+ kfree(ptr);
296+}
297+
298+#else
299+
300+/**
301+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
302+ *
303+ * @arg: Pointer to "void".
304+ *
305+ * Returns nothing.
306+ */
307+static void ccs_rcu_free(void *arg)
308+{
309+ struct ccs_security *ptr = arg;
310+ kfree(ptr);
311+}
312+
313+#endif
314+
315+/**
316+ * __ccs_free_task_security - Release memory associated with "struct task_struct".
317+ *
318+ * @task: Pointer to "struct task_struct".
319+ *
320+ * Returns nothing.
321+ */
322+static void __ccs_free_task_security(const struct task_struct *task)
323+{
324+ unsigned long flags;
325+ struct ccs_security *ptr = ccs_find_task_security(task);
326+ if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
327+ return;
328+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
329+ list_del_rcu(&ptr->list);
330+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
331+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
332+ call_rcu(&ptr->rcu, ccs_rcu_free);
333+#else
334+ call_rcu(&ptr->rcu, ccs_rcu_free, ptr);
335+#endif
336+}
337+
338+#endif
339+
340+/**
341+ * ccs_mm_init - Initialize mm related code.
342+ *
343+ * Returns nothing.
344+ */
345+void __init ccs_mm_init(void)
346+{
347+ int idx;
348+ for (idx = 0; idx < CCS_MAX_HASH; idx++)
349+ INIT_LIST_HEAD(&ccs_name_list[idx]);
350+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
351+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++)
352+ INIT_LIST_HEAD(&ccs_task_security_list[idx]);
353+#endif
354+ smp_wmb(); /* Avoid out of order execution. */
355+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
356+ ccsecurity_ops.alloc_task_security = __ccs_alloc_task_security;
357+ ccsecurity_ops.free_task_security = __ccs_free_task_security;
358+#endif
359+ ccs_kernel_domain.domainname = ccs_get_name("<kernel>");
360+ list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
361+}
--- tags/patches/1.0.33/mclsm.c (nonexistent)
+++ tags/patches/1.0.33/mclsm.c (revision 502)
@@ -0,0 +1,1492 @@
1+/*
2+ * mclsm.c
3+ *
4+ * Copyright (C) 2010-2013 Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
5+ *
6+ * Version: 1.0.33 2015/04/21
7+ */
8+
9+#include "internal.h"
10+#include "probe.h"
11+
12+/* Prototype definition. */
13+static void ccs_task_security_gc(void);
14+static int ccs_copy_cred_security(const struct cred *new,
15+ const struct cred *old, gfp_t gfp);
16+static struct ccs_security *ccs_find_cred_security(const struct cred *cred);
17+static DEFINE_SPINLOCK(ccs_task_security_list_lock);
18+static atomic_t ccs_in_execve_tasks = ATOMIC_INIT(0);
19+/*
20+ * List of "struct ccs_security" for "struct pid".
21+ *
22+ * All instances on this list is guaranteed that "struct ccs_security"->pid !=
23+ * NULL. Also, instances on this list that are in execve() are guaranteed that
24+ * "struct ccs_security"->cred remembers "struct linux_binprm"->cred with a
25+ * refcount on "struct linux_binprm"->cred.
26+ */
27+struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
28+/*
29+ * List of "struct ccs_security" for "struct cred".
30+ *
31+ * Since the number of "struct cred" is nearly equals to the number of
32+ * "struct pid", we allocate hash tables like ccs_task_security_list.
33+ *
34+ * All instances on this list are guaranteed that "struct ccs_security"->pid ==
35+ * NULL and "struct ccs_security"->cred != NULL.
36+ */
37+static struct list_head ccs_cred_security_list[CCS_MAX_TASK_SECURITY_HASH];
38+
39+/* Dummy security context for avoiding NULL pointer dereference. */
40+static struct ccs_security ccs_oom_security = {
41+ .ccs_domain_info = &ccs_kernel_domain
42+};
43+
44+/* Dummy security context for avoiding NULL pointer dereference. */
45+static struct ccs_security ccs_default_security = {
46+ .ccs_domain_info = &ccs_kernel_domain
47+};
48+
49+/* For exporting variables and functions. */
50+struct ccsecurity_exports ccsecurity_exports;
51+/* Members are updated by loadable kernel module. */
52+struct ccsecurity_operations ccsecurity_ops;
53+
54+/* Original hooks. */
55+static union security_list_options original_cred_prepare;
56+static union security_list_options original_cred_free;
57+static union security_list_options original_cred_alloc_blank;
58+
59+#ifdef CONFIG_AKARI_TRACE_EXECVE_COUNT
60+
61+/**
62+ * ccs_update_ee_counter - Update "struct ccs_execve" counter.
63+ *
64+ * @count: Count to increment or decrement.
65+ *
66+ * Returns updated counter.
67+ */
68+static unsigned int ccs_update_ee_counter(int count)
69+{
70+ /* Debug counter for detecting "struct ccs_execve" memory leak. */
71+ static atomic_t ccs_ee_counter = ATOMIC_INIT(0);
72+ return atomic_add_return(count, &ccs_ee_counter);
73+}
74+
75+/**
76+ * ccs_audit_alloc_execve - Audit allocation of "struct ccs_execve".
77+ *
78+ * @ee: Pointer to "struct ccs_execve".
79+ *
80+ * Returns nothing.
81+ */
82+void ccs_audit_alloc_execve(const struct ccs_execve * const ee)
83+{
84+ printk(KERN_INFO "AKARI: Allocated %p by pid=%u (count=%u)\n", ee,
85+ current->pid, ccs_update_ee_counter(1) - 1);
86+}
87+
88+/**
89+ * ccs_audit_free_execve - Audit release of "struct ccs_execve".
90+ *
91+ * @ee: Pointer to "struct ccs_execve".
92+ * @task: True if released by current task, false otherwise.
93+ *
94+ * Returns nothing.
95+ */
96+void ccs_audit_free_execve(const struct ccs_execve * const ee,
97+ const bool is_current)
98+{
99+ const unsigned int tmp = ccs_update_ee_counter(-1);
100+ if (is_current)
101+ printk(KERN_INFO "AKARI: Releasing %p by pid=%u (count=%u)\n",
102+ ee, current->pid, tmp);
103+ else
104+ printk(KERN_INFO "AKARI: Releasing %p by kernel (count=%u)\n",
105+ ee, tmp);
106+}
107+
108+#endif
109+
110+#if !defined(CONFIG_AKARI_DEBUG)
111+#define ccs_debug_trace(pos) do { } while (0)
112+#else
113+#define ccs_debug_trace(pos) \
114+ do { \
115+ static bool done; \
116+ if (!done) { \
117+ printk(KERN_INFO \
118+ "AKARI: Debug trace: " pos " of 4\n"); \
119+ done = true; \
120+ } \
121+ } while (0)
122+#endif
123+
124+/**
125+ * ccs_clear_execve - Release memory used by do_execve().
126+ *
127+ * @ret: 0 if do_execve() succeeded, negative value otherwise.
128+ * @security: Pointer to "struct ccs_security".
129+ *
130+ * Returns nothing.
131+ */
132+static void ccs_clear_execve(int ret, struct ccs_security *security)
133+{
134+ struct ccs_execve *ee;
135+ if (security == &ccs_default_security || security == &ccs_oom_security)
136+ return;
137+ ee = security->ee;
138+ security->ee = NULL;
139+ if (!ee)
140+ return;
141+ atomic_dec(&ccs_in_execve_tasks);
142+ ccs_finish_execve(ret, ee);
143+}
144+
145+/**
146+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
147+ *
148+ * @rcu: Pointer to "struct rcu_head".
149+ *
150+ * Returns nothing.
151+ */
152+static void ccs_rcu_free(struct rcu_head *rcu)
153+{
154+ struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
155+ struct ccs_execve *ee = ptr->ee;
156+ /*
157+ * If this security context was associated with "struct pid" and
158+ * ptr->ccs_flags has CCS_TASK_IS_IN_EXECVE set, it indicates that a
159+ * "struct task_struct" associated with this security context exited
160+ * immediately after do_execve() has failed.
161+ */
162+ if (ptr->pid && (ptr->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
163+ ccs_debug_trace("1");
164+ atomic_dec(&ccs_in_execve_tasks);
165+ }
166+ /*
167+ * If this security context was associated with "struct pid",
168+ * drop refcount obtained by get_pid() in ccs_find_task_security().
169+ */
170+ if (ptr->pid) {
171+ ccs_debug_trace("2");
172+ put_pid(ptr->pid);
173+ }
174+ if (ee) {
175+ ccs_debug_trace("3");
176+ ccs_audit_free_execve(ee, false);
177+ kfree(ee->handler_path);
178+ kfree(ee);
179+ }
180+ kfree(ptr);
181+}
182+
183+/**
184+ * ccs_del_security - Release "struct ccs_security".
185+ *
186+ * @ptr: Pointer to "struct ccs_security".
187+ *
188+ * Returns nothing.
189+ */
190+static void ccs_del_security(struct ccs_security *ptr)
191+{
192+ unsigned long flags;
193+ if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
194+ return;
195+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
196+ list_del_rcu(&ptr->list);
197+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
198+ call_rcu(&ptr->rcu, ccs_rcu_free);
199+}
200+
201+/**
202+ * ccs_add_cred_security - Add "struct ccs_security" to list.
203+ *
204+ * @ptr: Pointer to "struct ccs_security".
205+ *
206+ * Returns nothing.
207+ */
208+static void ccs_add_cred_security(struct ccs_security *ptr)
209+{
210+ unsigned long flags;
211+ struct list_head *list = &ccs_cred_security_list
212+ [hash_ptr((void *) ptr->cred, CCS_TASK_SECURITY_HASH_BITS)];
213+#ifdef CONFIG_AKARI_DEBUG
214+ if (ptr->pid)
215+ printk(KERN_INFO "AKARI: \"struct ccs_security\"->pid != NULL"
216+ "\n");
217+#endif
218+ ptr->pid = NULL;
219+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
220+ list_add_rcu(&ptr->list, list);
221+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
222+}
223+
224+/**
225+ * ccs_task_create - Make snapshot of security context for new task.
226+ *
227+ * @clone_flags: Flags passed to clone().
228+ *
229+ * Returns 0 on success, negative value otherwise.
230+ */
231+static int ccs_task_create(unsigned long clone_flags)
232+{
233+ struct ccs_security *old_security;
234+ struct ccs_security *new_security;
235+ struct cred *cred = prepare_creds();
236+ if (!cred)
237+ return -ENOMEM;
238+ old_security = ccs_find_task_security(current);
239+ new_security = ccs_find_cred_security(cred);
240+ new_security->ccs_domain_info = old_security->ccs_domain_info;
241+ new_security->ccs_flags = old_security->ccs_flags;
242+ return commit_creds(cred);
243+}
244+
245+/**
246+ * ccs_cred_prepare - Allocate memory for new credentials.
247+ *
248+ * @new: Pointer to "struct cred".
249+ * @old: Pointer to "struct cred".
250+ * @gfp: Memory allocation flags.
251+ *
252+ * Returns 0 on success, negative value otherwise.
253+ */
254+static int ccs_cred_prepare(struct cred *new, const struct cred *old,
255+ gfp_t gfp)
256+{
257+ int rc1;
258+ /*
259+ * For checking whether reverting domain transition is needed or not.
260+ *
261+ * See ccs_find_task_security() for reason.
262+ */
263+ if (gfp == GFP_KERNEL)
264+ ccs_find_task_security(current);
265+ rc1 = ccs_copy_cred_security(new, old, gfp);
266+ if (gfp == GFP_KERNEL)
267+ ccs_task_security_gc();
268+ if (original_cred_prepare.cred_prepare) {
269+ const int rc2 = original_cred_prepare.cred_prepare(new, old,
270+ gfp);
271+ if (rc2) {
272+ ccs_del_security(ccs_find_cred_security(new));
273+ return rc2;
274+ }
275+ }
276+ return rc1;
277+}
278+
279+/**
280+ * ccs_cred_free - Release memory used by credentials.
281+ *
282+ * @cred: Pointer to "struct cred".
283+ *
284+ * Returns nothing.
285+ */
286+static void ccs_cred_free(struct cred *cred)
287+{
288+ if (original_cred_free.cred_free)
289+ original_cred_free.cred_free(cred);
290+ ccs_del_security(ccs_find_cred_security(cred));
291+}
292+
293+/**
294+ * ccs_alloc_cred_security - Allocate memory for new credentials.
295+ *
296+ * @cred: Pointer to "struct cred".
297+ * @gfp: Memory allocation flags.
298+ *
299+ * Returns 0 on success, negative value otherwise.
300+ */
301+static int ccs_alloc_cred_security(const struct cred *cred, gfp_t gfp)
302+{
303+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
304+ gfp);
305+ if (!new_security)
306+ return -ENOMEM;
307+ new_security->cred = cred;
308+ ccs_add_cred_security(new_security);
309+ return 0;
310+}
311+
312+/**
313+ * ccs_cred_alloc_blank - Allocate memory for new credentials.
314+ *
315+ * @new: Pointer to "struct cred".
316+ * @gfp: Memory allocation flags.
317+ *
318+ * Returns 0 on success, negative value otherwise.
319+ */
320+static int ccs_cred_alloc_blank(struct cred *new, gfp_t gfp)
321+{
322+ const int rc1 = ccs_alloc_cred_security(new, gfp);
323+ if (original_cred_alloc_blank.cred_alloc_blank) {
324+ const int rc2 = original_cred_alloc_blank.
325+ cred_alloc_blank(new, gfp);
326+ if (rc2) {
327+ ccs_del_security(ccs_find_cred_security(new));
328+ return rc2;
329+ }
330+ }
331+ return rc1;
332+}
333+
334+/**
335+ * ccs_cred_transfer - Transfer "struct ccs_security" between credentials.
336+ *
337+ * @new: Pointer to "struct cred".
338+ * @old: Pointer to "struct cred".
339+ *
340+ * Returns nothing.
341+ */
342+static void ccs_cred_transfer(struct cred *new, const struct cred *old)
343+{
344+ struct ccs_security *new_security = ccs_find_cred_security(new);
345+ struct ccs_security *old_security = ccs_find_cred_security(old);
346+ if (new_security == &ccs_default_security ||
347+ new_security == &ccs_oom_security ||
348+ old_security == &ccs_default_security ||
349+ old_security == &ccs_oom_security)
350+ return;
351+ new_security->ccs_flags = old_security->ccs_flags;
352+ new_security->ccs_domain_info = old_security->ccs_domain_info;
353+}
354+
355+/**
356+ * ccs_bprm_committing_creds - A hook which is called when do_execve() succeeded.
357+ *
358+ * @bprm: Pointer to "struct linux_binprm".
359+ *
360+ * Returns nothing.
361+ */
362+static void ccs_bprm_committing_creds(struct linux_binprm *bprm)
363+{
364+ struct ccs_security *old_security = ccs_current_security();
365+ struct ccs_security *new_security;
366+ if (old_security == &ccs_default_security ||
367+ old_security == &ccs_oom_security)
368+ return;
369+ ccs_clear_execve(0, old_security);
370+ /* Update current task's cred's domain for future fork(). */
371+ new_security = ccs_find_cred_security(bprm->cred);
372+ new_security->ccs_flags = old_security->ccs_flags;
373+ new_security->ccs_domain_info = old_security->ccs_domain_info;
374+}
375+
376+/**
377+ * ccs_bprm_check_security - Check permission for execve().
378+ *
379+ * @bprm: Pointer to "struct linux_binprm".
380+ *
381+ * Returns 0 on success, negative value otherwise.
382+ */
383+static int ccs_bprm_check_security(struct linux_binprm *bprm)
384+{
385+ struct ccs_security *security = ccs_current_security();
386+ int rc;
387+ if (security == &ccs_default_security || security == &ccs_oom_security)
388+ return -ENOMEM;
389+ if (security->ee)
390+ return 0;
391+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
392+ if (!ccs_policy_loaded)
393+ ccs_load_policy(bprm->filename);
394+#endif
395+ rc = ccs_start_execve(bprm, &security->ee);
396+ if (security->ee)
397+ atomic_inc(&ccs_in_execve_tasks);
398+ return rc;
399+}
400+
401+/**
402+ * ccs_file_open - Check permission for open().
403+ *
404+ * @f: Pointer to "struct file".
405+ * @cred: Pointer to "struct cred".
406+ *
407+ * Returns 0 on success, negative value otherwise.
408+ */
409+static int ccs_file_open(struct file *f, const struct cred *cred)
410+{
411+ return ccs_open_permission(f);
412+}
413+
414+#ifdef CONFIG_SECURITY_PATH
415+
416+/**
417+ * ccs_path_chown - Check permission for chown()/chgrp().
418+ *
419+ * @path: Pointer to "struct path".
420+ * @user: User ID.
421+ * @group: Group ID.
422+ *
423+ * Returns 0 on success, negative value otherwise.
424+ */
425+static int ccs_path_chown(struct path *path, kuid_t user, kgid_t group)
426+{
427+ return ccs_chown_permission(path->dentry, path->mnt, user, group);
428+}
429+
430+/**
431+ * ccs_path_chmod - Check permission for chmod().
432+ *
433+ * @path: Pointer to "struct path".
434+ * @mode: Mode.
435+ *
436+ * Returns 0 on success, negative value otherwise.
437+ */
438+static int ccs_path_chmod(struct path *path, umode_t mode)
439+{
440+ return ccs_chmod_permission(path->dentry, path->mnt, mode);
441+}
442+
443+/**
444+ * ccs_path_chroot - Check permission for chroot().
445+ *
446+ * @path: Pointer to "struct path".
447+ *
448+ * Returns 0 on success, negative value otherwise.
449+ */
450+static int ccs_path_chroot(struct path *path)
451+{
452+ return ccs_chroot_permission(path);
453+}
454+
455+/**
456+ * ccs_path_truncate - Check permission for truncate().
457+ *
458+ * @path: Pointer to "struct path".
459+ *
460+ * Returns 0 on success, negative value otherwise.
461+ */
462+static int ccs_path_truncate(struct path *path)
463+{
464+ return ccs_truncate_permission(path->dentry, path->mnt);
465+}
466+
467+#else
468+
469+/**
470+ * ccs_inode_setattr - Check permission for chown()/chgrp()/chmod()/truncate().
471+ *
472+ * @dentry: Pointer to "struct dentry".
473+ * @attr: Pointer to "struct iattr".
474+ *
475+ * Returns 0 on success, negative value otherwise.
476+ */
477+static int ccs_inode_setattr(struct dentry *dentry, struct iattr *attr)
478+{
479+ const int rc1 = (attr->ia_valid & ATTR_UID) ?
480+ ccs_chown_permission(dentry, NULL, attr->ia_uid, INVALID_GID) :
481+ 0;
482+ const int rc2 = (attr->ia_valid & ATTR_GID) ?
483+ ccs_chown_permission(dentry, NULL, INVALID_UID, attr->ia_gid) :
484+ 0;
485+ const int rc3 = (attr->ia_valid & ATTR_MODE) ?
486+ ccs_chmod_permission(dentry, NULL, attr->ia_mode) : 0;
487+ const int rc4 = (attr->ia_valid & ATTR_SIZE) ?
488+ ccs_truncate_permission(dentry, NULL) : 0;
489+ if (rc4)
490+ return rc4;
491+ if (rc3)
492+ return rc3;
493+ if (rc2)
494+ return rc2;
495+ return rc1;
496+}
497+
498+#endif
499+
500+/**
501+ * ccs_inode_getattr - Check permission for stat().
502+ *
503+ * @mnt: Pointer to "struct vfsmount".
504+ * @dentry: Pointer to "struct dentry".
505+ *
506+ * Returns 0 on success, negative value otherwise.
507+ */
508+static int ccs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
509+{
510+ return ccs_getattr_permission(mnt, dentry);
511+}
512+
513+#ifdef CONFIG_SECURITY_PATH
514+
515+/**
516+ * ccs_path_mknod - Check permission for mknod().
517+ *
518+ * @dir: Pointer to "struct path".
519+ * @dentry: Pointer to "struct dentry".
520+ * @mode: Create mode.
521+ * @dev: Device major/minor number.
522+ *
523+ * Returns 0 on success, negative value otherwise.
524+ */
525+static int ccs_path_mknod(struct path *dir, struct dentry *dentry,
526+ umode_t mode, unsigned int dev)
527+{
528+ return ccs_mknod_permission(dentry, dir->mnt, mode, dev);
529+}
530+
531+/**
532+ * ccs_path_mkdir - Check permission for mkdir().
533+ *
534+ * @dir: Pointer to "struct path".
535+ * @dentry: Pointer to "struct dentry".
536+ * @mode: Create mode.
537+ *
538+ * Returns 0 on success, negative value otherwise.
539+ */
540+static int ccs_path_mkdir(struct path *dir, struct dentry *dentry,
541+ umode_t mode)
542+{
543+ return ccs_mkdir_permission(dentry, dir->mnt, mode);
544+}
545+
546+/**
547+ * ccs_path_rmdir - Check permission for rmdir().
548+ *
549+ * @dir: Pointer to "struct path".
550+ * @dentry: Pointer to "struct dentry".
551+ *
552+ * Returns 0 on success, negative value otherwise.
553+ */
554+static int ccs_path_rmdir(struct path *dir, struct dentry *dentry)
555+{
556+ return ccs_rmdir_permission(dentry, dir->mnt);
557+}
558+
559+/**
560+ * ccs_path_unlink - Check permission for unlink().
561+ *
562+ * @dir: Pointer to "struct path".
563+ * @dentry: Pointer to "struct dentry".
564+ *
565+ * Returns 0 on success, negative value otherwise.
566+ */
567+static int ccs_path_unlink(struct path *dir, struct dentry *dentry)
568+{
569+ return ccs_unlink_permission(dentry, dir->mnt);
570+}
571+
572+/**
573+ * ccs_path_symlink - Check permission for symlink().
574+ *
575+ * @dir: Pointer to "struct path".
576+ * @dentry: Pointer to "struct dentry".
577+ * @old_name: Content of symbolic link.
578+ *
579+ * Returns 0 on success, negative value otherwise.
580+ */
581+static int ccs_path_symlink(struct path *dir, struct dentry *dentry,
582+ const char *old_name)
583+{
584+ return ccs_symlink_permission(dentry, dir->mnt, old_name);
585+}
586+
587+/**
588+ * ccs_path_rename - Check permission for rename().
589+ *
590+ * @old_dir: Pointer to "struct path".
591+ * @old_dentry: Pointer to "struct dentry".
592+ * @new_dir: Pointer to "struct path".
593+ * @new_dentry: Pointer to "struct dentry".
594+ *
595+ * Returns 0 on success, negative value otherwise.
596+ */
597+static int ccs_path_rename(struct path *old_dir, struct dentry *old_dentry,
598+ struct path *new_dir, struct dentry *new_dentry)
599+{
600+ return ccs_rename_permission(old_dentry, new_dentry, old_dir->mnt);
601+}
602+
603+/**
604+ * ccs_path_link - Check permission for link().
605+ *
606+ * @old_dentry: Pointer to "struct dentry".
607+ * @new_dir: Pointer to "struct path".
608+ * @new_dentry: Pointer to "struct dentry".
609+ *
610+ * Returns 0 on success, negative value otherwise.
611+ */
612+static int ccs_path_link(struct dentry *old_dentry, struct path *new_dir,
613+ struct dentry *new_dentry)
614+{
615+ return ccs_link_permission(old_dentry, new_dentry, new_dir->mnt);
616+}
617+
618+#else
619+
620+/**
621+ * ccs_inode_mknod - Check permission for mknod().
622+ *
623+ * @dir: Pointer to "struct inode".
624+ * @dentry: Pointer to "struct dentry".
625+ * @mode: Create mode.
626+ * @dev: Device major/minor number.
627+ *
628+ * Returns 0 on success, negative value otherwise.
629+ */
630+static int ccs_inode_mknod(struct inode *dir, struct dentry *dentry,
631+ umode_t mode, dev_t dev)
632+{
633+ return ccs_mknod_permission(dentry, NULL, mode, dev);
634+}
635+
636+/**
637+ * ccs_inode_mkdir - Check permission for mkdir().
638+ *
639+ * @dir: Pointer to "struct inode".
640+ * @dentry: Pointer to "struct dentry".
641+ * @mode: Create mode.
642+ *
643+ * Returns 0 on success, negative value otherwise.
644+ */
645+static int ccs_inode_mkdir(struct inode *dir, struct dentry *dentry,
646+ umode_t mode)
647+{
648+ return ccs_mkdir_permission(dentry, NULL, mode);
649+}
650+
651+/**
652+ * ccs_inode_rmdir - Check permission for rmdir().
653+ *
654+ * @dir: Pointer to "struct inode".
655+ * @dentry: Pointer to "struct dentry".
656+ *
657+ * Returns 0 on success, negative value otherwise.
658+ */
659+static int ccs_inode_rmdir(struct inode *dir, struct dentry *dentry)
660+{
661+ return ccs_rmdir_permission(dentry, NULL);
662+}
663+
664+/**
665+ * ccs_inode_unlink - Check permission for unlink().
666+ *
667+ * @dir: Pointer to "struct inode".
668+ * @dentry: Pointer to "struct dentry".
669+ *
670+ * Returns 0 on success, negative value otherwise.
671+ */
672+static int ccs_inode_unlink(struct inode *dir, struct dentry *dentry)
673+{
674+ return ccs_unlink_permission(dentry, NULL);
675+}
676+
677+/**
678+ * ccs_inode_symlink - Check permission for symlink().
679+ *
680+ * @dir: Pointer to "struct inode".
681+ * @dentry: Pointer to "struct dentry".
682+ * @old_name: Content of symbolic link.
683+ *
684+ * Returns 0 on success, negative value otherwise.
685+ */
686+static int ccs_inode_symlink(struct inode *dir, struct dentry *dentry,
687+ const char *old_name)
688+{
689+ return ccs_symlink_permission(dentry, NULL, old_name);
690+}
691+
692+/**
693+ * ccs_inode_rename - Check permission for rename().
694+ *
695+ * @old_dir: Pointer to "struct inode".
696+ * @old_dentry: Pointer to "struct dentry".
697+ * @new_dir: Pointer to "struct inode".
698+ * @new_dentry: Pointer to "struct dentry".
699+ *
700+ * Returns 0 on success, negative value otherwise.
701+ */
702+static int ccs_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
703+ struct inode *new_dir, struct dentry *new_dentry)
704+{
705+ return ccs_rename_permission(old_dentry, new_dentry, NULL);
706+}
707+
708+/**
709+ * ccs_inode_link - Check permission for link().
710+ *
711+ * @old_dentry: Pointer to "struct dentry".
712+ * @dir: Pointer to "struct inode".
713+ * @new_dentry: Pointer to "struct dentry".
714+ *
715+ * Returns 0 on success, negative value otherwise.
716+ */
717+static int ccs_inode_link(struct dentry *old_dentry, struct inode *dir,
718+ struct dentry *new_dentry)
719+{
720+ return ccs_link_permission(old_dentry, new_dentry, NULL);
721+}
722+
723+/**
724+ * ccs_inode_create - Check permission for creat().
725+ *
726+ * @dir: Pointer to "struct inode".
727+ * @dentry: Pointer to "struct dentry".
728+ * @mode: Create mode.
729+ *
730+ * Returns 0 on success, negative value otherwise.
731+ */
732+static int ccs_inode_create(struct inode *dir, struct dentry *dentry,
733+ umode_t mode)
734+{
735+ return ccs_mknod_permission(dentry, NULL, mode, 0);
736+}
737+
738+#endif
739+
740+#ifdef CONFIG_SECURITY_NETWORK
741+
742+#include <net/sock.h>
743+
744+/* Structure for remembering an accept()ed socket's status. */
745+struct ccs_socket_tag {
746+ struct list_head list;
747+ struct inode *inode;
748+ int status;
749+ struct rcu_head rcu;
750+};
751+
752+/*
753+ * List for managing accept()ed sockets.
754+ * Since we don't need to keep an accept()ed socket into this list after
755+ * once the permission was granted, the number of entries in this list is
756+ * likely small. Therefore, we don't use hash tables.
757+ */
758+static LIST_HEAD(ccs_accepted_socket_list);
759+/* Lock for protecting ccs_accepted_socket_list . */
760+static DEFINE_SPINLOCK(ccs_accepted_socket_list_lock);
761+
762+/**
763+ * ccs_socket_rcu_free - RCU callback for releasing "struct ccs_socket_tag".
764+ *
765+ * @rcu: Pointer to "struct rcu_head".
766+ *
767+ * Returns nothing.
768+ */
769+static void ccs_socket_rcu_free(struct rcu_head *rcu)
770+{
771+ struct ccs_socket_tag *ptr = container_of(rcu, typeof(*ptr), rcu);
772+ kfree(ptr);
773+}
774+
775+/**
776+ * ccs_update_socket_tag - Update tag associated with accept()ed sockets.
777+ *
778+ * @inode: Pointer to "struct inode".
779+ * @status: New status.
780+ *
781+ * Returns nothing.
782+ *
783+ * If @status == 0, memory for that socket will be released after RCU grace
784+ * period.
785+ */
786+static void ccs_update_socket_tag(struct inode *inode, int status)
787+{
788+ struct ccs_socket_tag *ptr;
789+ /*
790+ * Protect whole section because multiple threads may call this
791+ * function with same "sock" via ccs_validate_socket().
792+ */
793+ spin_lock(&ccs_accepted_socket_list_lock);
794+ rcu_read_lock();
795+ list_for_each_entry_rcu(ptr, &ccs_accepted_socket_list, list) {
796+ if (ptr->inode != inode)
797+ continue;
798+ ptr->status = status;
799+ if (status)
800+ break;
801+ list_del_rcu(&ptr->list);
802+ call_rcu(&ptr->rcu, ccs_socket_rcu_free);
803+ break;
804+ }
805+ rcu_read_unlock();
806+ spin_unlock(&ccs_accepted_socket_list_lock);
807+}
808+
809+/**
810+ * ccs_validate_socket - Check post accept() permission if needed.
811+ *
812+ * @sock: Pointer to "struct socket".
813+ *
814+ * Returns 0 on success, negative value otherwise.
815+ */
816+static int ccs_validate_socket(struct socket *sock)
817+{
818+ struct inode *inode = SOCK_INODE(sock);
819+ struct ccs_socket_tag *ptr;
820+ int ret = 0;
821+ rcu_read_lock();
822+ list_for_each_entry_rcu(ptr, &ccs_accepted_socket_list, list) {
823+ if (ptr->inode != inode)
824+ continue;
825+ ret = ptr->status;
826+ break;
827+ }
828+ rcu_read_unlock();
829+ if (ret <= 0)
830+ /*
831+ * This socket is not an accept()ed socket or this socket is
832+ * an accept()ed socket and post accept() permission is done.
833+ */
834+ return ret;
835+ /*
836+ * Check post accept() permission now.
837+ *
838+ * Strictly speaking, we need to pass both listen()ing socket and
839+ * accept()ed socket to __ccs_socket_post_accept_permission().
840+ * But since socket's family and type are same for both sockets,
841+ * passing the accept()ed socket in place for the listen()ing socket
842+ * will work.
843+ */
844+ ret = ccs_socket_post_accept_permission(sock, sock);
845+ /*
846+ * If permission was granted, we forget that this is an accept()ed
847+ * socket. Otherwise, we remember that this socket needs to return
848+ * error for subsequent socketcalls.
849+ */
850+ ccs_update_socket_tag(inode, ret);
851+ return ret;
852+}
853+
854+/**
855+ * ccs_socket_accept - Check permission for accept().
856+ *
857+ * @sock: Pointer to "struct socket".
858+ * @newsock: Pointer to "struct socket".
859+ *
860+ * Returns 0 on success, negative value otherwise.
861+ *
862+ * This hook is used for setting up environment for doing post accept()
863+ * permission check. If dereferencing sock->ops->something() were ordered by
864+ * rcu_dereference(), we could replace sock->ops with "a copy of original
865+ * sock->ops with modified sock->ops->accept()" using rcu_assign_pointer()
866+ * in order to do post accept() permission check before returning to userspace.
867+ * If we make the copy in security_socket_post_create(), it would be possible
868+ * to safely replace sock->ops here, but we don't do so because we don't want
869+ * to allocate memory for sockets which do not call sock->ops->accept().
870+ * Therefore, we do post accept() permission check upon next socket syscalls
871+ * rather than between sock->ops->accept() and returning to userspace.
872+ * This means that if a socket was close()d before calling some socket
873+ * syscalls, post accept() permission check will not be done.
874+ */
875+static int ccs_socket_accept(struct socket *sock, struct socket *newsock)
876+{
877+ struct ccs_socket_tag *ptr;
878+ const int rc = ccs_validate_socket(sock);
879+ if (rc < 0)
880+ return rc;
881+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
882+ if (!ptr)
883+ return -ENOMEM;
884+ /*
885+ * Subsequent LSM hooks will receive "newsock". Therefore, I mark
886+ * "newsock" as "an accept()ed socket but post accept() permission
887+ * check is not done yet" by allocating memory using inode of the
888+ * "newsock" as a search key.
889+ */
890+ ptr->inode = SOCK_INODE(newsock);
891+ ptr->status = 1; /* Check post accept() permission later. */
892+ spin_lock(&ccs_accepted_socket_list_lock);
893+ list_add_tail_rcu(&ptr->list, &ccs_accepted_socket_list);
894+ spin_unlock(&ccs_accepted_socket_list_lock);
895+ return 0;
896+}
897+
898+/**
899+ * ccs_socket_listen - Check permission for listen().
900+ *
901+ * @sock: Pointer to "struct socket".
902+ * @backlog: Backlog parameter.
903+ *
904+ * Returns 0 on success, negative value otherwise.
905+ */
906+static int ccs_socket_listen(struct socket *sock, int backlog)
907+{
908+ const int rc = ccs_validate_socket(sock);
909+ if (rc < 0)
910+ return rc;
911+ return ccs_socket_listen_permission(sock);
912+}
913+
914+/**
915+ * ccs_socket_connect - Check permission for connect().
916+ *
917+ * @sock: Pointer to "struct socket".
918+ * @addr: Pointer to "struct sockaddr".
919+ * @addr_len: Size of @addr.
920+ *
921+ * Returns 0 on success, negative value otherwise.
922+ */
923+static int ccs_socket_connect(struct socket *sock, struct sockaddr *addr,
924+ int addr_len)
925+{
926+ const int rc = ccs_validate_socket(sock);
927+ if (rc < 0)
928+ return rc;
929+ return ccs_socket_connect_permission(sock, addr, addr_len);
930+}
931+
932+/**
933+ * ccs_socket_bind - Check permission for bind().
934+ *
935+ * @sock: Pointer to "struct socket".
936+ * @addr: Pointer to "struct sockaddr".
937+ * @addr_len: Size of @addr.
938+ *
939+ * Returns 0 on success, negative value otherwise.
940+ */
941+static int ccs_socket_bind(struct socket *sock, struct sockaddr *addr,
942+ int addr_len)
943+{
944+ const int rc = ccs_validate_socket(sock);
945+ if (rc < 0)
946+ return rc;
947+ return ccs_socket_bind_permission(sock, addr, addr_len);
948+}
949+
950+/**
951+ * ccs_socket_sendmsg - Check permission for sendmsg().
952+ *
953+ * @sock: Pointer to "struct socket".
954+ * @msg: Pointer to "struct msghdr".
955+ * @size: Size of message.
956+ *
957+ * Returns 0 on success, negative value otherwise.
958+ */
959+static int ccs_socket_sendmsg(struct socket *sock, struct msghdr *msg,
960+ int size)
961+{
962+ const int rc = ccs_validate_socket(sock);
963+ if (rc < 0)
964+ return rc;
965+ return ccs_socket_sendmsg_permission(sock, msg, size);
966+}
967+
968+/**
969+ * ccs_socket_recvmsg - Check permission for recvmsg().
970+ *
971+ * @sock: Pointer to "struct socket".
972+ * @msg: Pointer to "struct msghdr".
973+ * @size: Size of message.
974+ * @flags: Flags.
975+ *
976+ * Returns 0 on success, negative value otherwise.
977+ */
978+static int ccs_socket_recvmsg(struct socket *sock, struct msghdr *msg,
979+ int size, int flags)
980+{
981+ return ccs_validate_socket(sock);
982+}
983+
984+/**
985+ * ccs_socket_getsockname - Check permission for getsockname().
986+ *
987+ * @sock: Pointer to "struct socket".
988+ *
989+ * Returns 0 on success, negative value otherwise.
990+ */
991+static int ccs_socket_getsockname(struct socket *sock)
992+{
993+ return ccs_validate_socket(sock);
994+}
995+
996+/**
997+ * ccs_socket_getpeername - Check permission for getpeername().
998+ *
999+ * @sock: Pointer to "struct socket".
1000+ *
1001+ * Returns 0 on success, negative value otherwise.
1002+ */
1003+static int ccs_socket_getpeername(struct socket *sock)
1004+{
1005+ return ccs_validate_socket(sock);
1006+}
1007+
1008+/**
1009+ * ccs_socket_getsockopt - Check permission for getsockopt().
1010+ *
1011+ * @sock: Pointer to "struct socket".
1012+ * @level: Level.
1013+ * @optname: Option's name,
1014+ *
1015+ * Returns 0 on success, negative value otherwise.
1016+ */
1017+static int ccs_socket_getsockopt(struct socket *sock, int level, int optname)
1018+{
1019+ return ccs_validate_socket(sock);
1020+}
1021+
1022+/**
1023+ * ccs_socket_setsockopt - Check permission for setsockopt().
1024+ *
1025+ * @sock: Pointer to "struct socket".
1026+ * @level: Level.
1027+ * @optname: Option's name,
1028+ *
1029+ * Returns 0 on success, negative value otherwise.
1030+ */
1031+static int ccs_socket_setsockopt(struct socket *sock, int level, int optname)
1032+{
1033+ return ccs_validate_socket(sock);
1034+}
1035+
1036+/**
1037+ * ccs_socket_shutdown - Check permission for shutdown().
1038+ *
1039+ * @sock: Pointer to "struct socket".
1040+ * @how: Shutdown mode.
1041+ *
1042+ * Returns 0 on success, negative value otherwise.
1043+ */
1044+static int ccs_socket_shutdown(struct socket *sock, int how)
1045+{
1046+ return ccs_validate_socket(sock);
1047+}
1048+
1049+#define SOCKFS_MAGIC 0x534F434B
1050+
1051+/**
1052+ * ccs_inode_free_security - Release memory associated with an inode.
1053+ *
1054+ * @inode: Pointer to "struct inode".
1055+ *
1056+ * Returns nothing.
1057+ *
1058+ * We use this hook for releasing memory associated with an accept()ed socket.
1059+ */
1060+static void ccs_inode_free_security(struct inode *inode)
1061+{
1062+ if (inode->i_sb && inode->i_sb->s_magic == SOCKFS_MAGIC)
1063+ ccs_update_socket_tag(inode, 0);
1064+}
1065+
1066+#endif
1067+
1068+/**
1069+ * ccs_sb_pivotroot - Check permission for pivot_root().
1070+ *
1071+ * @old_path: Pointer to "struct path".
1072+ * @new_path: Pointer to "struct path".
1073+ *
1074+ * Returns 0 on success, negative value otherwise.
1075+ */
1076+static int ccs_sb_pivotroot(struct path *old_path, struct path *new_path)
1077+{
1078+ return ccs_pivot_root_permission(old_path, new_path);
1079+}
1080+
1081+/**
1082+ * ccs_sb_mount - Check permission for mount().
1083+ *
1084+ * @dev_name: Name of device file.
1085+ * @path: Pointer to "struct path".
1086+ * @type: Name of filesystem type. Maybe NULL.
1087+ * @flags: Mount options.
1088+ * @data_page: Optional data. Maybe NULL.
1089+ *
1090+ * Returns 0 on success, negative value otherwise.
1091+ */
1092+static int ccs_sb_mount(const char *dev_name, struct path *path,
1093+ const char *type, unsigned long flags, void *data_page)
1094+{
1095+ return ccs_mount_permission(dev_name, path, type, flags, data_page);
1096+}
1097+
1098+/**
1099+ * ccs_sb_umount - Check permission for umount().
1100+ *
1101+ * @mnt: Pointer to "struct vfsmount".
1102+ * @flags: Unmount flags.
1103+ *
1104+ * Returns 0 on success, negative value otherwise.
1105+ */
1106+static int ccs_sb_umount(struct vfsmount *mnt, int flags)
1107+{
1108+ return ccs_umount_permission(mnt, flags);
1109+}
1110+
1111+/**
1112+ * ccs_file_fcntl - Check permission for fcntl().
1113+ *
1114+ * @file: Pointer to "struct file".
1115+ * @cmd: Command number.
1116+ * @arg: Value for @cmd.
1117+ *
1118+ * Returns 0 on success, negative value otherwise.
1119+ */
1120+static int ccs_file_fcntl(struct file *file, unsigned int cmd,
1121+ unsigned long arg)
1122+{
1123+ return ccs_fcntl_permission(file, cmd, arg);
1124+}
1125+
1126+/**
1127+ * ccs_file_ioctl - Check permission for ioctl().
1128+ *
1129+ * @filp: Pointer to "struct file".
1130+ * @cmd: Command number.
1131+ * @arg: Value for @cmd.
1132+ *
1133+ * Returns 0 on success, negative value otherwise.
1134+ */
1135+static int ccs_file_ioctl(struct file *filp, unsigned int cmd,
1136+ unsigned long arg)
1137+{
1138+ return ccs_ioctl_permission(filp, cmd, arg);
1139+}
1140+
1141+#define MY_HOOK_INIT(HEAD, HOOK) \
1142+ { .head = &probe_dummy_security_hook_heads.HEAD, \
1143+ .hook = { .HEAD = HOOK } }
1144+
1145+static struct security_hook_list akari_hooks[] = {
1146+ /* Security context allocator. */
1147+ MY_HOOK_INIT(cred_free, ccs_cred_free),
1148+ MY_HOOK_INIT(cred_prepare, ccs_cred_prepare),
1149+ MY_HOOK_INIT(cred_alloc_blank, ccs_cred_alloc_blank),
1150+ MY_HOOK_INIT(cred_transfer, ccs_cred_transfer),
1151+ MY_HOOK_INIT(task_create, ccs_task_create),
1152+ /* Security context updater for successful execve(). */
1153+ MY_HOOK_INIT(bprm_check_security, ccs_bprm_check_security),
1154+ MY_HOOK_INIT(bprm_committing_creds, ccs_bprm_committing_creds),
1155+ /* Various permission checker. */
1156+ MY_HOOK_INIT(file_open, ccs_file_open),
1157+ MY_HOOK_INIT(file_fcntl, ccs_file_fcntl),
1158+ MY_HOOK_INIT(file_ioctl, ccs_file_ioctl),
1159+ MY_HOOK_INIT(sb_pivotroot, ccs_sb_pivotroot),
1160+ MY_HOOK_INIT(sb_mount, ccs_sb_mount),
1161+ MY_HOOK_INIT(sb_umount, ccs_sb_umount),
1162+#ifdef CONFIG_SECURITY_PATH
1163+ MY_HOOK_INIT(path_mknod, ccs_path_mknod),
1164+ MY_HOOK_INIT(path_mkdir, ccs_path_mkdir),
1165+ MY_HOOK_INIT(path_rmdir, ccs_path_rmdir),
1166+ MY_HOOK_INIT(path_unlink, ccs_path_unlink),
1167+ MY_HOOK_INIT(path_symlink, ccs_path_symlink),
1168+ MY_HOOK_INIT(path_rename, ccs_path_rename),
1169+ MY_HOOK_INIT(path_link, ccs_path_link),
1170+ MY_HOOK_INIT(path_truncate, ccs_path_truncate),
1171+ MY_HOOK_INIT(path_chmod, ccs_path_chmod),
1172+ MY_HOOK_INIT(path_chown, ccs_path_chown),
1173+ MY_HOOK_INIT(path_chroot, ccs_path_chroot),
1174+#else
1175+ MY_HOOK_INIT(inode_mknod, ccs_inode_mknod),
1176+ MY_HOOK_INIT(inode_mkdir, ccs_inode_mkdir),
1177+ MY_HOOK_INIT(inode_rmdir, ccs_inode_rmdir),
1178+ MY_HOOK_INIT(inode_unlink, ccs_inode_unlink),
1179+ MY_HOOK_INIT(inode_symlink, ccs_inode_symlink),
1180+ MY_HOOK_INIT(inode_rename, ccs_inode_rename),
1181+ MY_HOOK_INIT(inode_link, ccs_inode_link),
1182+ MY_HOOK_INIT(inode_create, ccs_inode_create),
1183+ MY_HOOK_INIT(inode_setattr, ccs_inode_setattr),
1184+#endif
1185+ MY_HOOK_INIT(inode_getattr, ccs_inode_getattr),
1186+#ifdef CONFIG_SECURITY_NETWORK
1187+ MY_HOOK_INIT(socket_bind, ccs_socket_bind),
1188+ MY_HOOK_INIT(socket_connect, ccs_socket_connect),
1189+ MY_HOOK_INIT(socket_listen, ccs_socket_listen),
1190+ MY_HOOK_INIT(socket_sendmsg, ccs_socket_sendmsg),
1191+ MY_HOOK_INIT(socket_recvmsg, ccs_socket_recvmsg),
1192+ MY_HOOK_INIT(socket_getsockname, ccs_socket_getsockname),
1193+ MY_HOOK_INIT(socket_getpeername, ccs_socket_getpeername),
1194+ MY_HOOK_INIT(socket_getsockopt, ccs_socket_getsockopt),
1195+ MY_HOOK_INIT(socket_setsockopt, ccs_socket_setsockopt),
1196+ MY_HOOK_INIT(socket_shutdown, ccs_socket_shutdown),
1197+ MY_HOOK_INIT(socket_accept, ccs_socket_accept),
1198+ MY_HOOK_INIT(inode_free_security, ccs_inode_free_security),
1199+#endif
1200+};
1201+
1202+static inline void add_hook(struct security_hook_list *hook)
1203+{
1204+ list_add_tail_rcu(&hook->list, hook->head);
1205+}
1206+
1207+static void __init swap_hook(struct security_hook_list *hook,
1208+ union security_list_options *original)
1209+{
1210+ struct list_head *list = hook->head;
1211+ if (list_empty(list)) {
1212+ add_hook(hook);
1213+ } else {
1214+ struct security_hook_list *shp =
1215+ list_last_entry(list, struct security_hook_list, list);
1216+ *original = shp->hook;
1217+ smp_wmb();
1218+ shp->hook = hook->hook;
1219+ }
1220+}
1221+
1222+/**
1223+ * ccs_init - Initialize this module.
1224+ *
1225+ * Returns 0 on success, negative value otherwise.
1226+ */
1227+static int __init ccs_init(void)
1228+{
1229+ int idx;
1230+ struct security_hook_heads *hooks = probe_security_hook_heads();
1231+ if (!hooks)
1232+ goto out;
1233+ for (idx = 0; idx < ARRAY_SIZE(akari_hooks); idx++)
1234+ akari_hooks[idx].head = ((void *) hooks)
1235+ + ((unsigned long) akari_hooks[idx].head)
1236+ - ((unsigned long) &probe_dummy_security_hook_heads);
1237+ ccsecurity_exports.find_task_by_vpid = probe_find_task_by_vpid();
1238+ if (!ccsecurity_exports.find_task_by_vpid)
1239+ goto out;
1240+ ccsecurity_exports.find_task_by_pid_ns = probe_find_task_by_pid_ns();
1241+ if (!ccsecurity_exports.find_task_by_pid_ns)
1242+ goto out;
1243+ ccsecurity_exports.d_absolute_path = probe_d_absolute_path();
1244+ if (!ccsecurity_exports.d_absolute_path)
1245+ goto out;
1246+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
1247+ INIT_LIST_HEAD(&ccs_cred_security_list[idx]);
1248+ INIT_LIST_HEAD(&ccs_task_security_list[idx]);
1249+ }
1250+ ccs_main_init();
1251+ swap_hook(&akari_hooks[0], &original_cred_free);
1252+ swap_hook(&akari_hooks[1], &original_cred_prepare);
1253+ swap_hook(&akari_hooks[2], &original_cred_alloc_blank);
1254+ for (idx = 3; idx < ARRAY_SIZE(akari_hooks); idx++)
1255+ add_hook(&akari_hooks[idx]);
1256+ printk(KERN_INFO "AKARI: 1.0.33 2015/04/21\n");
1257+ printk(KERN_INFO
1258+ "Access Keeping And Regulating Instrument registered.\n");
1259+ return 0;
1260+out:
1261+ return -EINVAL;
1262+}
1263+
1264+module_init(ccs_init);
1265+MODULE_LICENSE("GPL");
1266+
1267+/**
1268+ * ccs_used_by_cred - Check whether the given domain is in use or not.
1269+ *
1270+ * @domain: Pointer to "struct ccs_domain_info".
1271+ *
1272+ * Returns true if @domain is in use, false otherwise.
1273+ *
1274+ * Caller holds rcu_read_lock().
1275+ */
1276+bool ccs_used_by_cred(const struct ccs_domain_info *domain)
1277+{
1278+ int idx;
1279+ struct ccs_security *ptr;
1280+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
1281+ struct list_head *list = &ccs_cred_security_list[idx];
1282+ list_for_each_entry_rcu(ptr, list, list) {
1283+ struct ccs_execve *ee = ptr->ee;
1284+ if (ptr->ccs_domain_info == domain ||
1285+ (ee && ee->previous_domain == domain)) {
1286+ return true;
1287+ }
1288+ }
1289+ }
1290+ return false;
1291+}
1292+
1293+/**
1294+ * ccs_add_task_security - Add "struct ccs_security" to list.
1295+ *
1296+ * @ptr: Pointer to "struct ccs_security".
1297+ * @list: Pointer to "struct list_head".
1298+ *
1299+ * Returns nothing.
1300+ */
1301+static void ccs_add_task_security(struct ccs_security *ptr,
1302+ struct list_head *list)
1303+{
1304+ unsigned long flags;
1305+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
1306+ list_add_rcu(&ptr->list, list);
1307+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
1308+}
1309+
1310+/**
1311+ * ccs_find_task_security - Find "struct ccs_security" for given task.
1312+ *
1313+ * @task: Pointer to "struct task_struct".
1314+ *
1315+ * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
1316+ * out of memory, &ccs_default_security otherwise.
1317+ *
1318+ * If @task is current thread and "struct ccs_security" for current thread was
1319+ * not found, I try to allocate it. But if allocation failed, current thread
1320+ * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
1321+ * won't work.
1322+ */
1323+struct ccs_security *ccs_find_task_security(const struct task_struct *task)
1324+{
1325+ struct ccs_security *ptr;
1326+ struct list_head *list = &ccs_task_security_list
1327+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
1328+ /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
1329+ while (!list->next);
1330+ rcu_read_lock();
1331+ list_for_each_entry_rcu(ptr, list, list) {
1332+ if (ptr->pid != task->pids[PIDTYPE_PID].pid)
1333+ continue;
1334+ rcu_read_unlock();
1335+ /*
1336+ * Current thread needs to transit from old domain to new
1337+ * domain before do_execve() succeeds in order to check
1338+ * permission for interpreters and environment variables using
1339+ * new domain's ACL rules. The domain transition has to be
1340+ * visible from other CPU in order to allow interactive
1341+ * enforcing mode. Also, the domain transition has to be
1342+ * reverted if do_execve() failed. However, an LSM hook for
1343+ * reverting domain transition is missing.
1344+ *
1345+ * security_prepare_creds() is called from prepare_creds() from
1346+ * prepare_bprm_creds() from do_execve() before setting
1347+ * current->in_execve flag, and current->in_execve flag is
1348+ * cleared by the time next do_execve() request starts.
1349+ * This means that we can emulate the missing LSM hook for
1350+ * reverting domain transition, by calling this function from
1351+ * security_prepare_creds().
1352+ *
1353+ * If current->in_execve is not set but ptr->ccs_flags has
1354+ * CCS_TASK_IS_IN_EXECVE set, it indicates that do_execve()
1355+ * has failed and reverting domain transition is needed.
1356+ */
1357+ if (task == current &&
1358+ (ptr->ccs_flags & CCS_TASK_IS_IN_EXECVE) &&
1359+ !current->in_execve) {
1360+ ccs_debug_trace("4");
1361+ ccs_clear_execve(-1, ptr);
1362+ }
1363+ return ptr;
1364+ }
1365+ rcu_read_unlock();
1366+ if (task != current) {
1367+ /*
1368+ * If a thread does nothing after fork(), caller will reach
1369+ * here because "struct ccs_security" for that thread is not
1370+ * yet allocated. But that thread is keeping a snapshot of
1371+ * "struct ccs_security" taken as of ccs_task_create()
1372+ * associated with that thread's "struct cred".
1373+ *
1374+ * Since that snapshot will be used as initial data when that
1375+ * thread allocates "struct ccs_security" for that thread, we
1376+ * can return that snapshot rather than &ccs_default_security.
1377+ *
1378+ * Since this function is called by only ccs_select_one() and
1379+ * ccs_read_pid() (via ccs_task_domain() and ccs_task_flags()),
1380+ * it is guaranteed that caller has called rcu_read_lock()
1381+ * (via ccs_tasklist_lock()) before finding this thread and
1382+ * this thread is valid. Therefore, we can do __task_cred(task)
1383+ * like get_robust_list() does.
1384+ */
1385+ return ccs_find_cred_security(__task_cred(task));
1386+ }
1387+ /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
1388+ ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
1389+ if (!ptr) {
1390+ printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
1391+ task->pid);
1392+ send_sig(SIGKILL, current, 0);
1393+ return &ccs_oom_security;
1394+ }
1395+ *ptr = *ccs_find_cred_security(task->cred);
1396+ /* We can shortcut because task == current. */
1397+ ptr->pid = get_pid(((struct task_struct *) task)->
1398+ pids[PIDTYPE_PID].pid);
1399+ ptr->cred = NULL;
1400+ ccs_add_task_security(ptr, list);
1401+ return ptr;
1402+}
1403+
1404+/**
1405+ * ccs_copy_cred_security - Allocate memory for new credentials.
1406+ *
1407+ * @new: Pointer to "struct cred".
1408+ * @old: Pointer to "struct cred".
1409+ * @gfp: Memory allocation flags.
1410+ *
1411+ * Returns 0 on success, negative value otherwise.
1412+ */
1413+static int ccs_copy_cred_security(const struct cred *new,
1414+ const struct cred *old, gfp_t gfp)
1415+{
1416+ struct ccs_security *old_security = ccs_find_cred_security(old);
1417+ struct ccs_security *new_security =
1418+ kzalloc(sizeof(*new_security), gfp);
1419+ if (!new_security)
1420+ return -ENOMEM;
1421+ *new_security = *old_security;
1422+ new_security->cred = new;
1423+ ccs_add_cred_security(new_security);
1424+ return 0;
1425+}
1426+
1427+/**
1428+ * ccs_find_cred_security - Find "struct ccs_security" for given credential.
1429+ *
1430+ * @cred: Pointer to "struct cred".
1431+ *
1432+ * Returns pointer to "struct ccs_security" on success, &ccs_default_security
1433+ * otherwise.
1434+ */
1435+static struct ccs_security *ccs_find_cred_security(const struct cred *cred)
1436+{
1437+ struct ccs_security *ptr;
1438+ struct list_head *list = &ccs_cred_security_list
1439+ [hash_ptr((void *) cred, CCS_TASK_SECURITY_HASH_BITS)];
1440+ rcu_read_lock();
1441+ list_for_each_entry_rcu(ptr, list, list) {
1442+ if (ptr->cred != cred)
1443+ continue;
1444+ rcu_read_unlock();
1445+ return ptr;
1446+ }
1447+ rcu_read_unlock();
1448+ return &ccs_default_security;
1449+}
1450+
1451+/**
1452+ * ccs_task_security_gc - Do garbage collection for "struct task_struct".
1453+ *
1454+ * Returns nothing.
1455+ *
1456+ * Since security_task_free() is missing, I can't release memory associated
1457+ * with "struct task_struct" when a task dies. Therefore, I hold a reference on
1458+ * "struct pid" and runs garbage collection when associated
1459+ * "struct task_struct" has gone.
1460+ */
1461+static void ccs_task_security_gc(void)
1462+{
1463+ static DEFINE_SPINLOCK(lock);
1464+ static atomic_t gc_counter = ATOMIC_INIT(0);
1465+ unsigned int idx;
1466+ /*
1467+ * If some process is doing execve(), try to garbage collection now.
1468+ * We should kfree() memory associated with "struct ccs_security"->ee
1469+ * as soon as execve() has completed in order to compensate for lack of
1470+ * security_bprm_free() and security_task_free() hooks.
1471+ *
1472+ * Otherwise, reduce frequency for performance reason.
1473+ */
1474+ if (!atomic_read(&ccs_in_execve_tasks) &&
1475+ atomic_inc_return(&gc_counter) < 1024)
1476+ return;
1477+ if (!spin_trylock(&lock))
1478+ return;
1479+ atomic_set(&gc_counter, 0);
1480+ rcu_read_lock();
1481+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
1482+ struct ccs_security *ptr;
1483+ struct list_head *list = &ccs_task_security_list[idx];
1484+ list_for_each_entry_rcu(ptr, list, list) {
1485+ if (pid_task(ptr->pid, PIDTYPE_PID))
1486+ continue;
1487+ ccs_del_security(ptr);
1488+ }
1489+ }
1490+ rcu_read_unlock();
1491+ spin_unlock(&lock);
1492+}
--- tags/patches/1.0.33/README (nonexistent)
+++ tags/patches/1.0.33/README (revision 502)
@@ -0,0 +1,286 @@
1+Notes for AKARI project
2+
3+AKARI is Access Keeping And Regulating Instrument for Linux 2.6 and later
4+kernels.
5+
6+You can use AKARI for analyzing your system's behavior (i.e. reports which
7+application accesses which resources like strace command does) and optionally
8+restricting your system's behavior (i.e. controls which application can
9+access which resources like TOMOYO/AppArmor does).
10+
11+AKARI is forked from TOMOYO 1.8 and made as a LKM (loadable kernel module)
12+so that you don't need to replace your kernels installed in your system.
13+
14+This patch is released under the GPLv2.
15+
16+Project URL: http://akari.sourceforge.jp/
17+
18+ChangeLog:
19+
20+Version 1.0 2010/10/10 First release.
21+
22+Version 1.0.1 2010/10/18 Minor update release.
23+
24+ Synchronize with TOMOYO revision 4069.
25+
26+ Fix off-by-two in ccs_check_unix_address().
27+
28+ Implement post accept() LSM hook.
29+
30+Version 1.0.2 2010/10/25 Minor update release.
31+
32+ Synchronize with TOMOYO revision 4090.
33+
34+ Add getattr() and readdir() checks.
35+
36+ Use "YYYY/MM/DD hh:mm:ss" format for /proc/ccs/ interface.
37+
38+ Do not automatically add / for umount().
39+
40+Version 1.0.3 2010/11/01 Minor update release.
41+
42+ Synchronize with TOMOYO revision 4104.
43+
44+ Fix pathname handling in ccs_unix_entry().
45+
46+Version 1.0.4 2010/11/11 Minor update release.
47+
48+ Synchronize with TOMOYO 1.8.0 release.
49+
50+ Add sysctl() check for 2.6.21 to 2.6.32 kernels.
51+
52+ Fix double new_decode_dev() bug for mknod().
53+
54+ Fix keyword typo.
55+
56+ Fix build failure on some kernels.
57+
58+ Changed pathname prefix priority.
59+
60+ Use hash table for faster scan.
61+
62+ Updated function comments.
63+
64+Version 1.0.5 2010/11/22 Minor update release.
65+
66+ Make ccs_domain_info/ccs_flags inheritable for 2.6.29 and later kernels.
67+
68+Version 1.0.6 2010/12/31 Minor update release.
69+
70+ Synchronize with TOMOYO revision 4280.
71+
72+ Use same interface for audit logs.
73+
74+ Split ccs_null_security into ccs_default_security and ccs_oom_security.
75+
76+Version 1.0.7 2011/01/21 Minor update release.
77+
78+ Synchronize with TOMOYO revision 4400.
79+
80+ Use filesystem name for unnamed devices when vfsmount is missing.
81+
82+Version 1.0.8 2011/02/07 Minor update release.
83+
84+ Synchronize with TOMOYO revision 4545.
85+
86+ Fix infinite loop bug when reading /proc/ccs/audit or /proc/ccs/query .
87+
88+Version 1.0.9 2011/02/14 Minor update release.
89+
90+ Fix missing permission check for interpreters in 2.6.30 and later kernels.
91+
92+Version 1.0.10 2011/02/15 Minor update release.
93+
94+ Fix missing permission check for interpreters in 2.6.23 and earlier kernels.
95+
96+ Fix wrong execute permission check and domain transition in 2.6.28 and earlier kernels.
97+
98+Version 1.0.11 2010/04/01 Minor update release.
99+
100+ Synchronize with TOMOYO 1.8.1 release.
101+
102+ Run garbage collector without waiting for /proc/ccs/ users.
103+
104+ Support built-in policy configuration.
105+
106+ Remove /proc/ccs/meminfo interface.
107+
108+ Pack policy when printing via /proc/ccs/ interface.
109+
110+ Fix conditional policy parsing.
111+
112+ Serialize updating profile's comment line.
113+
114+Version 1.0.12 2011/04/11 Minor update release.
115+
116+ Synchronize with TOMOYO revision 4874.
117+
118+ Fix fcntl(F_SETFL, O_APPEND) handling.
119+
120+Version 1.0.13 2011/05/05 Minor update release.
121+
122+ Synchronize with TOMOYO revision 4963.
123+
124+ Fix wrong profile number in audit logs for "misc env" permission.
125+
126+Version 1.0.14 2011/05/11 Minor update release.
127+
128+ Synchronize with TOMOYO revision 4978.
129+
130+ Fix wrong domainname validation.
131+
132+Version 1.0.15 2011/06/20 Minor update release.
133+
134+ Synchronize with TOMOYO 1.8.2 release.
135+
136+ Add policy namespace support.
137+
138+Version 1.0.16 2011/07/07 Minor update release.
139+
140+ Synchronize with TOMOYO revision 5235.
141+
142+ Remove /proc/ccs/.domain_status interface.
143+
144+Version 1.0.17 2011/07/13 Minor update release.
145+
146+ Synchronize with TOMOYO revision 5266.
147+
148+ Fix /proc/ccs/stat parser.
149+
150+ Accept "::" notation for IPv6 address.
151+
152+Version 1.0.18 2011/09/03 Minor update release.
153+
154+ Synchronize with TOMOYO revision 5401.
155+
156+ Avoid race when retrying "file execute" permission check.
157+
158+ Remove unneeded daemonize().
159+
160+ Fix load failure with !CONFIG_SMP && !CONFIG_DEBUG_SPINLOCK kernels.
161+
162+Version 1.0.19 2011/09/15 Minor update release.
163+
164+ Use akari/config.h for choosing build options.
165+
166+ Fix build error on CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER=y case.
167+
168+ Use lookup_mnt() rather than __put_namespace(). (2.6.0 to 2.6.2 kernels)
169+
170+ Fix unbalanced spin_lock()/spin_unlock() pair in lsm_pin().
171+ (2.6.15 to 2.6.35 kernels)
172+
173+ Fix "struct task_struct" leaks of tasks created before loading akari.ko .
174+ (2.6.28 and earlier kernels)
175+
176+ Use "struct task_struct"->pids[PIDTYPE_PID].pid instead of
177+ "struct task_struct" for associating with per "struct task_struct" variables
178+ (i.e. "struct ccs_security") in order to reduce amount of dead memory
179+ waiting for garbage collection. (2.6.29 and later kernels)
180+
181+ Add akari_test.ko for checking whether akari.ko seems to work or not.
182+
183+ Add SH and ARM architectures support. (Needs more testing.)
184+
185+Version 1.0.20 2011/09/29 Minor update release.
186+
187+ Synchronize with TOMOYO 1.8.3 release.
188+
189+ Allow specifying domain transition preference.
190+
191+ Simplify garbage collector.
192+
193+Version 1.0.21 2011/10/25 Minor update release.
194+
195+ Synchronize with TOMOYO revision 5569.
196+
197+ Fix incomplete read after seek.
198+
199+ Use query id for reaching target process's domain policy.
200+
201+ Fix quota counting.
202+
203+Version 1.0.22 2011/11/11 Minor update release.
204+
205+ Synchronize with TOMOYO revision 5625.
206+
207+ Optimize for object's size.
208+
209+Version 1.0.23 2011/11/18 Minor update release.
210+
211+ Synchronize with TOMOYO revision 5646.
212+
213+ Fix kernel config mapping error.
214+
215+Version 1.0.24 2011/12/13 Minor update release.
216+
217+ Synchronize with TOMOYO revision 5711.
218+
219+ Follow __d_path() behavior change. (Only 2.6.36 and later)
220+
221+Version 1.0.25 2012/02/29 Minor update release.
222+
223+ Synchronize with TOMOYO revision 5893.
224+
225+ Follow UMH_WAIT_PROC constant renumbering.
226+
227+ Fix mount flags checking order.
228+
229+Version 1.0.26 2012/04/01 Minor update release.
230+
231+ Synchronize with TOMOYO revision 5973.
232+
233+ Return appropriate value to poll().
234+
235+Version 1.0.27 2012/05/05 Minor update release.
236+
237+ Synchronize with TOMOYO revision 6035.
238+
239+ Readd RHEL_MINOR/AX_MINOR checks.
240+
241+ Accept manager programs which do not start with / .
242+
243+Version 1.0.28 2012/10/20 Security update release.
244+
245+ Fix kernel panic caused by double kfree() bug when "struct ccs_execve"
246+ pointer was by error duplicated at __ccs_alloc_task_security().
247+ This bug affects only 2.6.28 and earlier kernels.
248+
249+Version 1.0.29 2012/11/04 Minor update release.
250+
251+ Use dummy pointer as needed in order to make sure that security_bprm_free()
252+ (which is used for making the caller of do_execve() return to previous
253+ domain when do_execve() failed after domain transition) is always called.
254+ Without this fix, domain transition history on 2.6.28 and earlier kernels
255+ becomes inaccurate.
256+
257+Version 1.0.30 2013/02/14 Minor update release.
258+
259+ Commit a2a8474c "exec: do not sleep in TASK_TRACED under ->cred_guard_mutex"
260+ moved "current->in_execve = 1;" from before prepare_bprm_creds() to after
261+ prepare_bprm_creds(). It turned out that, as an unexpected bonus, we can use
262+ security_prepare_creds() as a hook for emulating security_bprm_free() hook.
263+
264+ I updated the logic for security_bprm_free() emulation, and now AKARI should
265+ be able to coexist with other AKARI-like LKM-based LSM implementations (e.g.
266+ CaitSith) on all kernel versions other than 2.6.29 and 2.6.30.
267+
268+Version 1.0.31 2015/01/12 Minor update release.
269+
270+ Synchronize with TOMOYO revision 6373.
271+
272+ Fix missing chmod(-1) check in Linux 3.1 and later kernels.
273+
274+ Fix potentially using bogus attributes when stat() fails.
275+
276+Version 1.0.32 2015/04/08 Minor update release.
277+
278+ Synchronize with TOMOYO revision 6388.
279+
280+ Fix incorrect readdir() permission check.
281+
282+Version 1.0.33 2015/04/21 Minor update release.
283+
284+ Synchronize with TOMOYO revision 6407.
285+
286+ Fix incorrect retry request check.
--- tags/patches/1.0.33/internal.h (nonexistent)
+++ tags/patches/1.0.33/internal.h (revision 502)
@@ -0,0 +1,2164 @@
1+/*
2+ * security/ccsecurity/internal.h
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
7+ */
8+
9+#ifndef _SECURITY_CCSECURITY_INTERNAL_H
10+#define _SECURITY_CCSECURITY_INTERNAL_H
11+
12+#include <linux/version.h>
13+#include <linux/types.h>
14+#include <linux/kernel.h>
15+#include <linux/string.h>
16+#include <linux/mm.h>
17+#include <linux/utime.h>
18+#include <linux/file.h>
19+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38)
20+#include <linux/smp_lock.h>
21+#endif
22+#include <linux/module.h>
23+#include <linux/init.h>
24+#include <linux/slab.h>
25+#include <linux/highmem.h>
26+#include <linux/poll.h>
27+#include <linux/binfmts.h>
28+#include <linux/delay.h>
29+#include <linux/sched.h>
30+#include <linux/dcache.h>
31+#include <linux/mount.h>
32+#include <linux/net.h>
33+#include <linux/inet.h>
34+#include <linux/in.h>
35+#include <linux/in6.h>
36+#include <linux/un.h>
37+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
38+#include <linux/fs.h>
39+#endif
40+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
41+#include <linux/namei.h>
42+#endif
43+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
44+#include <linux/fs_struct.h>
45+#endif
46+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
47+#include <linux/namespace.h>
48+#endif
49+#include <linux/proc_fs.h>
50+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(RHEL_MAJOR)
51+#include <linux/hash.h>
52+#endif
53+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
54+#include <linux/sysctl.h>
55+#endif
56+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 6)
57+#include <linux/kthread.h>
58+#endif
59+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
60+#include <linux/magic.h>
61+#endif
62+#include <stdarg.h>
63+#include <asm/uaccess.h>
64+#include <net/sock.h>
65+#include <net/af_unix.h>
66+#include <net/ip.h>
67+#include <net/ipv6.h>
68+#include <net/udp.h>
69+
70+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
71+#define sk_family family
72+#define sk_protocol protocol
73+#define sk_type type
74+#endif
75+
76+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
77+
78+/* Structure for holding "struct vfsmount *" and "struct dentry *". */
79+struct path {
80+ struct vfsmount *mnt;
81+ struct dentry *dentry;
82+};
83+
84+#endif
85+
86+#ifndef __printf
87+#define __printf(a,b) __attribute__((format(printf,a,b)))
88+#endif
89+#ifndef __packed
90+#define __packed __attribute__((__packed__))
91+#endif
92+#ifndef bool
93+#define bool _Bool
94+#endif
95+#ifndef false
96+#define false 0
97+#endif
98+#ifndef true
99+#define true 1
100+#endif
101+
102+#ifndef __user
103+#define __user
104+#endif
105+
106+#ifndef current_uid
107+#define current_uid() (current->uid)
108+#endif
109+#ifndef current_gid
110+#define current_gid() (current->gid)
111+#endif
112+#ifndef current_euid
113+#define current_euid() (current->euid)
114+#endif
115+#ifndef current_egid
116+#define current_egid() (current->egid)
117+#endif
118+#ifndef current_suid
119+#define current_suid() (current->suid)
120+#endif
121+#ifndef current_sgid
122+#define current_sgid() (current->sgid)
123+#endif
124+#ifndef current_fsuid
125+#define current_fsuid() (current->fsuid)
126+#endif
127+#ifndef current_fsgid
128+#define current_fsgid() (current->fsgid)
129+#endif
130+
131+#ifndef DEFINE_SPINLOCK
132+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
133+#endif
134+
135+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
136+#define mutex semaphore
137+#define mutex_init(mutex) init_MUTEX(mutex)
138+#define mutex_unlock(mutex) up(mutex)
139+#define mutex_lock(mutex) down(mutex)
140+#define mutex_lock_interruptible(mutex) down_interruptible(mutex)
141+#define mutex_trylock(mutex) (!down_trylock(mutex))
142+#define DEFINE_MUTEX(mutexname) DECLARE_MUTEX(mutexname)
143+#endif
144+
145+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
146+#define MS_UNBINDABLE (1<<17) /* change to unbindable */
147+#define MS_PRIVATE (1<<18) /* change to private */
148+#define MS_SLAVE (1<<19) /* change to slave */
149+#define MS_SHARED (1<<20) /* change to shared */
150+#endif
151+
152+#ifndef container_of
153+#define container_of(ptr, type, member) ({ \
154+ const typeof(((type *)0)->member) *__mptr = (ptr); \
155+ (type *)((char *)__mptr - offsetof(type, member)); })
156+#endif
157+
158+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
159+#define smp_read_barrier_depends smp_rmb
160+#endif
161+
162+#ifndef ACCESS_ONCE
163+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
164+#endif
165+
166+#ifndef rcu_dereference
167+#define rcu_dereference(p) ({ \
168+ typeof(p) _________p1 = ACCESS_ONCE(p); \
169+ smp_read_barrier_depends(); /* see RCU */ \
170+ (_________p1); \
171+ })
172+#endif
173+
174+#ifndef rcu_assign_pointer
175+#define rcu_assign_pointer(p, v) \
176+ ({ \
177+ if (!__builtin_constant_p(v) || \
178+ ((v) != NULL)) \
179+ smp_wmb(); /* see RCU */ \
180+ (p) = (v); \
181+ })
182+#endif
183+
184+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
185+#define f_vfsmnt f_path.mnt
186+#endif
187+
188+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
189+
190+/**
191+ * kzalloc() - Allocate memory. The memory is set to zero.
192+ *
193+ * @size: Size to allocate.
194+ * @flags: GFP flags.
195+ *
196+ * Returns pointer to allocated memory on success, NULL otherwise.
197+ *
198+ * This is for compatibility with older kernels.
199+ *
200+ * Since several distributions backported kzalloc(), I define it as a macro
201+ * rather than an inlined function in order to avoid multiple definition error.
202+ */
203+#define kzalloc(size, flags) ({ \
204+ void *ret = kmalloc((size), (flags)); \
205+ if (ret) \
206+ memset(ret, 0, (size)); \
207+ ret; })
208+
209+#endif
210+
211+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
212+
213+/**
214+ * path_put - Drop reference on "struct path".
215+ *
216+ * @path: Pointer to "struct path".
217+ *
218+ * Returns nothing.
219+ *
220+ * This is for compatibility with older kernels.
221+ */
222+static inline void path_put(struct path *path)
223+{
224+ dput(path->dentry);
225+ mntput(path->mnt);
226+}
227+
228+#endif
229+
230+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
231+
232+/**
233+ * __list_add_rcu - Insert a new entry between two known consecutive entries.
234+ *
235+ * @new: Pointer to "struct list_head".
236+ * @prev: Pointer to "struct list_head".
237+ * @next: Pointer to "struct list_head".
238+ *
239+ * Returns nothing.
240+ *
241+ * This is for compatibility with older kernels.
242+ */
243+static inline void __list_add_rcu(struct list_head *new,
244+ struct list_head *prev,
245+ struct list_head *next)
246+{
247+ new->next = next;
248+ new->prev = prev;
249+ rcu_assign_pointer(prev->next, new);
250+ next->prev = new;
251+}
252+
253+/**
254+ * list_add_tail_rcu - Add a new entry to rcu-protected list.
255+ *
256+ * @new: Pointer to "struct list_head".
257+ * @head: Pointer to "struct list_head".
258+ *
259+ * Returns nothing.
260+ *
261+ * This is for compatibility with older kernels.
262+ */
263+static inline void list_add_tail_rcu(struct list_head *new,
264+ struct list_head *head)
265+{
266+ __list_add_rcu(new, head->prev, head);
267+}
268+
269+/**
270+ * list_add_rcu - Add a new entry to rcu-protected list.
271+ *
272+ * @new: Pointer to "struct list_head".
273+ * @head: Pointer to "struct list_head".
274+ *
275+ * Returns nothing.
276+ *
277+ * This is for compatibility with older kernels.
278+ */
279+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
280+{
281+ __list_add_rcu(new, head, head->next);
282+}
283+
284+#endif
285+
286+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
287+
288+/**
289+ * __list_del_entry - Deletes entry from list without re-initialization.
290+ *
291+ * @entry: Pointer to "struct list_head".
292+ *
293+ * Returns nothing.
294+ *
295+ * This is for compatibility with older kernels.
296+ */
297+static inline void __list_del_entry(struct list_head *entry)
298+{
299+ __list_del(entry->prev, entry->next);
300+}
301+
302+#endif
303+
304+#ifndef list_for_each_entry_safe
305+
306+/**
307+ * list_for_each_entry_safe - Iterate over list of given type safe against removal of list entry.
308+ *
309+ * @pos: The "type *" to use as a loop cursor.
310+ * @n: Another "type *" to use as temporary storage.
311+ * @head: Pointer to "struct list_head".
312+ * @member: The name of the list_struct within the struct.
313+ *
314+ * This is for compatibility with older kernels.
315+ */
316+#define list_for_each_entry_safe(pos, n, head, member) \
317+ for (pos = list_entry((head)->next, typeof(*pos), member), \
318+ n = list_entry(pos->member.next, typeof(*pos), member); \
319+ &pos->member != (head); \
320+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
321+
322+#endif
323+
324+#ifndef srcu_dereference
325+
326+/**
327+ * srcu_dereference - Fetch SRCU-protected pointer with checking.
328+ *
329+ * @p: The pointer to read, prior to dereferencing.
330+ * @ss: Pointer to "struct srcu_struct".
331+ *
332+ * Returns @p.
333+ *
334+ * This is for compatibility with older kernels.
335+ */
336+#define srcu_dereference(p, ss) rcu_dereference(p)
337+
338+#endif
339+
340+#ifndef list_for_each_entry_srcu
341+
342+/**
343+ * list_for_each_entry_srcu - Iterate over rcu list of given type.
344+ *
345+ * @pos: The type * to use as a loop cursor.
346+ * @head: The head for your list.
347+ * @member: The name of the list_struct within the struct.
348+ * @ss: Pointer to "struct srcu_struct".
349+ *
350+ * As of 2.6.36, this macro is not provided because only TOMOYO wants it.
351+ */
352+#define list_for_each_entry_srcu(pos, head, member, ss) \
353+ for (pos = list_entry(srcu_dereference((head)->next, ss), \
354+ typeof(*pos), member); \
355+ prefetch(pos->member.next), &pos->member != (head); \
356+ pos = list_entry(srcu_dereference(pos->member.next, ss), \
357+ typeof(*pos), member))
358+
359+#endif
360+
361+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 30) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9))
362+
363+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 4, 21)
364+#undef ssleep
365+#endif
366+
367+#ifndef ssleep
368+
369+/**
370+ * ssleep - Sleep for specified seconds.
371+ *
372+ * @secs: Seconds to sleep.
373+ *
374+ * Returns nothing.
375+ *
376+ * This is for compatibility with older kernels.
377+ *
378+ * Since several distributions backported ssleep(), I define it as a macro
379+ * rather than an inlined function in order to avoid multiple definition error.
380+ */
381+#define ssleep(secs) { \
382+ set_current_state(TASK_UNINTERRUPTIBLE); \
383+ schedule_timeout((HZ * secs) + 1); \
384+ }
385+
386+#endif
387+
388+#endif
389+
390+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
391+
392+/**
393+ * from_kuid - Convert kuid_t to uid_t.
394+ *
395+ * @ns: Unused.
396+ * @uid: kuid_t value.
397+ *
398+ * Returns uid seen from init's user namespace.
399+ */
400+#define from_kuid(ns, uid) (uid)
401+
402+/**
403+ * from_kgid - Convert kgid_t to gid_t.
404+ *
405+ * @ns: Unused.
406+ * @gid: kgid_t value.
407+ *
408+ * Returns gid seen from init's user namespace.
409+ */
410+#define from_kgid(ns, gid) (gid)
411+
412+/**
413+ * uid_eq - Check whether the uids are equals or not.
414+ *
415+ * @left: Uid seen from current user namespace.
416+ * @right: Uid seen from current user namespace.
417+ *
418+ * Returns true if uid is root in init's user namespace, false otherwise.
419+ */
420+#define uid_eq(left, right) ((left) == (right))
421+#define GLOBAL_ROOT_UID 0
422+
423+#endif
424+
425+/*
426+ * TOMOYO specific part start.
427+ */
428+
429+/* Clear TOMOYO 1.8 config. */
430+#undef CONFIG_CCSECURITY
431+#undef CONFIG_CCSECURITY_LKM
432+#undef CONFIG_CCSECURITY_DISABLE_BY_DEFAULT
433+#undef CONFIG_CCSECURITY_MAX_AUDIT_LOG
434+#undef CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY
435+#undef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
436+#undef CONFIG_CCSECURITY_POLICY_LOADER
437+#undef CONFIG_CCSECURITY_ACTIVATION_TRIGGER
438+#undef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
439+#undef CONFIG_CCSECURITY_FILE_READDIR
440+#undef CONFIG_CCSECURITY_FILE_GETATTR
441+#undef CONFIG_CCSECURITY_NETWORK
442+#undef CONFIG_CCSECURITY_NETWORK_RECVMSG
443+#undef CONFIG_CCSECURITY_CAPABILITY
444+#undef CONFIG_CCSECURITY_IPC
445+#undef CONFIG_CCSECURITY_MISC
446+#undef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
447+#undef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
448+#undef CONFIG_CCSECURITY_PORTRESERVE
449+/* Define AKARI 1.0 config. */
450+#include "config.h"
451+#ifndef CONFIG_CCSECURITY
452+#define CONFIG_CCSECURITY
453+#endif
454+#ifndef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
455+#define CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
456+#endif
457+#ifndef CONFIG_CCSECURITY_MAX_AUDIT_LOG
458+#define CONFIG_CCSECURITY_MAX_AUDIT_LOG 1024
459+#endif
460+#ifndef CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY
461+#define CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY 2048
462+#endif
463+#ifndef CONFIG_CCSECURITY_POLICY_LOADER
464+#define CONFIG_CCSECURITY_POLICY_LOADER "/sbin/ccs-init"
465+#endif
466+#ifndef CONFIG_CCSECURITY_ACTIVATION_TRIGGER
467+#define CONFIG_CCSECURITY_ACTIVATION_TRIGGER "/sbin/init"
468+#endif
469+#include "ccsecurity.h"
470+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
471+#error This module supports only 2.6.0 and later kernels.
472+#endif
473+#ifndef CONFIG_SECURITY
474+#error You must choose CONFIG_SECURITY=y for building this module.
475+#endif
476+#ifndef CONFIG_KALLSYMS
477+#error You must choose CONFIG_KALLSYMS=y for building this module.
478+#endif
479+#ifndef CONFIG_PROC_FS
480+#error You must choose CONFIG_PROC_FS=y for building this module.
481+#endif
482+#ifndef CONFIG_MODULES
483+#error You must choose CONFIG_MODULES=y for building this module.
484+#endif
485+
486+/* Enumeration definition for internal use. */
487+
488+/* Index numbers for Access Controls. */
489+enum ccs_acl_entry_type_index {
490+ CCS_TYPE_PATH_ACL,
491+ CCS_TYPE_PATH2_ACL,
492+ CCS_TYPE_PATH_NUMBER_ACL,
493+ CCS_TYPE_MKDEV_ACL,
494+ CCS_TYPE_MOUNT_ACL,
495+#ifdef CONFIG_CCSECURITY_MISC
496+ CCS_TYPE_ENV_ACL,
497+#endif
498+#ifdef CONFIG_CCSECURITY_CAPABILITY
499+ CCS_TYPE_CAPABILITY_ACL,
500+#endif
501+#ifdef CONFIG_CCSECURITY_NETWORK
502+ CCS_TYPE_INET_ACL,
503+ CCS_TYPE_UNIX_ACL,
504+#endif
505+#ifdef CONFIG_CCSECURITY_IPC
506+ CCS_TYPE_SIGNAL_ACL,
507+#endif
508+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
509+ CCS_TYPE_AUTO_EXECUTE_HANDLER,
510+ CCS_TYPE_DENIED_EXECUTE_HANDLER,
511+#endif
512+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
513+ CCS_TYPE_AUTO_TASK_ACL,
514+ CCS_TYPE_MANUAL_TASK_ACL,
515+#endif
516+};
517+
518+/* Index numbers for "struct ccs_condition". */
519+enum ccs_conditions_index {
520+ CCS_TASK_UID, /* current_uid() */
521+ CCS_TASK_EUID, /* current_euid() */
522+ CCS_TASK_SUID, /* current_suid() */
523+ CCS_TASK_FSUID, /* current_fsuid() */
524+ CCS_TASK_GID, /* current_gid() */
525+ CCS_TASK_EGID, /* current_egid() */
526+ CCS_TASK_SGID, /* current_sgid() */
527+ CCS_TASK_FSGID, /* current_fsgid() */
528+ CCS_TASK_PID, /* sys_getpid() */
529+ CCS_TASK_PPID, /* sys_getppid() */
530+ CCS_EXEC_ARGC, /* "struct linux_binprm *"->argc */
531+ CCS_EXEC_ENVC, /* "struct linux_binprm *"->envc */
532+ CCS_TYPE_IS_SOCKET, /* S_IFSOCK */
533+ CCS_TYPE_IS_SYMLINK, /* S_IFLNK */
534+ CCS_TYPE_IS_FILE, /* S_IFREG */
535+ CCS_TYPE_IS_BLOCK_DEV, /* S_IFBLK */
536+ CCS_TYPE_IS_DIRECTORY, /* S_IFDIR */
537+ CCS_TYPE_IS_CHAR_DEV, /* S_IFCHR */
538+ CCS_TYPE_IS_FIFO, /* S_IFIFO */
539+ CCS_MODE_SETUID, /* S_ISUID */
540+ CCS_MODE_SETGID, /* S_ISGID */
541+ CCS_MODE_STICKY, /* S_ISVTX */
542+ CCS_MODE_OWNER_READ, /* S_IRUSR */
543+ CCS_MODE_OWNER_WRITE, /* S_IWUSR */
544+ CCS_MODE_OWNER_EXECUTE, /* S_IXUSR */
545+ CCS_MODE_GROUP_READ, /* S_IRGRP */
546+ CCS_MODE_GROUP_WRITE, /* S_IWGRP */
547+ CCS_MODE_GROUP_EXECUTE, /* S_IXGRP */
548+ CCS_MODE_OTHERS_READ, /* S_IROTH */
549+ CCS_MODE_OTHERS_WRITE, /* S_IWOTH */
550+ CCS_MODE_OTHERS_EXECUTE, /* S_IXOTH */
551+ CCS_TASK_TYPE, /* ((u8) task->ccs_flags) &
552+ CCS_TASK_IS_EXECUTE_HANDLER */
553+ CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
554+ CCS_EXEC_REALPATH,
555+ CCS_SYMLINK_TARGET,
556+ CCS_PATH1_UID,
557+ CCS_PATH1_GID,
558+ CCS_PATH1_INO,
559+ CCS_PATH1_MAJOR,
560+ CCS_PATH1_MINOR,
561+ CCS_PATH1_PERM,
562+ CCS_PATH1_TYPE,
563+ CCS_PATH1_DEV_MAJOR,
564+ CCS_PATH1_DEV_MINOR,
565+ CCS_PATH2_UID,
566+ CCS_PATH2_GID,
567+ CCS_PATH2_INO,
568+ CCS_PATH2_MAJOR,
569+ CCS_PATH2_MINOR,
570+ CCS_PATH2_PERM,
571+ CCS_PATH2_TYPE,
572+ CCS_PATH2_DEV_MAJOR,
573+ CCS_PATH2_DEV_MINOR,
574+ CCS_PATH1_PARENT_UID,
575+ CCS_PATH1_PARENT_GID,
576+ CCS_PATH1_PARENT_INO,
577+ CCS_PATH1_PARENT_PERM,
578+ CCS_PATH2_PARENT_UID,
579+ CCS_PATH2_PARENT_GID,
580+ CCS_PATH2_PARENT_INO,
581+ CCS_PATH2_PARENT_PERM,
582+ CCS_MAX_CONDITION_KEYWORD,
583+ CCS_NUMBER_UNION,
584+ CCS_NAME_UNION,
585+ CCS_ARGV_ENTRY,
586+ CCS_ENVP_ENTRY,
587+};
588+
589+/* Index numbers for domain's attributes. */
590+enum ccs_domain_info_flags_index {
591+ /* Quota warnning flag. */
592+ CCS_DIF_QUOTA_WARNED,
593+ /*
594+ * This domain was unable to create a new domain at
595+ * ccs_find_next_domain() because the name of the domain to be created
596+ * was too long or it could not allocate memory.
597+ * More than one process continued execve() without domain transition.
598+ */
599+ CCS_DIF_TRANSITION_FAILED,
600+ CCS_MAX_DOMAIN_INFO_FLAGS
601+};
602+
603+/* Index numbers for audit type. */
604+enum ccs_grant_log {
605+ /* Follow profile's configuration. */
606+ CCS_GRANTLOG_AUTO,
607+ /* Do not generate grant log. */
608+ CCS_GRANTLOG_NO,
609+ /* Generate grant_log. */
610+ CCS_GRANTLOG_YES,
611+};
612+
613+/* Index numbers for group entries. */
614+enum ccs_group_id {
615+ CCS_PATH_GROUP,
616+ CCS_NUMBER_GROUP,
617+#ifdef CONFIG_CCSECURITY_NETWORK
618+ CCS_ADDRESS_GROUP,
619+#endif
620+ CCS_MAX_GROUP
621+};
622+
623+/* Index numbers for category of functionality. */
624+enum ccs_mac_category_index {
625+ CCS_MAC_CATEGORY_FILE,
626+#ifdef CONFIG_CCSECURITY_NETWORK
627+ CCS_MAC_CATEGORY_NETWORK,
628+#endif
629+#ifdef CONFIG_CCSECURITY_MISC
630+ CCS_MAC_CATEGORY_MISC,
631+#endif
632+#ifdef CONFIG_CCSECURITY_IPC
633+ CCS_MAC_CATEGORY_IPC,
634+#endif
635+#ifdef CONFIG_CCSECURITY_CAPABILITY
636+ CCS_MAC_CATEGORY_CAPABILITY,
637+#endif
638+ CCS_MAX_MAC_CATEGORY_INDEX
639+};
640+
641+/* Index numbers for functionality. */
642+enum ccs_mac_index {
643+ CCS_MAC_FILE_EXECUTE,
644+ CCS_MAC_FILE_OPEN,
645+ CCS_MAC_FILE_CREATE,
646+ CCS_MAC_FILE_UNLINK,
647+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
648+ CCS_MAC_FILE_GETATTR,
649+#endif
650+ CCS_MAC_FILE_MKDIR,
651+ CCS_MAC_FILE_RMDIR,
652+ CCS_MAC_FILE_MKFIFO,
653+ CCS_MAC_FILE_MKSOCK,
654+ CCS_MAC_FILE_TRUNCATE,
655+ CCS_MAC_FILE_SYMLINK,
656+ CCS_MAC_FILE_MKBLOCK,
657+ CCS_MAC_FILE_MKCHAR,
658+ CCS_MAC_FILE_LINK,
659+ CCS_MAC_FILE_RENAME,
660+ CCS_MAC_FILE_CHMOD,
661+ CCS_MAC_FILE_CHOWN,
662+ CCS_MAC_FILE_CHGRP,
663+ CCS_MAC_FILE_IOCTL,
664+ CCS_MAC_FILE_CHROOT,
665+ CCS_MAC_FILE_MOUNT,
666+ CCS_MAC_FILE_UMOUNT,
667+ CCS_MAC_FILE_PIVOT_ROOT,
668+#ifdef CONFIG_CCSECURITY_NETWORK
669+ CCS_MAC_NETWORK_INET_STREAM_BIND,
670+ CCS_MAC_NETWORK_INET_STREAM_LISTEN,
671+ CCS_MAC_NETWORK_INET_STREAM_CONNECT,
672+ CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
673+ CCS_MAC_NETWORK_INET_DGRAM_BIND,
674+ CCS_MAC_NETWORK_INET_DGRAM_SEND,
675+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
676+ CCS_MAC_NETWORK_INET_DGRAM_RECV,
677+#endif
678+ CCS_MAC_NETWORK_INET_RAW_BIND,
679+ CCS_MAC_NETWORK_INET_RAW_SEND,
680+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
681+ CCS_MAC_NETWORK_INET_RAW_RECV,
682+#endif
683+ CCS_MAC_NETWORK_UNIX_STREAM_BIND,
684+ CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
685+ CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
686+ CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
687+ CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
688+ CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
689+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
690+ CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
691+#endif
692+ CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
693+ CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
694+ CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
695+ CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
696+#endif
697+#ifdef CONFIG_CCSECURITY_MISC
698+ CCS_MAC_ENVIRON,
699+#endif
700+#ifdef CONFIG_CCSECURITY_IPC
701+ CCS_MAC_SIGNAL,
702+#endif
703+#ifdef CONFIG_CCSECURITY_CAPABILITY
704+ CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
705+ CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
706+ CCS_MAC_CAPABILITY_SYS_REBOOT,
707+ CCS_MAC_CAPABILITY_SYS_VHANGUP,
708+ CCS_MAC_CAPABILITY_SYS_SETTIME,
709+ CCS_MAC_CAPABILITY_SYS_NICE,
710+ CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
711+ CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
712+ CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
713+ CCS_MAC_CAPABILITY_SYS_PTRACE,
714+#endif
715+ CCS_MAX_MAC_INDEX
716+};
717+
718+/* Index numbers for /proc/ccs/stat interface. */
719+enum ccs_memory_stat_type {
720+ CCS_MEMORY_POLICY,
721+ CCS_MEMORY_AUDIT,
722+ CCS_MEMORY_QUERY,
723+ CCS_MAX_MEMORY_STAT
724+};
725+
726+/* Index numbers for access controls with one pathname and three numbers. */
727+enum ccs_mkdev_acl_index {
728+ CCS_TYPE_MKBLOCK,
729+ CCS_TYPE_MKCHAR,
730+ CCS_MAX_MKDEV_OPERATION
731+};
732+
733+/* Index numbers for operation mode. */
734+enum ccs_mode_value {
735+ CCS_CONFIG_DISABLED,
736+ CCS_CONFIG_LEARNING,
737+ CCS_CONFIG_PERMISSIVE,
738+ CCS_CONFIG_ENFORCING,
739+ CCS_CONFIG_MAX_MODE,
740+ CCS_CONFIG_WANT_REJECT_LOG = 64,
741+ CCS_CONFIG_WANT_GRANT_LOG = 128,
742+ CCS_CONFIG_USE_DEFAULT = 255,
743+};
744+
745+/* Index numbers for socket operations. */
746+enum ccs_network_acl_index {
747+ CCS_NETWORK_BIND, /* bind() operation. */
748+ CCS_NETWORK_LISTEN, /* listen() operation. */
749+ CCS_NETWORK_CONNECT, /* connect() operation. */
750+ CCS_NETWORK_ACCEPT, /* accept() operation. */
751+ CCS_NETWORK_SEND, /* send() operation. */
752+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
753+ CCS_NETWORK_RECV, /* recv() operation. */
754+#endif
755+ CCS_MAX_NETWORK_OPERATION
756+};
757+
758+/* Index numbers for access controls with two pathnames. */
759+enum ccs_path2_acl_index {
760+ CCS_TYPE_LINK,
761+ CCS_TYPE_RENAME,
762+ CCS_TYPE_PIVOT_ROOT,
763+ CCS_MAX_PATH2_OPERATION
764+};
765+
766+/* Index numbers for access controls with one pathname. */
767+enum ccs_path_acl_index {
768+ CCS_TYPE_EXECUTE,
769+ CCS_TYPE_READ,
770+ CCS_TYPE_WRITE,
771+ CCS_TYPE_APPEND,
772+ CCS_TYPE_UNLINK,
773+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
774+ CCS_TYPE_GETATTR,
775+#endif
776+ CCS_TYPE_RMDIR,
777+ CCS_TYPE_TRUNCATE,
778+ CCS_TYPE_SYMLINK,
779+ CCS_TYPE_CHROOT,
780+ CCS_TYPE_UMOUNT,
781+ CCS_MAX_PATH_OPERATION
782+};
783+
784+/* Index numbers for access controls with one pathname and one number. */
785+enum ccs_path_number_acl_index {
786+ CCS_TYPE_CREATE,
787+ CCS_TYPE_MKDIR,
788+ CCS_TYPE_MKFIFO,
789+ CCS_TYPE_MKSOCK,
790+ CCS_TYPE_IOCTL,
791+ CCS_TYPE_CHMOD,
792+ CCS_TYPE_CHOWN,
793+ CCS_TYPE_CHGRP,
794+ CCS_MAX_PATH_NUMBER_OPERATION
795+};
796+
797+/* Index numbers for stat(). */
798+enum ccs_path_stat_index {
799+ /* Do not change this order. */
800+ CCS_PATH1,
801+ CCS_PATH1_PARENT,
802+ CCS_PATH2,
803+ CCS_PATH2_PARENT,
804+ CCS_MAX_PATH_STAT
805+};
806+
807+/* Index numbers for entry type. */
808+enum ccs_policy_id {
809+#ifdef CONFIG_CCSECURITY_PORTRESERVE
810+ CCS_ID_RESERVEDPORT,
811+#endif
812+ CCS_ID_GROUP,
813+#ifdef CONFIG_CCSECURITY_NETWORK
814+ CCS_ID_ADDRESS_GROUP,
815+#endif
816+ CCS_ID_PATH_GROUP,
817+ CCS_ID_NUMBER_GROUP,
818+ CCS_ID_AGGREGATOR,
819+ CCS_ID_TRANSITION_CONTROL,
820+ CCS_ID_MANAGER,
821+ CCS_ID_CONDITION,
822+ CCS_ID_NAME,
823+ CCS_ID_ACL,
824+ CCS_ID_DOMAIN,
825+ CCS_MAX_POLICY
826+};
827+
828+/* Index numbers for /proc/ccs/stat interface. */
829+enum ccs_policy_stat_type {
830+ /* Do not change this order. */
831+ CCS_STAT_POLICY_UPDATES,
832+ CCS_STAT_POLICY_LEARNING, /* == CCS_CONFIG_LEARNING */
833+ CCS_STAT_POLICY_PERMISSIVE, /* == CCS_CONFIG_PERMISSIVE */
834+ CCS_STAT_POLICY_ENFORCING, /* == CCS_CONFIG_ENFORCING */
835+ CCS_MAX_POLICY_STAT
836+};
837+
838+/* Index numbers for profile's PREFERENCE values. */
839+enum ccs_pref_index {
840+ CCS_PREF_MAX_AUDIT_LOG,
841+ CCS_PREF_MAX_LEARNING_ENTRY,
842+ CCS_PREF_ENFORCING_PENALTY,
843+ CCS_MAX_PREF
844+};
845+
846+/* Index numbers for /proc/ccs/ interfaces. */
847+enum ccs_proc_interface_index {
848+ CCS_DOMAIN_POLICY,
849+ CCS_EXCEPTION_POLICY,
850+ CCS_PROCESS_STATUS,
851+ CCS_STAT,
852+ CCS_AUDIT,
853+ CCS_VERSION,
854+ CCS_PROFILE,
855+ CCS_QUERY,
856+ CCS_MANAGER,
857+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
858+ CCS_EXECUTE_HANDLER,
859+#endif
860+};
861+
862+/* Index numbers for special mount operations. */
863+enum ccs_special_mount {
864+ CCS_MOUNT_BIND, /* mount --bind /source /dest */
865+ CCS_MOUNT_MOVE, /* mount --move /old /new */
866+ CCS_MOUNT_REMOUNT, /* mount -o remount /dir */
867+ CCS_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
868+ CCS_MOUNT_MAKE_PRIVATE, /* mount --make-private /dir */
869+ CCS_MOUNT_MAKE_SLAVE, /* mount --make-slave /dir */
870+ CCS_MOUNT_MAKE_SHARED, /* mount --make-shared /dir */
871+ CCS_MAX_SPECIAL_MOUNT
872+};
873+
874+/* Index numbers for domain transition control keywords. */
875+enum ccs_transition_type {
876+ /* Do not change this order, */
877+ CCS_TRANSITION_CONTROL_NO_RESET,
878+ CCS_TRANSITION_CONTROL_RESET,
879+ CCS_TRANSITION_CONTROL_NO_INITIALIZE,
880+ CCS_TRANSITION_CONTROL_INITIALIZE,
881+ CCS_TRANSITION_CONTROL_NO_KEEP,
882+ CCS_TRANSITION_CONTROL_KEEP,
883+ CCS_MAX_TRANSITION_TYPE
884+};
885+
886+/* Index numbers for type of numeric values. */
887+enum ccs_value_type {
888+ CCS_VALUE_TYPE_INVALID,
889+ CCS_VALUE_TYPE_DECIMAL,
890+ CCS_VALUE_TYPE_OCTAL,
891+ CCS_VALUE_TYPE_HEXADECIMAL,
892+};
893+
894+/* Constants definition for internal use. */
895+
896+/*
897+ * TOMOYO uses this hash only when appending a string into the string table.
898+ * Frequency of appending strings is very low. So we don't need large (e.g.
899+ * 64k) hash size. 256 will be sufficient.
900+ */
901+#define CCS_HASH_BITS 8
902+#define CCS_MAX_HASH (1u << CCS_HASH_BITS)
903+
904+/*
905+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
906+ * Therefore, we don't need SOCK_MAX.
907+ */
908+#define CCS_SOCK_MAX 6
909+
910+/* Size of temporary buffer for execve() operation. */
911+#define CCS_EXEC_TMPSIZE 4096
912+
913+/* Garbage collector is trying to kfree() this element. */
914+#define CCS_GC_IN_PROGRESS -1
915+
916+/* Profile number is an integer between 0 and 255. */
917+#define CCS_MAX_PROFILES 256
918+
919+/* Group number is an integer between 0 and 255. */
920+#define CCS_MAX_ACL_GROUPS 256
921+
922+/* Current thread is doing open(O_RDONLY | O_TRUNC) ? */
923+#define CCS_OPEN_FOR_READ_TRUNCATE 1
924+/* Current thread is doing open(3) ? */
925+#define CCS_OPEN_FOR_IOCTL_ONLY 2
926+/* Current thread is doing do_execve() ? */
927+#define CCS_TASK_IS_IN_EXECVE 4
928+/* Current thread is running as an execute handler program? */
929+#define CCS_TASK_IS_EXECUTE_HANDLER 8
930+/* Current thread is allowed to modify policy via /proc/ccs/ interface? */
931+#define CCS_TASK_IS_MANAGER 16
932+
933+/*
934+ * Retry this request. Returned by ccs_supervisor() if policy violation has
935+ * occurred in enforcing mode and the userspace daemon decided to retry.
936+ *
937+ * We must choose a positive value in order to distinguish "granted" (which is
938+ * 0) and "rejected" (which is a negative value) and "retry".
939+ */
940+#define CCS_RETRY_REQUEST 1
941+
942+/* Ignore gfp flags which are not supported. */
943+#ifndef __GFP_HIGHIO
944+#define __GFP_HIGHIO 0
945+#endif
946+#ifndef __GFP_NOWARN
947+#define __GFP_NOWARN 0
948+#endif
949+#ifndef __GFP_NORETRY
950+#define __GFP_NORETRY 0
951+#endif
952+#ifndef __GFP_NOMEMALLOC
953+#define __GFP_NOMEMALLOC 0
954+#endif
955+
956+/* The gfp flags used by TOMOYO. */
957+#define CCS_GFP_FLAGS (__GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_NOWARN | \
958+ __GFP_NORETRY | __GFP_NOMEMALLOC)
959+
960+/* Size of read buffer for /proc/ccs/ interface. */
961+#define CCS_MAX_IO_READ_QUEUE 64
962+
963+/* Structure definition for internal use. */
964+
965+/* Common header for holding ACL entries. */
966+struct ccs_acl_head {
967+ struct list_head list;
968+ s8 is_deleted; /* true or false or CCS_GC_IN_PROGRESS */
969+} __packed;
970+
971+/* Common header for shared entries. */
972+struct ccs_shared_acl_head {
973+ struct list_head list;
974+ atomic_t users;
975+} __packed;
976+
977+/* Common header for individual entries. */
978+struct ccs_acl_info {
979+ struct list_head list;
980+ struct ccs_condition *cond; /* Maybe NULL. */
981+ s8 is_deleted; /* true or false or CCS_GC_IN_PROGRESS */
982+ u8 type; /* One of values in "enum ccs_acl_entry_type_index". */
983+ u16 perm;
984+} __packed;
985+
986+/* Structure for holding a word. */
987+struct ccs_name_union {
988+ /* Either @filename or @group is NULL. */
989+ const struct ccs_path_info *filename;
990+ struct ccs_group *group;
991+};
992+
993+/* Structure for holding a number. */
994+struct ccs_number_union {
995+ unsigned long values[2];
996+ struct ccs_group *group; /* Maybe NULL. */
997+ /* One of values in "enum ccs_value_type". */
998+ u8 value_type[2];
999+};
1000+
1001+/* Structure for holding an IP address. */
1002+struct ccs_ipaddr_union {
1003+ struct in6_addr ip[2]; /* Big endian. */
1004+ struct ccs_group *group; /* Pointer to address group. */
1005+ bool is_ipv6; /* Valid only if @group == NULL. */
1006+};
1007+
1008+/* Structure for "path_group"/"number_group"/"address_group" directive. */
1009+struct ccs_group {
1010+ struct ccs_shared_acl_head head;
1011+ /* Name of group (without leading '@'). */
1012+ const struct ccs_path_info *group_name;
1013+ /*
1014+ * List of "struct ccs_path_group" or "struct ccs_number_group" or
1015+ * "struct ccs_address_group".
1016+ */
1017+ struct list_head member_list;
1018+};
1019+
1020+/* Structure for "path_group" directive. */
1021+struct ccs_path_group {
1022+ struct ccs_acl_head head;
1023+ const struct ccs_path_info *member_name;
1024+};
1025+
1026+/* Structure for "number_group" directive. */
1027+struct ccs_number_group {
1028+ struct ccs_acl_head head;
1029+ struct ccs_number_union number;
1030+};
1031+
1032+/* Structure for "address_group" directive. */
1033+struct ccs_address_group {
1034+ struct ccs_acl_head head;
1035+ /* Structure for holding an IP address. */
1036+ struct ccs_ipaddr_union address;
1037+};
1038+
1039+/* Subset of "struct stat". Used by conditional ACL and audit logs. */
1040+struct ccs_mini_stat {
1041+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
1042+ kuid_t uid;
1043+ kgid_t gid;
1044+#else
1045+ uid_t uid;
1046+ gid_t gid;
1047+#endif
1048+ ino_t ino;
1049+ umode_t mode;
1050+ dev_t dev;
1051+ dev_t rdev;
1052+};
1053+
1054+/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
1055+struct ccs_page_dump {
1056+ struct page *page; /* Previously dumped page. */
1057+ char *data; /* Contents of "page". Size is PAGE_SIZE. */
1058+};
1059+
1060+/* Structure for attribute checks in addition to pathname checks. */
1061+struct ccs_obj_info {
1062+ /* True if ccs_get_attributes() was already called, false otherwise. */
1063+ bool validate_done;
1064+ /* True if @stat[] is valid. */
1065+ bool stat_valid[CCS_MAX_PATH_STAT];
1066+ /* First pathname. Initialized with { NULL, NULL } if no path. */
1067+ struct path path1;
1068+ /* Second pathname. Initialized with { NULL, NULL } if no path. */
1069+ struct path path2;
1070+ /*
1071+ * Information on @path1, @path1's parent directory, @path2, @path2's
1072+ * parent directory.
1073+ */
1074+ struct ccs_mini_stat stat[CCS_MAX_PATH_STAT];
1075+ /*
1076+ * Content of symbolic link to be created. NULL for operations other
1077+ * than symlink().
1078+ */
1079+ struct ccs_path_info *symlink_target;
1080+};
1081+
1082+/* Structure for entries which follows "struct ccs_condition". */
1083+struct ccs_condition_element {
1084+ /*
1085+ * Left hand operand. A "struct ccs_argv" for CCS_ARGV_ENTRY, a
1086+ * "struct ccs_envp" for CCS_ENVP_ENTRY is attached to the tail
1087+ * of the array of this struct.
1088+ */
1089+ u8 left;
1090+ /*
1091+ * Right hand operand. A "struct ccs_number_union" for
1092+ * CCS_NUMBER_UNION, a "struct ccs_name_union" for CCS_NAME_UNION is
1093+ * attached to the tail of the array of this struct.
1094+ */
1095+ u8 right;
1096+ /* Equation operator. True if equals or overlaps, false otherwise. */
1097+ bool equals;
1098+};
1099+
1100+/* Structure for optional arguments. */
1101+struct ccs_condition {
1102+ struct ccs_shared_acl_head head;
1103+ u32 size; /* Memory size allocated for this entry. */
1104+ u16 condc; /* Number of conditions in this struct. */
1105+ u16 numbers_count; /* Number of "struct ccs_number_union values". */
1106+ u16 names_count; /* Number of "struct ccs_name_union names". */
1107+ u16 argc; /* Number of "struct ccs_argv". */
1108+ u16 envc; /* Number of "struct ccs_envp". */
1109+ u8 grant_log; /* One of values in "enum ccs_grant_log". */
1110+ bool exec_transit; /* True if transit is for "file execute". */
1111+ const struct ccs_path_info *transit; /* Maybe NULL. */
1112+ /*
1113+ * struct ccs_condition_element condition[condc];
1114+ * struct ccs_number_union values[numbers_count];
1115+ * struct ccs_name_union names[names_count];
1116+ * struct ccs_argv argv[argc];
1117+ * struct ccs_envp envp[envc];
1118+ */
1119+};
1120+
1121+struct ccs_execve;
1122+struct ccs_policy_namespace;
1123+
1124+/* Structure for request info. */
1125+struct ccs_request_info {
1126+ /*
1127+ * For holding parameters specific to operations which deal files.
1128+ * NULL if not dealing files.
1129+ */
1130+ struct ccs_obj_info *obj;
1131+ /*
1132+ * For holding parameters specific to execve() request.
1133+ * NULL if not dealing do_execve().
1134+ */
1135+ struct ccs_execve *ee;
1136+ /*
1137+ * For holding parameters.
1138+ * Pointers in this union are not NULL except path->matched_path.
1139+ */
1140+ union {
1141+ struct {
1142+ const struct ccs_path_info *filename;
1143+ /*
1144+ * For using wildcards at ccs_find_next_domain().
1145+ *
1146+ * The matched_acl cannot be used because it may refer
1147+ * a "struct ccs_path_acl" with ->is_group == true.
1148+ * We want to use exact "struct ccs_path_info" rather
1149+ * than "struct ccs_path_acl".
1150+ */
1151+ const struct ccs_path_info *matched_path;
1152+ /* One of values in "enum ccs_path_acl_index". */
1153+ u8 operation;
1154+ } path;
1155+ struct {
1156+ const struct ccs_path_info *filename1;
1157+ const struct ccs_path_info *filename2;
1158+ /* One of values in "enum ccs_path2_acl_index". */
1159+ u8 operation;
1160+ } path2;
1161+ struct {
1162+ const struct ccs_path_info *filename;
1163+ unsigned int mode;
1164+ unsigned int major;
1165+ unsigned int minor;
1166+ /* One of values in "enum ccs_mkdev_acl_index". */
1167+ u8 operation;
1168+ } mkdev;
1169+ struct {
1170+ const struct ccs_path_info *filename;
1171+ unsigned long number;
1172+ /*
1173+ * One of values in "enum ccs_path_number_acl_index".
1174+ */
1175+ u8 operation;
1176+ } path_number;
1177+#ifdef CONFIG_CCSECURITY_NETWORK
1178+ struct {
1179+ const u32 *address; /* Big endian. */
1180+ u16 port; /* Host endian. */
1181+ /* One of values smaller than CCS_SOCK_MAX. */
1182+ u8 protocol;
1183+ /* One of values in "enum ccs_network_acl_index". */
1184+ u8 operation;
1185+ bool is_ipv6;
1186+ } inet_network;
1187+ struct {
1188+ const struct ccs_path_info *address;
1189+ /* One of values smaller than CCS_SOCK_MAX. */
1190+ u8 protocol;
1191+ /* One of values in "enum ccs_network_acl_index". */
1192+ u8 operation;
1193+ } unix_network;
1194+#endif
1195+#ifdef CONFIG_CCSECURITY_MISC
1196+ struct {
1197+ const struct ccs_path_info *name;
1198+ } environ;
1199+#endif
1200+#ifdef CONFIG_CCSECURITY_CAPABILITY
1201+ struct {
1202+ /* One of values in "enum ccs_capability_acl_index". */
1203+ u8 operation;
1204+ } capability;
1205+#endif
1206+#ifdef CONFIG_CCSECURITY_IPC
1207+ struct {
1208+ const char *dest_pattern;
1209+ int sig;
1210+ } signal;
1211+#endif
1212+ struct {
1213+ const struct ccs_path_info *type;
1214+ const struct ccs_path_info *dir;
1215+ const struct ccs_path_info *dev;
1216+ unsigned long flags;
1217+ int need_dev;
1218+ } mount;
1219+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
1220+ struct {
1221+ const struct ccs_path_info *domainname;
1222+ } task;
1223+#endif
1224+ } param;
1225+ /*
1226+ * For updating current->ccs_domain_info at ccs_update_task_domain().
1227+ * Initialized to NULL at ccs_init_request_info().
1228+ * Matching "struct ccs_acl_info" is copied if access request was
1229+ * granted. Re-initialized to NULL at ccs_update_task_domain().
1230+ */
1231+ struct ccs_acl_info *matched_acl;
1232+ u8 param_type; /* One of values in "enum ccs_acl_entry_type_index". */
1233+ bool granted; /* True if granted, false otherwise. */
1234+ /* True if current thread should not be carried sleep penalty. */
1235+ bool dont_sleep_on_enforce_error;
1236+ /*
1237+ * For counting number of retries made for this request.
1238+ * This counter is incremented whenever ccs_supervisor() returned
1239+ * CCS_RETRY_REQUEST.
1240+ */
1241+ u8 retry;
1242+ /*
1243+ * For holding profile number used for this request.
1244+ * One of values between 0 and CCS_MAX_PROFILES - 1.
1245+ */
1246+ u8 profile;
1247+ /*
1248+ * For holding operation mode used for this request.
1249+ * One of CCS_CONFIG_DISABLED, CCS_CONFIG_LEARNING,
1250+ * CCS_CONFIG_PERMISSIVE, CCS_CONFIG_ENFORCING.
1251+ */
1252+ u8 mode;
1253+ /*
1254+ * For holding operation index used for this request.
1255+ * Used by ccs_init_request_info() / ccs_get_mode() /
1256+ * ccs_write_log(). One of values in "enum ccs_mac_index".
1257+ */
1258+ u8 type;
1259+};
1260+
1261+/* Structure for holding a token. */
1262+struct ccs_path_info {
1263+ const char *name;
1264+ u32 hash; /* = full_name_hash(name, strlen(name)) */
1265+ u16 total_len; /* = strlen(name) */
1266+ u16 const_len; /* = ccs_const_part_length(name) */
1267+ bool is_dir; /* = ccs_strendswith(name, "/") */
1268+ bool is_patterned; /* = const_len < total_len */
1269+};
1270+
1271+/* Structure for execve() operation. */
1272+struct ccs_execve {
1273+ struct ccs_request_info r;
1274+ struct ccs_obj_info obj;
1275+ struct linux_binprm *bprm;
1276+ struct ccs_domain_info *previous_domain;
1277+ const struct ccs_path_info *transition;
1278+ /* For execute_handler */
1279+ const struct ccs_path_info *handler;
1280+ char *handler_path; /* = kstrdup(handler->name, CCS_GFP_FLAGS) */
1281+ /* For dumping argv[] and envp[]. */
1282+ struct ccs_page_dump dump;
1283+ /* For temporary use. */
1284+ char *tmp; /* Size is CCS_EXEC_TMPSIZE bytes */
1285+};
1286+
1287+/* Structure for domain information. */
1288+struct ccs_domain_info {
1289+ struct list_head list;
1290+ struct list_head acl_info_list;
1291+ /* Name of this domain. Never NULL. */
1292+ const struct ccs_path_info *domainname;
1293+ /* Namespace for this domain. Never NULL. */
1294+ struct ccs_policy_namespace *ns;
1295+ u8 profile; /* Profile number to use. */
1296+ u8 group; /* Group number to use. */
1297+ bool is_deleted; /* Delete flag. */
1298+ bool flags[CCS_MAX_DOMAIN_INFO_FLAGS];
1299+};
1300+
1301+/*
1302+ * Structure for "reset_domain"/"no_reset_domain"/"initialize_domain"/
1303+ * "no_initialize_domain"/"keep_domain"/"no_keep_domain" keyword.
1304+ */
1305+struct ccs_transition_control {
1306+ struct ccs_acl_head head;
1307+ u8 type; /* One of values in "enum ccs_transition_type" */
1308+ bool is_last_name; /* True if the domainname is ccs_last_word(). */
1309+ const struct ccs_path_info *domainname; /* Maybe NULL */
1310+ const struct ccs_path_info *program; /* Maybe NULL */
1311+};
1312+
1313+/* Structure for "aggregator" keyword. */
1314+struct ccs_aggregator {
1315+ struct ccs_acl_head head;
1316+ const struct ccs_path_info *original_name;
1317+ const struct ccs_path_info *aggregated_name;
1318+};
1319+
1320+/* Structure for "deny_autobind" keyword. */
1321+struct ccs_reserved {
1322+ struct ccs_acl_head head;
1323+ struct ccs_number_union port;
1324+};
1325+
1326+/* Structure for policy manager. */
1327+struct ccs_manager {
1328+ struct ccs_acl_head head;
1329+ /* A path to program or a domainname. */
1330+ const struct ccs_path_info *manager;
1331+};
1332+
1333+/* Structure for argv[]. */
1334+struct ccs_argv {
1335+ unsigned long index;
1336+ const struct ccs_path_info *value;
1337+ bool is_not;
1338+};
1339+
1340+/* Structure for envp[]. */
1341+struct ccs_envp {
1342+ const struct ccs_path_info *name;
1343+ const struct ccs_path_info *value;
1344+ bool is_not;
1345+};
1346+
1347+/*
1348+ * Structure for "task auto_execute_handler" and "task denied_execute_handler"
1349+ * directive.
1350+ *
1351+ * If "task auto_execute_handler" directive exists and the current process is
1352+ * not an execute handler, all execve() requests are replaced by execve()
1353+ * requests of a program specified by "task auto_execute_handler" directive.
1354+ * If the current process is an execute handler, "task auto_execute_handler"
1355+ * and "task denied_execute_handler" directives are ignored.
1356+ * The program specified by "task execute_handler" validates execve()
1357+ * parameters and executes the original execve() requests if appropriate.
1358+ *
1359+ * "task denied_execute_handler" directive is used only when execve() request
1360+ * was rejected in enforcing mode (i.e. CONFIG::file::execute={ mode=enforcing
1361+ * }). The program specified by "task denied_execute_handler" does whatever it
1362+ * wants to do (e.g. silently terminate, change firewall settings, redirect the
1363+ * user to honey pot etc.).
1364+ */
1365+struct ccs_handler_acl {
1366+ struct ccs_acl_info head; /* type = CCS_TYPE_*_EXECUTE_HANDLER */
1367+ const struct ccs_path_info *handler; /* Pointer to single pathname. */
1368+};
1369+
1370+/*
1371+ * Structure for "task auto_domain_transition" and
1372+ * "task manual_domain_transition" directive.
1373+ */
1374+struct ccs_task_acl {
1375+ struct ccs_acl_info head; /* type = CCS_TYPE_*_TASK_ACL */
1376+ /* Pointer to domainname. */
1377+ const struct ccs_path_info *domainname;
1378+};
1379+
1380+/*
1381+ * Structure for "file execute", "file read", "file write", "file append",
1382+ * "file unlink", "file getattr", "file rmdir", "file truncate",
1383+ * "file symlink", "file chroot" and "file unmount" directive.
1384+ */
1385+struct ccs_path_acl {
1386+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_ACL */
1387+ struct ccs_name_union name;
1388+};
1389+
1390+/*
1391+ * Structure for "file rename", "file link" and "file pivot_root" directive.
1392+ */
1393+struct ccs_path2_acl {
1394+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH2_ACL */
1395+ struct ccs_name_union name1;
1396+ struct ccs_name_union name2;
1397+};
1398+
1399+/*
1400+ * Structure for "file create", "file mkdir", "file mkfifo", "file mksock",
1401+ * "file ioctl", "file chmod", "file chown" and "file chgrp" directive.
1402+ */
1403+struct ccs_path_number_acl {
1404+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_NUMBER_ACL */
1405+ struct ccs_name_union name;
1406+ struct ccs_number_union number;
1407+};
1408+
1409+/* Structure for "file mkblock" and "file mkchar" directive. */
1410+struct ccs_mkdev_acl {
1411+ struct ccs_acl_info head; /* type = CCS_TYPE_MKDEV_ACL */
1412+ struct ccs_name_union name;
1413+ struct ccs_number_union mode;
1414+ struct ccs_number_union major;
1415+ struct ccs_number_union minor;
1416+};
1417+
1418+/* Structure for "file mount" directive. */
1419+struct ccs_mount_acl {
1420+ struct ccs_acl_info head; /* type = CCS_TYPE_MOUNT_ACL */
1421+ struct ccs_name_union dev_name;
1422+ struct ccs_name_union dir_name;
1423+ struct ccs_name_union fs_type;
1424+ struct ccs_number_union flags;
1425+};
1426+
1427+/* Structure for "misc env" directive in domain policy. */
1428+struct ccs_env_acl {
1429+ struct ccs_acl_info head; /* type = CCS_TYPE_ENV_ACL */
1430+ const struct ccs_path_info *env; /* environment variable */
1431+};
1432+
1433+/* Structure for "capability" directive. */
1434+struct ccs_capability_acl {
1435+ struct ccs_acl_info head; /* type = CCS_TYPE_CAPABILITY_ACL */
1436+ u8 operation; /* One of values in "enum ccs_capability_acl_index". */
1437+};
1438+
1439+/* Structure for "ipc signal" directive. */
1440+struct ccs_signal_acl {
1441+ struct ccs_acl_info head; /* type = CCS_TYPE_SIGNAL_ACL */
1442+ struct ccs_number_union sig;
1443+ /* Pointer to destination pattern. */
1444+ const struct ccs_path_info *domainname;
1445+};
1446+
1447+/* Structure for "network inet" directive. */
1448+struct ccs_inet_acl {
1449+ struct ccs_acl_info head; /* type = CCS_TYPE_INET_ACL */
1450+ u8 protocol;
1451+ struct ccs_ipaddr_union address;
1452+ struct ccs_number_union port;
1453+};
1454+
1455+/* Structure for "network unix" directive. */
1456+struct ccs_unix_acl {
1457+ struct ccs_acl_info head; /* type = CCS_TYPE_UNIX_ACL */
1458+ u8 protocol;
1459+ struct ccs_name_union name;
1460+};
1461+
1462+/* Structure for holding string data. */
1463+struct ccs_name {
1464+ struct ccs_shared_acl_head head;
1465+ int size; /* Memory size allocated for this entry. */
1466+ struct ccs_path_info entry;
1467+};
1468+
1469+/* Structure for holding a line from /proc/ccs/ interface. */
1470+struct ccs_acl_param {
1471+ char *data; /* Unprocessed data. */
1472+ struct list_head *list; /* List to add or remove. */
1473+ struct ccs_policy_namespace *ns; /* Namespace to use. */
1474+ bool is_delete; /* True if it is a delete request. */
1475+ union ccs_acl_union {
1476+ struct ccs_acl_info acl_info;
1477+ struct ccs_handler_acl handler_acl;
1478+ struct ccs_task_acl task_acl;
1479+ struct ccs_path_acl path_acl;
1480+ struct ccs_path2_acl path2_acl;
1481+ struct ccs_path_number_acl path_number_acl;
1482+ struct ccs_mkdev_acl mkdev_acl;
1483+ struct ccs_mount_acl mount_acl;
1484+ struct ccs_env_acl env_acl;
1485+ struct ccs_capability_acl capability_acl;
1486+ struct ccs_signal_acl signal_acl;
1487+ struct ccs_inet_acl inet_acl;
1488+ struct ccs_unix_acl unix_acl;
1489+ /**/
1490+ struct ccs_acl_head acl_head;
1491+ struct ccs_transition_control transition_control;
1492+ struct ccs_aggregator aggregator;
1493+ struct ccs_reserved reserved;
1494+ struct ccs_manager manager;
1495+ struct ccs_path_group path_group;
1496+ struct ccs_number_group number_group;
1497+ struct ccs_address_group address_group;
1498+ } e;
1499+};
1500+
1501+/* Structure for reading/writing policy via /proc/ccs/ interfaces. */
1502+struct ccs_io_buffer {
1503+ /* Exclusive lock for this structure. */
1504+ struct mutex io_sem;
1505+ char __user *read_user_buf;
1506+ size_t read_user_buf_avail;
1507+ struct {
1508+ struct list_head *ns;
1509+ struct list_head *domain;
1510+ struct list_head *group;
1511+ struct list_head *acl;
1512+ size_t avail;
1513+ unsigned int step;
1514+ unsigned int query_index;
1515+ u16 index;
1516+ u16 cond_index;
1517+ u8 acl_group_index;
1518+ u8 cond_step;
1519+ u8 bit;
1520+ u8 w_pos;
1521+ bool eof;
1522+ bool print_this_domain_only;
1523+ bool print_transition_related_only;
1524+ bool print_cond_part;
1525+ const char *w[CCS_MAX_IO_READ_QUEUE];
1526+ } r;
1527+ struct {
1528+ struct ccs_policy_namespace *ns;
1529+ struct ccs_domain_info *domain;
1530+ size_t avail;
1531+ bool is_delete;
1532+ } w;
1533+ /* Buffer for reading. */
1534+ char *read_buf;
1535+ /* Size of read buffer. */
1536+ size_t readbuf_size;
1537+ /* Buffer for writing. */
1538+ char *write_buf;
1539+ /* Size of write buffer. */
1540+ size_t writebuf_size;
1541+ /* Type of interface. */
1542+ enum ccs_proc_interface_index type;
1543+ /* Users counter protected by ccs_io_buffer_list_lock. */
1544+ u8 users;
1545+ /* List for telling GC not to kfree() elements. */
1546+ struct list_head list;
1547+};
1548+
1549+/* Structure for /proc/ccs/profile interface. */
1550+struct ccs_profile {
1551+ const struct ccs_path_info *comment;
1552+ u8 default_config;
1553+ u8 config[CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX];
1554+ unsigned int pref[CCS_MAX_PREF];
1555+};
1556+
1557+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
1558+struct ccs_time {
1559+ u16 year;
1560+ u8 month;
1561+ u8 day;
1562+ u8 hour;
1563+ u8 min;
1564+ u8 sec;
1565+};
1566+
1567+/* Structure for policy namespace. */
1568+struct ccs_policy_namespace {
1569+ /* Profile table. Memory is allocated as needed. */
1570+ struct ccs_profile *profile_ptr[CCS_MAX_PROFILES];
1571+ /* List of "struct ccs_group". */
1572+ struct list_head group_list[CCS_MAX_GROUP];
1573+ /* List of policy. */
1574+ struct list_head policy_list[CCS_MAX_POLICY];
1575+ /* The global ACL referred by "use_group" keyword. */
1576+ struct list_head acl_group[CCS_MAX_ACL_GROUPS];
1577+ /* List for connecting to ccs_namespace_list list. */
1578+ struct list_head namespace_list;
1579+ /* Profile version. Currently only 20100903 is defined. */
1580+ unsigned int profile_version;
1581+ /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
1582+ const char *name;
1583+};
1584+
1585+/* Prototype definition for "struct ccsecurity_operations". */
1586+
1587+void __init ccs_permission_init(void);
1588+void __init ccs_mm_init(void);
1589+
1590+/* Prototype definition for internal use. */
1591+
1592+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1593+ struct ccs_page_dump *dump);
1594+bool ccs_memory_ok(const void *ptr, const unsigned int size);
1595+char *ccs_encode(const char *str);
1596+char *ccs_encode2(const char *str, int str_len);
1597+char *ccs_realpath(const struct path *path);
1598+const char *ccs_get_exe(void);
1599+const struct ccs_path_info *ccs_get_name(const char *name);
1600+int ccs_audit_log(struct ccs_request_info *r);
1601+int ccs_check_acl(struct ccs_request_info *r);
1602+int ccs_init_request_info(struct ccs_request_info *r, const u8 index);
1603+struct ccs_domain_info *ccs_assign_domain(const char *domainname,
1604+ const bool transit);
1605+u8 ccs_get_config(const u8 profile, const u8 index);
1606+void *ccs_commit_ok(void *data, const unsigned int size);
1607+void ccs_del_acl(struct list_head *element);
1608+void ccs_del_condition(struct list_head *element);
1609+void ccs_fill_path_info(struct ccs_path_info *ptr);
1610+void ccs_get_attributes(struct ccs_obj_info *obj);
1611+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
1612+void ccs_transition_failed(const char *domainname);
1613+void ccs_warn_oom(const char *function);
1614+void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...)
1615+ __printf(2, 3);
1616+
1617+/* Variable definition for internal use. */
1618+
1619+extern bool ccs_policy_loaded;
1620+extern const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS];
1621+extern const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX];
1622+extern const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION];
1623+extern const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION];
1624+extern const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION];
1625+extern struct ccs_domain_info ccs_kernel_domain;
1626+extern struct list_head ccs_condition_list;
1627+extern struct list_head ccs_domain_list;
1628+extern struct list_head ccs_name_list[CCS_MAX_HASH];
1629+extern struct list_head ccs_namespace_list;
1630+extern struct mutex ccs_policy_lock;
1631+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1632+extern struct srcu_struct ccs_ss;
1633+#endif
1634+extern unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
1635+extern unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
1636+
1637+/* Inlined functions for internal use. */
1638+
1639+/**
1640+ * ccs_pathcmp - strcmp() for "struct ccs_path_info" structure.
1641+ *
1642+ * @a: Pointer to "struct ccs_path_info".
1643+ * @b: Pointer to "struct ccs_path_info".
1644+ *
1645+ * Returns true if @a != @b, false otherwise.
1646+ */
1647+static inline bool ccs_pathcmp(const struct ccs_path_info *a,
1648+ const struct ccs_path_info *b)
1649+{
1650+ return a->hash != b->hash || strcmp(a->name, b->name);
1651+}
1652+
1653+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1654+
1655+/**
1656+ * ccs_read_lock - Take lock for protecting policy.
1657+ *
1658+ * Returns index number for ccs_read_unlock().
1659+ */
1660+static inline int ccs_read_lock(void)
1661+{
1662+ return srcu_read_lock(&ccs_ss);
1663+}
1664+
1665+/**
1666+ * ccs_read_unlock - Release lock for protecting policy.
1667+ *
1668+ * @idx: Index number returned by ccs_read_lock().
1669+ *
1670+ * Returns nothing.
1671+ */
1672+static inline void ccs_read_unlock(const int idx)
1673+{
1674+ srcu_read_unlock(&ccs_ss, idx);
1675+}
1676+
1677+#else
1678+
1679+int ccs_lock(void);
1680+void ccs_unlock(const int idx);
1681+
1682+/**
1683+ * ccs_read_lock - Take lock for protecting policy.
1684+ *
1685+ * Returns index number for ccs_read_unlock().
1686+ */
1687+static inline int ccs_read_lock(void)
1688+{
1689+ return ccs_lock();
1690+}
1691+
1692+/**
1693+ * ccs_read_unlock - Release lock for protecting policy.
1694+ *
1695+ * @idx: Index number returned by ccs_read_lock().
1696+ *
1697+ * Returns nothing.
1698+ */
1699+static inline void ccs_read_unlock(const int idx)
1700+{
1701+ ccs_unlock(idx);
1702+}
1703+
1704+#endif
1705+
1706+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
1707+
1708+/**
1709+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
1710+ *
1711+ * Returns nothing.
1712+ */
1713+static inline void ccs_tasklist_lock(void)
1714+{
1715+ rcu_read_lock();
1716+}
1717+
1718+/**
1719+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
1720+ *
1721+ * Returns nothing.
1722+ */
1723+static inline void ccs_tasklist_unlock(void)
1724+{
1725+ rcu_read_unlock();
1726+}
1727+
1728+#else
1729+
1730+/**
1731+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
1732+ *
1733+ * Returns nothing.
1734+ */
1735+static inline void ccs_tasklist_lock(void)
1736+{
1737+ read_lock(&tasklist_lock);
1738+}
1739+
1740+/**
1741+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
1742+ *
1743+ * Returns nothing.
1744+ */
1745+static inline void ccs_tasklist_unlock(void)
1746+{
1747+ read_unlock(&tasklist_lock);
1748+}
1749+
1750+#endif
1751+
1752+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1753+
1754+/**
1755+ * ccs_sys_getppid - Copy of getppid().
1756+ *
1757+ * Returns parent process's PID.
1758+ *
1759+ * Alpha does not have getppid() defined. To be able to build this module on
1760+ * Alpha, I have to copy getppid() from kernel/timer.c.
1761+ */
1762+static inline pid_t ccs_sys_getppid(void)
1763+{
1764+ pid_t pid;
1765+ rcu_read_lock();
1766+ pid = task_tgid_vnr(rcu_dereference(current->real_parent));
1767+ rcu_read_unlock();
1768+ return pid;
1769+}
1770+
1771+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1772+
1773+/**
1774+ * ccs_sys_getppid - Copy of getppid().
1775+ *
1776+ * Returns parent process's PID.
1777+ *
1778+ * This function was rewritten to use RCU in 2.6.16.34. However, distributors
1779+ * which use earlier kernels (e.g. 2.6.8/2.6.9) did not backport the bugfix.
1780+ * Therefore, I'm using code for 2.6.16.34 for earlier kernels.
1781+ */
1782+static inline pid_t ccs_sys_getppid(void)
1783+{
1784+ pid_t pid;
1785+ rcu_read_lock();
1786+#if (defined(RHEL_MAJOR) && RHEL_MAJOR == 5) || (defined(AX_MAJOR) && AX_MAJOR == 3)
1787+ pid = rcu_dereference(current->parent)->tgid;
1788+#elif defined(CONFIG_UTRACE)
1789+ /*
1790+ * RHEL 5.0 kernel does not have RHEL_MAJOR/RHEL_MINOR defined.
1791+ * Assume RHEL 5.0 if CONFIG_UTRACE is defined.
1792+ */
1793+ pid = rcu_dereference(current->parent)->tgid;
1794+#else
1795+ pid = rcu_dereference(current->real_parent)->tgid;
1796+#endif
1797+ rcu_read_unlock();
1798+ return pid;
1799+}
1800+
1801+#else
1802+
1803+/**
1804+ * ccs_sys_getppid - Copy of getppid().
1805+ *
1806+ * Returns parent process's PID.
1807+ *
1808+ * I can't use code for 2.6.16.34 for 2.4 kernels because 2.4 kernels does not
1809+ * have RCU. Therefore, I'm using pessimistic lock (i.e. tasklist_lock
1810+ * spinlock).
1811+ */
1812+static inline pid_t ccs_sys_getppid(void)
1813+{
1814+ pid_t pid;
1815+ read_lock(&tasklist_lock);
1816+#ifdef TASK_DEAD
1817+ pid = current->group_leader->real_parent->tgid;
1818+#else
1819+ pid = current->p_opptr->pid;
1820+#endif
1821+ read_unlock(&tasklist_lock);
1822+ return pid;
1823+}
1824+
1825+#endif
1826+
1827+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1828+
1829+/**
1830+ * ccs_sys_getpid - Copy of getpid().
1831+ *
1832+ * Returns current thread's PID.
1833+ *
1834+ * Alpha does not have getpid() defined. To be able to build this module on
1835+ * Alpha, I have to copy getpid() from kernel/timer.c.
1836+ */
1837+static inline pid_t ccs_sys_getpid(void)
1838+{
1839+ return task_tgid_vnr(current);
1840+}
1841+
1842+#else
1843+
1844+/**
1845+ * ccs_sys_getpid - Copy of getpid().
1846+ *
1847+ * Returns current thread's PID.
1848+ */
1849+static inline pid_t ccs_sys_getpid(void)
1850+{
1851+ return current->tgid;
1852+}
1853+
1854+#endif
1855+
1856+/**
1857+ * ccs_get_mode - Get mode for specified functionality.
1858+ *
1859+ * @profile: Profile number.
1860+ * @index: Functionality number.
1861+ *
1862+ * Returns mode.
1863+ */
1864+static inline u8 ccs_get_mode(const u8 profile, const u8 index)
1865+{
1866+ return ccs_get_config(profile, index) & (CCS_CONFIG_MAX_MODE - 1);
1867+}
1868+
1869+#if defined(CONFIG_SLOB)
1870+
1871+/**
1872+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
1873+ *
1874+ * @size: Size to be rounded up.
1875+ *
1876+ * Returns @size.
1877+ *
1878+ * Since SLOB does not round up, this function simply returns @size.
1879+ */
1880+static inline int ccs_round2(size_t size)
1881+{
1882+ return size;
1883+}
1884+
1885+#else
1886+
1887+/**
1888+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
1889+ *
1890+ * @size: Size to be rounded up.
1891+ *
1892+ * Returns rounded size.
1893+ *
1894+ * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
1895+ * (e.g.) 128 bytes.
1896+ */
1897+static inline int ccs_round2(size_t size)
1898+{
1899+#if PAGE_SIZE == 4096
1900+ size_t bsize = 32;
1901+#else
1902+ size_t bsize = 64;
1903+#endif
1904+ if (!size)
1905+ return 0;
1906+ while (size > bsize)
1907+ bsize <<= 1;
1908+ return bsize;
1909+}
1910+
1911+#endif
1912+
1913+/**
1914+ * ccs_put_condition - Drop reference on "struct ccs_condition".
1915+ *
1916+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
1917+ *
1918+ * Returns nothing.
1919+ */
1920+static inline void ccs_put_condition(struct ccs_condition *cond)
1921+{
1922+ if (cond)
1923+ atomic_dec(&cond->head.users);
1924+}
1925+
1926+/**
1927+ * ccs_put_group - Drop reference on "struct ccs_group".
1928+ *
1929+ * @group: Pointer to "struct ccs_group". Maybe NULL.
1930+ *
1931+ * Returns nothing.
1932+ */
1933+static inline void ccs_put_group(struct ccs_group *group)
1934+{
1935+ if (group)
1936+ atomic_dec(&group->head.users);
1937+}
1938+
1939+/**
1940+ * ccs_put_name - Drop reference on "struct ccs_name".
1941+ *
1942+ * @name: Pointer to "struct ccs_path_info". Maybe NULL.
1943+ *
1944+ * Returns nothing.
1945+ */
1946+static inline void ccs_put_name(const struct ccs_path_info *name)
1947+{
1948+ if (name)
1949+ atomic_dec(&container_of(name, struct ccs_name, entry)->
1950+ head.users);
1951+}
1952+
1953+/* For importing variables and functions. */
1954+extern struct ccsecurity_exports ccsecurity_exports;
1955+
1956+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
1957+
1958+/*
1959+ * Structure for holding "struct ccs_domain_info *" and "struct ccs_execve *"
1960+ * and "u32 ccs_flags" for each "struct task_struct".
1961+ *
1962+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
1963+ * are maintained outside that "struct task_struct". Therefore, ccs_security
1964+ * != task_struct . This keeps KABI for distributor's prebuilt kernels but
1965+ * entails slow access.
1966+ *
1967+ * Memory for this structure is allocated when current thread tries to access
1968+ * it. Therefore, if memory allocation failed, current thread will be killed by
1969+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
1970+ */
1971+struct ccs_security {
1972+ struct list_head list;
1973+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1974+ const struct task_struct *task;
1975+#else
1976+ struct pid *pid; /* Maybe NULL. */
1977+ const struct cred *cred; /* Maybe NULL. */
1978+#endif
1979+ struct ccs_domain_info *ccs_domain_info;
1980+ u32 ccs_flags;
1981+ struct ccs_execve *ee; /* Maybe NULL. */
1982+ struct rcu_head rcu;
1983+};
1984+
1985+void __init ccs_main_init(void);
1986+bool ccs_used_by_cred(const struct ccs_domain_info *domain);
1987+int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve **eep);
1988+void ccs_finish_execve(int retval, struct ccs_execve *ee);
1989+void ccs_load_policy(const char *filename);
1990+#ifndef CONFIG_AKARI_TRACE_EXECVE_COUNT
1991+#define ccs_audit_alloc_execve(ee) do { } while (0)
1992+#define ccs_audit_free_execve(ee, is_current) do { } while (0)
1993+#else
1994+void ccs_audit_alloc_execve(const struct ccs_execve * const ee);
1995+void ccs_audit_free_execve(const struct ccs_execve * const ee,
1996+ const bool is_current);
1997+#endif
1998+
1999+#define CCS_TASK_SECURITY_HASH_BITS 12
2000+#define CCS_MAX_TASK_SECURITY_HASH (1u << CCS_TASK_SECURITY_HASH_BITS)
2001+extern struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
2002+
2003+struct ccs_security *ccs_find_task_security(const struct task_struct *task);
2004+
2005+/**
2006+ * ccs_current_security - Get "struct ccs_security" for current thread.
2007+ *
2008+ * Returns pointer to "struct ccs_security" for current thread.
2009+ */
2010+static inline struct ccs_security *ccs_current_security(void)
2011+{
2012+ return ccs_find_task_security(current);
2013+}
2014+
2015+/**
2016+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
2017+ *
2018+ * @task: Pointer to "struct task_struct".
2019+ *
2020+ * Returns pointer to "struct ccs_security" for specified thread.
2021+ */
2022+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
2023+{
2024+ struct ccs_domain_info *domain;
2025+ rcu_read_lock();
2026+ domain = ccs_find_task_security(task)->ccs_domain_info;
2027+ rcu_read_unlock();
2028+ return domain;
2029+}
2030+
2031+/**
2032+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
2033+ *
2034+ * Returns pointer to "struct ccs_domain_info" for current thread.
2035+ */
2036+static inline struct ccs_domain_info *ccs_current_domain(void)
2037+{
2038+ return ccs_find_task_security(current)->ccs_domain_info;
2039+}
2040+
2041+/**
2042+ * ccs_task_flags - Get flags for specified thread.
2043+ *
2044+ * @task: Pointer to "struct task_struct".
2045+ *
2046+ * Returns flags for specified thread.
2047+ */
2048+static inline u32 ccs_task_flags(struct task_struct *task)
2049+{
2050+ u32 ccs_flags;
2051+ rcu_read_lock();
2052+ ccs_flags = ccs_find_task_security(task)->ccs_flags;
2053+ rcu_read_unlock();
2054+ return ccs_flags;
2055+}
2056+
2057+/**
2058+ * ccs_current_flags - Get flags for current thread.
2059+ *
2060+ * Returns flags for current thread.
2061+ */
2062+static inline u32 ccs_current_flags(void)
2063+{
2064+ return ccs_find_task_security(current)->ccs_flags;
2065+}
2066+
2067+#else
2068+
2069+/*
2070+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
2071+ * are maintained inside that "struct task_struct". Therefore, ccs_security ==
2072+ * task_struct . This allows fast access but breaks KABI checks for
2073+ * distributor's prebuilt kernels due to changes in "struct task_struct".
2074+ */
2075+#define ccs_security task_struct
2076+
2077+/**
2078+ * ccs_find_task_security - Find "struct ccs_security" for given task.
2079+ *
2080+ * @task: Pointer to "struct task_struct".
2081+ *
2082+ * Returns pointer to "struct ccs_security".
2083+ */
2084+static inline struct ccs_security *ccs_find_task_security(struct task_struct *
2085+ task)
2086+{
2087+ return task;
2088+}
2089+
2090+/**
2091+ * ccs_current_security - Get "struct ccs_security" for current thread.
2092+ *
2093+ * Returns pointer to "struct ccs_security" for current thread.
2094+ */
2095+static inline struct ccs_security *ccs_current_security(void)
2096+{
2097+ return ccs_find_task_security(current);
2098+}
2099+
2100+/**
2101+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
2102+ *
2103+ * @task: Pointer to "struct task_struct".
2104+ *
2105+ * Returns pointer to "struct ccs_security" for specified thread.
2106+ */
2107+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
2108+{
2109+ struct ccs_domain_info *domain = task->ccs_domain_info;
2110+ return domain ? domain : &ccs_kernel_domain;
2111+}
2112+
2113+/**
2114+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
2115+ *
2116+ * Returns pointer to "struct ccs_domain_info" for current thread.
2117+ *
2118+ * If current thread does not belong to a domain (which is true for initial
2119+ * init_task in order to hide ccs_kernel_domain from this module),
2120+ * current thread enters into ccs_kernel_domain.
2121+ */
2122+static inline struct ccs_domain_info *ccs_current_domain(void)
2123+{
2124+ struct task_struct *task = current;
2125+ if (!task->ccs_domain_info)
2126+ task->ccs_domain_info = &ccs_kernel_domain;
2127+ return task->ccs_domain_info;
2128+}
2129+
2130+/**
2131+ * ccs_task_flags - Get flags for specified thread.
2132+ *
2133+ * @task: Pointer to "struct task_struct".
2134+ *
2135+ * Returns flags for specified thread.
2136+ */
2137+static inline u32 ccs_task_flags(struct task_struct *task)
2138+{
2139+ return ccs_find_task_security(task)->ccs_flags;
2140+}
2141+
2142+/**
2143+ * ccs_current_flags - Get flags for current thread.
2144+ *
2145+ * Returns flags for current thread.
2146+ */
2147+static inline u32 ccs_current_flags(void)
2148+{
2149+ return ccs_find_task_security(current)->ccs_flags;
2150+}
2151+
2152+#endif
2153+
2154+/**
2155+ * ccs_current_namespace - Get "struct ccs_policy_namespace" for current thread.
2156+ *
2157+ * Returns pointer to "struct ccs_policy_namespace" for current thread.
2158+ */
2159+static inline struct ccs_policy_namespace *ccs_current_namespace(void)
2160+{
2161+ return ccs_current_domain()->ns;
2162+}
2163+
2164+#endif
--- tags/patches/1.0.33/ccsecurity.h (nonexistent)
+++ tags/patches/1.0.33/ccsecurity.h (revision 502)
@@ -0,0 +1,919 @@
1+/*
2+ * include/linux/ccsecurity.h
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
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+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
33+int search_binary_handler(struct linux_binprm *bprm);
34+#else
35+int search_binary_handler(struct linux_binprm *bprm, struct pt_regs *regs);
36+#endif
37+
38+#ifdef CONFIG_CCSECURITY
39+
40+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
41+/* Obtain prototype of __d_path(). */
42+#include <linux/dcache.h>
43+#endif
44+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
45+/* Obtain definition of kuid_t and kgid_t. */
46+#include <linux/uidgid.h>
47+#endif
48+
49+/* For exporting variables and functions. */
50+struct ccsecurity_exports {
51+ void (*load_policy) (const char *filename);
52+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
53+ char * (*d_absolute_path) (const struct path *, char *, int);
54+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
55+ typeof(__d_path) (*__d_path);
56+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
57+ spinlock_t *vfsmount_lock;
58+#endif
59+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
60+ struct task_struct * (*find_task_by_vpid) (pid_t nr);
61+ struct task_struct * (*find_task_by_pid_ns) (pid_t nr,
62+ struct pid_namespace *ns);
63+#endif
64+};
65+
66+/* For doing access control. */
67+struct ccsecurity_operations {
68+ void (*check_profile) (void);
69+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
70+ int (*chroot_permission) (struct path *path);
71+ int (*pivot_root_permission) (struct path *old_path,
72+ struct path *new_path);
73+ int (*mount_permission) (const char *dev_name, struct path *path,
74+ const char *type, unsigned long flags,
75+ void *data_page);
76+#else
77+ int (*chroot_permission) (struct nameidata *nd);
78+ int (*pivot_root_permission) (struct nameidata *old_nd,
79+ struct nameidata *new_nd);
80+ int (*mount_permission) (const char *dev_name, struct nameidata *nd,
81+ const char *type, unsigned long flags,
82+ void *data_page);
83+#endif
84+ int (*umount_permission) (struct vfsmount *mnt, int flags);
85+ _Bool (*lport_reserved) (const u16 port);
86+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
87+ void (*save_open_mode) (int mode);
88+ void (*clear_open_mode) (void);
89+ int (*open_permission) (struct dentry *dentry, struct vfsmount *mnt,
90+ const int flag);
91+#else
92+ int (*open_permission) (struct file *file);
93+#endif
94+ int (*ptrace_permission) (long request, long pid);
95+ int (*ioctl_permission) (struct file *filp, unsigned int cmd,
96+ unsigned long arg);
97+ int (*parse_table) (int __user *name, int nlen, void __user *oldval,
98+ void __user *newval, struct ctl_table *table);
99+ _Bool (*capable) (const u8 operation);
100+ int (*mknod_permission) (struct dentry *dentry, struct vfsmount *mnt,
101+ unsigned int mode, unsigned int dev);
102+ int (*mkdir_permission) (struct dentry *dentry, struct vfsmount *mnt,
103+ unsigned int mode);
104+ int (*rmdir_permission) (struct dentry *dentry, struct vfsmount *mnt);
105+ int (*unlink_permission) (struct dentry *dentry, struct vfsmount *mnt);
106+ int (*symlink_permission) (struct dentry *dentry, struct vfsmount *mnt,
107+ const char *from);
108+ int (*truncate_permission) (struct dentry *dentry,
109+ struct vfsmount *mnt);
110+ int (*rename_permission) (struct dentry *old_dentry,
111+ struct dentry *new_dentry,
112+ struct vfsmount *mnt);
113+ int (*link_permission) (struct dentry *old_dentry,
114+ struct dentry *new_dentry,
115+ struct vfsmount *mnt);
116+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
117+ int (*open_exec_permission) (struct dentry *dentry,
118+ struct vfsmount *mnt);
119+ int (*uselib_permission) (struct dentry *dentry, struct vfsmount *mnt);
120+#endif
121+ int (*fcntl_permission) (struct file *file, unsigned int cmd,
122+ unsigned long arg);
123+ int (*kill_permission) (pid_t pid, int sig);
124+ int (*tgkill_permission) (pid_t tgid, pid_t pid, int sig);
125+ int (*tkill_permission) (pid_t pid, int sig);
126+ int (*socket_create_permission) (int family, int type, int protocol);
127+ int (*socket_listen_permission) (struct socket *sock);
128+ int (*socket_connect_permission) (struct socket *sock,
129+ struct sockaddr *addr, int addr_len);
130+ int (*socket_bind_permission) (struct socket *sock,
131+ struct sockaddr *addr, int addr_len);
132+ int (*socket_post_accept_permission) (struct socket *sock,
133+ struct socket *newsock);
134+ int (*socket_sendmsg_permission) (struct socket *sock,
135+ struct msghdr *msg, int size);
136+ int (*socket_post_recvmsg_permission) (struct sock *sk,
137+ struct sk_buff *skb, int flags);
138+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
139+ int (*chown_permission) (struct dentry *dentry, struct vfsmount *mnt,
140+ kuid_t user, kgid_t group);
141+#else
142+ int (*chown_permission) (struct dentry *dentry, struct vfsmount *mnt,
143+ uid_t user, gid_t group);
144+#endif
145+ int (*chmod_permission) (struct dentry *dentry, struct vfsmount *mnt,
146+ mode_t mode);
147+ int (*getattr_permission) (struct vfsmount *mnt,
148+ struct dentry *dentry);
149+ int (*sigqueue_permission) (pid_t pid, int sig);
150+ int (*tgsigqueue_permission) (pid_t tgid, pid_t pid, int sig);
151+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
152+ int (*search_binary_handler) (struct linux_binprm *bprm);
153+#else
154+ int (*search_binary_handler) (struct linux_binprm *bprm,
155+ struct pt_regs *regs);
156+#endif
157+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
158+ int (*alloc_task_security) (const struct task_struct *task);
159+ void (*free_task_security) (const struct task_struct *task);
160+#endif
161+ _Bool disabled;
162+};
163+
164+extern struct ccsecurity_operations ccsecurity_ops;
165+
166+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
167+
168+static inline int ccs_chroot_permission(struct path *path)
169+{
170+ int (*func) (struct path *) = ccsecurity_ops.chroot_permission;
171+ return func ? func(path) : 0;
172+}
173+
174+static inline int ccs_pivot_root_permission(struct path *old_path,
175+ struct path *new_path)
176+{
177+ int (*func) (struct path *, struct path *)
178+ = ccsecurity_ops.pivot_root_permission;
179+ return func ? func(old_path, new_path) : 0;
180+}
181+
182+static inline int ccs_mount_permission(const char *dev_name, struct path *path,
183+ const char *type, unsigned long flags,
184+ void *data_page)
185+{
186+ int (*func) (const char *, struct path *, const char *, unsigned long,
187+ void *) = ccsecurity_ops.mount_permission;
188+ return func ? func(dev_name, path, type, flags, data_page) : 0;
189+}
190+
191+#else
192+
193+static inline int ccs_chroot_permission(struct nameidata *nd)
194+{
195+ int (*func) (struct nameidata *) = ccsecurity_ops.chroot_permission;
196+ return func ? func(nd) : 0;
197+}
198+
199+static inline int ccs_pivot_root_permission(struct nameidata *old_nd,
200+ struct nameidata *new_nd)
201+{
202+ int (*func) (struct nameidata *, struct nameidata *)
203+ = ccsecurity_ops.pivot_root_permission;
204+ return func ? func(old_nd, new_nd) : 0;
205+}
206+
207+static inline int ccs_mount_permission(const char *dev_name,
208+ struct nameidata *nd, const char *type,
209+ unsigned long flags, void *data_page)
210+{
211+ int (*func) (const char *, struct nameidata *, const char *,
212+ unsigned long, void *) = ccsecurity_ops.mount_permission;
213+ return func ? func(dev_name, nd, type, flags, data_page) : 0;
214+}
215+
216+#endif
217+
218+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
219+{
220+ int (*func) (struct vfsmount *, int)
221+ = ccsecurity_ops.umount_permission;
222+ return func ? func(mnt, flags) : 0;
223+}
224+
225+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
226+
227+static inline void ccs_save_open_mode(int mode)
228+{
229+ void (*func) (int) = ccsecurity_ops.save_open_mode;
230+ if (func)
231+ func(mode);
232+}
233+
234+static inline void ccs_clear_open_mode(void)
235+{
236+ void (*func) (void) = ccsecurity_ops.clear_open_mode;
237+ if (func)
238+ func();
239+}
240+
241+static inline int ccs_open_permission(struct dentry *dentry,
242+ struct vfsmount *mnt, const int flag)
243+{
244+ int (*func) (struct dentry *, struct vfsmount *, const int)
245+ = ccsecurity_ops.open_permission;
246+ return func ? func(dentry, mnt, flag) : 0;
247+}
248+
249+#else
250+
251+static inline int ccs_open_permission(struct file *filp)
252+{
253+ int (*func) (struct file *) = ccsecurity_ops.open_permission;
254+ return func ? func(filp) : 0;
255+}
256+
257+#endif
258+
259+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
260+ unsigned long arg)
261+{
262+ int (*func) (struct file *, unsigned int, unsigned long)
263+ = ccsecurity_ops.fcntl_permission;
264+ return func ? func(file, cmd, arg) : 0;
265+}
266+
267+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
268+ unsigned long arg)
269+{
270+ int (*func) (struct file *, unsigned int, unsigned long)
271+ = ccsecurity_ops.ioctl_permission;
272+ return func ? func(filp, cmd, arg) : 0;
273+}
274+
275+static inline int ccs_parse_table(int __user *name, int nlen,
276+ void __user *oldval, void __user *newval,
277+ struct ctl_table *table)
278+{
279+ int (*func) (int __user *, int, void __user *, void __user *,
280+ struct ctl_table *) = ccsecurity_ops.parse_table;
281+ return func ? func(name, nlen, oldval, newval, table) : 0;
282+}
283+
284+static inline int ccs_mknod_permission(struct dentry *dentry,
285+ struct vfsmount *mnt, unsigned int mode,
286+ unsigned int dev)
287+{
288+ int (*func) (struct dentry *, struct vfsmount *, unsigned int,
289+ unsigned int) = ccsecurity_ops.mknod_permission;
290+ return func ? func(dentry, mnt, mode, dev) : 0;
291+}
292+
293+static inline int ccs_mkdir_permission(struct dentry *dentry,
294+ struct vfsmount *mnt, unsigned int mode)
295+{
296+ int (*func) (struct dentry *, struct vfsmount *, unsigned int)
297+ = ccsecurity_ops.mkdir_permission;
298+ return func ? func(dentry, mnt, mode) : 0;
299+}
300+
301+static inline int ccs_rmdir_permission(struct dentry *dentry,
302+ struct vfsmount *mnt)
303+{
304+ int (*func) (struct dentry *, struct vfsmount *)
305+ = ccsecurity_ops.rmdir_permission;
306+ return func ? func(dentry, mnt) : 0;
307+}
308+
309+static inline int ccs_unlink_permission(struct dentry *dentry,
310+ struct vfsmount *mnt)
311+{
312+ int (*func) (struct dentry *, struct vfsmount *)
313+ = ccsecurity_ops.unlink_permission;
314+ return func ? func(dentry, mnt) : 0;
315+}
316+
317+static inline int ccs_symlink_permission(struct dentry *dentry,
318+ struct vfsmount *mnt,
319+ const char *from)
320+{
321+ int (*func) (struct dentry *, struct vfsmount *, const char *)
322+ = ccsecurity_ops.symlink_permission;
323+ return func ? func(dentry, mnt, from) : 0;
324+}
325+
326+static inline int ccs_truncate_permission(struct dentry *dentry,
327+ struct vfsmount *mnt)
328+{
329+ int (*func) (struct dentry *, struct vfsmount *)
330+ = ccsecurity_ops.truncate_permission;
331+ return func ? func(dentry, mnt) : 0;
332+}
333+
334+static inline int ccs_rename_permission(struct dentry *old_dentry,
335+ struct dentry *new_dentry,
336+ struct vfsmount *mnt)
337+{
338+ int (*func) (struct dentry *, struct dentry *, struct vfsmount *)
339+ = ccsecurity_ops.rename_permission;
340+ return func ? func(old_dentry, new_dentry, mnt) : 0;
341+}
342+
343+static inline int ccs_link_permission(struct dentry *old_dentry,
344+ struct dentry *new_dentry,
345+ struct vfsmount *mnt)
346+{
347+ int (*func) (struct dentry *, struct dentry *, struct vfsmount *)
348+ = ccsecurity_ops.link_permission;
349+ return func ? func(old_dentry, new_dentry, mnt) : 0;
350+}
351+
352+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
353+
354+static inline int ccs_open_exec_permission(struct dentry *dentry,
355+ struct vfsmount *mnt)
356+{
357+ int (*func) (struct dentry *, struct vfsmount *)
358+ = ccsecurity_ops.open_exec_permission;
359+ return func ? func(dentry, mnt) : 0;
360+}
361+
362+static inline int ccs_uselib_permission(struct dentry *dentry,
363+ struct vfsmount *mnt)
364+{
365+ int (*func) (struct dentry *, struct vfsmount *)
366+ = ccsecurity_ops.uselib_permission;
367+ return func ? func(dentry, mnt) : 0;
368+}
369+
370+#endif
371+
372+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
373+
374+static inline int ccs_chown_permission(struct dentry *dentry,
375+ struct vfsmount *mnt, kuid_t user,
376+ kgid_t group)
377+{
378+ int (*func) (struct dentry *, struct vfsmount *, kuid_t, kgid_t)
379+ = ccsecurity_ops.chown_permission;
380+ return func ? func(dentry, mnt, user, group) : 0;
381+}
382+
383+#else
384+
385+static inline int ccs_chown_permission(struct dentry *dentry,
386+ struct vfsmount *mnt, uid_t user,
387+ gid_t group)
388+{
389+ int (*func) (struct dentry *, struct vfsmount *, uid_t, gid_t)
390+ = ccsecurity_ops.chown_permission;
391+ return func ? func(dentry, mnt, user, group) : 0;
392+}
393+
394+#endif
395+
396+static inline int ccs_chmod_permission(struct dentry *dentry,
397+ struct vfsmount *mnt, mode_t mode)
398+{
399+ int (*func) (struct dentry *, struct vfsmount *, mode_t)
400+ = ccsecurity_ops.chmod_permission;
401+ return func ? func(dentry, mnt, mode) : 0;
402+}
403+
404+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
405+
406+static inline int ccs_search_binary_handler(struct linux_binprm *bprm)
407+{
408+ return ccsecurity_ops.search_binary_handler(bprm);
409+}
410+
411+#else
412+
413+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
414+ struct pt_regs *regs)
415+{
416+ return ccsecurity_ops.search_binary_handler(bprm, regs);
417+}
418+
419+#endif
420+
421+#else
422+
423+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
424+
425+static inline int ccs_chroot_permission(struct path *path)
426+{
427+ return 0;
428+}
429+
430+static inline int ccs_pivot_root_permission(struct path *old_path,
431+ struct path *new_path)
432+{
433+ return 0;
434+}
435+
436+static inline int ccs_mount_permission(const char *dev_name, struct path *path,
437+ const char *type, unsigned long flags,
438+ void *data_page)
439+{
440+ return 0;
441+}
442+
443+#else
444+
445+static inline int ccs_chroot_permission(struct nameidata *nd)
446+{
447+ return 0;
448+}
449+
450+static inline int ccs_pivot_root_permission(struct nameidata *old_nd,
451+ struct nameidata *new_nd)
452+{
453+ return 0;
454+}
455+
456+static inline int ccs_mount_permission(const char *dev_name,
457+ struct nameidata *nd, const char *type,
458+ unsigned long flags, void *data_page)
459+{
460+ return 0;
461+}
462+
463+#endif
464+
465+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
466+{
467+ return 0;
468+}
469+
470+static inline void ccs_save_open_mode(int mode)
471+{
472+}
473+
474+static inline void ccs_clear_open_mode(void)
475+{
476+}
477+
478+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
479+
480+static inline int ccs_open_permission(struct dentry *dentry,
481+ struct vfsmount *mnt, const int flag)
482+{
483+ return 0;
484+}
485+
486+#else
487+
488+static inline int ccs_open_permission(struct file *filp)
489+{
490+ return 0;
491+}
492+
493+#endif
494+
495+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
496+ unsigned long arg)
497+{
498+ return 0;
499+}
500+
501+static inline int ccs_parse_table(int __user *name, int nlen,
502+ void __user *oldval, void __user *newval,
503+ struct ctl_table *table)
504+{
505+ return 0;
506+}
507+
508+static inline int ccs_mknod_permission(struct dentry *dentry,
509+ struct vfsmount *mnt, unsigned int mode,
510+ unsigned int dev)
511+{
512+ return 0;
513+}
514+
515+static inline int ccs_mkdir_permission(struct dentry *dentry,
516+ struct vfsmount *mnt, unsigned int mode)
517+{
518+ return 0;
519+}
520+
521+static inline int ccs_rmdir_permission(struct dentry *dentry,
522+ struct vfsmount *mnt)
523+{
524+ return 0;
525+}
526+
527+static inline int ccs_unlink_permission(struct dentry *dentry,
528+ struct vfsmount *mnt)
529+{
530+ return 0;
531+}
532+
533+static inline int ccs_symlink_permission(struct dentry *dentry,
534+ struct vfsmount *mnt,
535+ const char *from)
536+{
537+ return 0;
538+}
539+
540+static inline int ccs_truncate_permission(struct dentry *dentry,
541+ struct vfsmount *mnt)
542+{
543+ return 0;
544+}
545+
546+static inline int ccs_rename_permission(struct dentry *old_dentry,
547+ struct dentry *new_dentry,
548+ struct vfsmount *mnt)
549+{
550+ return 0;
551+}
552+
553+static inline int ccs_link_permission(struct dentry *old_dentry,
554+ struct dentry *new_dentry,
555+ struct vfsmount *mnt)
556+{
557+ return 0;
558+}
559+
560+static inline int ccs_open_exec_permission(struct dentry *dentry,
561+ struct vfsmount *mnt)
562+{
563+ return 0;
564+}
565+
566+static inline int ccs_uselib_permission(struct dentry *dentry,
567+ struct vfsmount *mnt)
568+{
569+ return 0;
570+}
571+
572+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
573+ unsigned long arg)
574+{
575+ return 0;
576+}
577+
578+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
579+
580+static inline int ccs_chown_permission(struct dentry *dentry,
581+ struct vfsmount *mnt, kuid_t user,
582+ kgid_t group)
583+{
584+ return 0;
585+}
586+
587+#else
588+
589+static inline int ccs_chown_permission(struct dentry *dentry,
590+ struct vfsmount *mnt, uid_t user,
591+ gid_t group)
592+{
593+ return 0;
594+}
595+
596+#endif
597+
598+static inline int ccs_chmod_permission(struct dentry *dentry,
599+ struct vfsmount *mnt, mode_t mode)
600+{
601+ return 0;
602+}
603+
604+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
605+
606+static inline int ccs_search_binary_handler(struct linux_binprm *bprm)
607+{
608+ return search_binary_handler(bprm);
609+}
610+
611+#else
612+
613+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
614+ struct pt_regs *regs)
615+{
616+ return search_binary_handler(bprm, regs);
617+}
618+
619+#endif
620+
621+#endif
622+
623+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
624+
625+static inline int ccs_alloc_task_security(const struct task_struct *task)
626+{
627+ int (*func) (const struct task_struct *)
628+ = ccsecurity_ops.alloc_task_security;
629+ return func ? func(task) : 0;
630+}
631+
632+static inline void ccs_free_task_security(const struct task_struct *task)
633+{
634+ void (*func) (const struct task_struct *)
635+ = ccsecurity_ops.free_task_security;
636+ if (func)
637+ func(task);
638+}
639+
640+#else
641+
642+static inline int ccs_alloc_task_security(const struct task_struct *task)
643+{
644+ return 0;
645+}
646+
647+static inline void ccs_free_task_security(const struct task_struct *task)
648+{
649+}
650+
651+#endif
652+
653+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
654+
655+static inline int ccs_getattr_permission(struct vfsmount *mnt,
656+ struct dentry *dentry)
657+{
658+ int (*func) (struct vfsmount *, struct dentry *)
659+ = ccsecurity_ops.getattr_permission;
660+ return func ? func(mnt, dentry) : 0;
661+}
662+
663+#else
664+
665+static inline int ccs_getattr_permission(struct vfsmount *mnt,
666+ struct dentry *dentry)
667+{
668+ return 0;
669+}
670+
671+#endif
672+
673+#ifdef CONFIG_CCSECURITY_NETWORK
674+
675+static inline int ccs_socket_listen_permission(struct socket *sock)
676+{
677+ int (*func) (struct socket *)
678+ = ccsecurity_ops.socket_listen_permission;
679+ return func ? func(sock) : 0;
680+}
681+
682+static inline int ccs_socket_connect_permission(struct socket *sock,
683+ struct sockaddr *addr,
684+ int addr_len)
685+{
686+ int (*func) (struct socket *, struct sockaddr *, int)
687+ = ccsecurity_ops.socket_connect_permission;
688+ return func ? func(sock, addr, addr_len) : 0;
689+}
690+
691+static inline int ccs_socket_bind_permission(struct socket *sock,
692+ struct sockaddr *addr,
693+ int addr_len)
694+{
695+ int (*func) (struct socket *, struct sockaddr *, int)
696+ = ccsecurity_ops.socket_bind_permission;
697+ return func ? func(sock, addr, addr_len) : 0;
698+}
699+
700+static inline int ccs_socket_post_accept_permission(struct socket *sock,
701+ struct socket *newsock)
702+{
703+ int (*func) (struct socket *, struct socket *)
704+ = ccsecurity_ops.socket_post_accept_permission;
705+ return func ? func(sock, newsock) : 0;
706+}
707+
708+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
709+ struct msghdr *msg,
710+ int size)
711+{
712+ int (*func) (struct socket *, struct msghdr *, int)
713+ = ccsecurity_ops.socket_sendmsg_permission;
714+ return func ? func(sock, msg, size) : 0;
715+}
716+
717+#else
718+
719+static inline int ccs_socket_listen_permission(struct socket *sock)
720+{
721+ return 0;
722+}
723+
724+static inline int ccs_socket_connect_permission(struct socket *sock,
725+ struct sockaddr *addr,
726+ int addr_len)
727+{
728+ return 0;
729+}
730+
731+static inline int ccs_socket_bind_permission(struct socket *sock,
732+ struct sockaddr *addr,
733+ int addr_len)
734+{
735+ return 0;
736+}
737+
738+static inline int ccs_socket_post_accept_permission(struct socket *sock,
739+ struct socket *newsock)
740+{
741+ return 0;
742+}
743+
744+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
745+ struct msghdr *msg,
746+ int size)
747+{
748+ return 0;
749+}
750+
751+#endif
752+
753+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
754+
755+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
756+ struct sk_buff *skb,
757+ int flags)
758+{
759+ int (*func) (struct sock *, struct sk_buff *, int)
760+ = ccsecurity_ops.socket_post_recvmsg_permission;
761+ return func ? func(sk, skb, flags) : 0;
762+}
763+
764+#else
765+
766+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
767+ struct sk_buff *skb,
768+ int flags)
769+{
770+ return 0;
771+}
772+
773+#endif
774+
775+#ifdef CONFIG_CCSECURITY_PORTRESERVE
776+
777+static inline _Bool ccs_lport_reserved(const u16 port)
778+{
779+ _Bool (*func) (const u16) = ccsecurity_ops.lport_reserved;
780+ return func ? func(port) : 0;
781+}
782+
783+#else
784+
785+static inline _Bool ccs_lport_reserved(const u16 port)
786+{
787+ return 0;
788+}
789+
790+#endif
791+
792+#ifdef CONFIG_CCSECURITY_CAPABILITY
793+
794+static inline _Bool ccs_capable(const u8 operation)
795+{
796+ _Bool (*func) (const u8) = ccsecurity_ops.capable;
797+ return func ? func(operation) : 1;
798+}
799+
800+static inline int ccs_socket_create_permission(int family, int type,
801+ int protocol)
802+{
803+ int (*func) (int, int, int) = ccsecurity_ops.socket_create_permission;
804+ return func ? func(family, type, protocol) : 0;
805+}
806+
807+static inline int ccs_ptrace_permission(long request, long pid)
808+{
809+ int (*func) (long, long) = ccsecurity_ops.ptrace_permission;
810+ return func ? func(request, pid) : 0;
811+}
812+
813+#else
814+
815+static inline _Bool ccs_capable(const u8 operation)
816+{
817+ return 1;
818+}
819+
820+static inline int ccs_socket_create_permission(int family, int type,
821+ int protocol)
822+{
823+ return 0;
824+}
825+
826+static inline int ccs_ptrace_permission(long request, long pid)
827+{
828+ return 0;
829+}
830+
831+#endif
832+
833+#ifdef CONFIG_CCSECURITY_IPC
834+
835+static inline int ccs_kill_permission(pid_t pid, int sig)
836+{
837+ int (*func) (pid_t, int) = ccsecurity_ops.kill_permission;
838+ return func ? func(pid, sig) : 0;
839+}
840+
841+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
842+{
843+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgkill_permission;
844+ return func ? func(tgid, pid, sig) : 0;
845+}
846+
847+static inline int ccs_tkill_permission(pid_t pid, int sig)
848+{
849+ int (*func) (pid_t, int) = ccsecurity_ops.tkill_permission;
850+ return func ? func(pid, sig) : 0;
851+}
852+
853+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
854+{
855+ int (*func) (pid_t, int) = ccsecurity_ops.sigqueue_permission;
856+ return func ? func(pid, sig) : 0;
857+}
858+
859+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
860+{
861+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgsigqueue_permission;
862+ return func ? func(tgid, pid, sig) : 0;
863+}
864+
865+#else
866+
867+static inline int ccs_kill_permission(pid_t pid, int sig)
868+{
869+ return 0;
870+}
871+
872+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
873+{
874+ return 0;
875+}
876+
877+static inline int ccs_tkill_permission(pid_t pid, int sig)
878+{
879+ return 0;
880+}
881+
882+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
883+{
884+ return 0;
885+}
886+
887+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
888+{
889+ return 0;
890+}
891+
892+#endif
893+
894+/* Index numbers for Capability Controls. */
895+enum ccs_capability_acl_index {
896+ /* socket(PF_ROUTE, *, *) */
897+ CCS_USE_ROUTE_SOCKET,
898+ /* socket(PF_PACKET, *, *) */
899+ CCS_USE_PACKET_SOCKET,
900+ /* sys_reboot() */
901+ CCS_SYS_REBOOT,
902+ /* sys_vhangup() */
903+ CCS_SYS_VHANGUP,
904+ /* do_settimeofday(), sys_adjtimex() */
905+ CCS_SYS_SETTIME,
906+ /* sys_nice(), sys_setpriority() */
907+ CCS_SYS_NICE,
908+ /* sys_sethostname(), sys_setdomainname() */
909+ CCS_SYS_SETHOSTNAME,
910+ /* sys_create_module(), sys_init_module(), sys_delete_module() */
911+ CCS_USE_KERNEL_MODULE,
912+ /* sys_kexec_load() */
913+ CCS_SYS_KEXEC_LOAD,
914+ /* sys_ptrace() */
915+ CCS_SYS_PTRACE,
916+ CCS_MAX_CAPABILITY_INDEX
917+};
918+
919+#endif
--- tags/patches/1.0.33/policy_io.c (nonexistent)
+++ tags/patches/1.0.33/policy_io.c (revision 502)
@@ -0,0 +1,6463 @@
1+/*
2+ * security/ccsecurity/policy_io.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
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+/* Mapping table from "enum ccs_mac_index" to "enum ccs_mac_category_index". */
23+static const u8 ccs_index2category[CCS_MAX_MAC_INDEX] = {
24+ /* CONFIG::file group */
25+ [CCS_MAC_FILE_EXECUTE] = CCS_MAC_CATEGORY_FILE,
26+ [CCS_MAC_FILE_OPEN] = CCS_MAC_CATEGORY_FILE,
27+ [CCS_MAC_FILE_CREATE] = CCS_MAC_CATEGORY_FILE,
28+ [CCS_MAC_FILE_UNLINK] = CCS_MAC_CATEGORY_FILE,
29+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
30+ [CCS_MAC_FILE_GETATTR] = CCS_MAC_CATEGORY_FILE,
31+#endif
32+ [CCS_MAC_FILE_MKDIR] = CCS_MAC_CATEGORY_FILE,
33+ [CCS_MAC_FILE_RMDIR] = CCS_MAC_CATEGORY_FILE,
34+ [CCS_MAC_FILE_MKFIFO] = CCS_MAC_CATEGORY_FILE,
35+ [CCS_MAC_FILE_MKSOCK] = CCS_MAC_CATEGORY_FILE,
36+ [CCS_MAC_FILE_TRUNCATE] = CCS_MAC_CATEGORY_FILE,
37+ [CCS_MAC_FILE_SYMLINK] = CCS_MAC_CATEGORY_FILE,
38+ [CCS_MAC_FILE_MKBLOCK] = CCS_MAC_CATEGORY_FILE,
39+ [CCS_MAC_FILE_MKCHAR] = CCS_MAC_CATEGORY_FILE,
40+ [CCS_MAC_FILE_LINK] = CCS_MAC_CATEGORY_FILE,
41+ [CCS_MAC_FILE_RENAME] = CCS_MAC_CATEGORY_FILE,
42+ [CCS_MAC_FILE_CHMOD] = CCS_MAC_CATEGORY_FILE,
43+ [CCS_MAC_FILE_CHOWN] = CCS_MAC_CATEGORY_FILE,
44+ [CCS_MAC_FILE_CHGRP] = CCS_MAC_CATEGORY_FILE,
45+ [CCS_MAC_FILE_IOCTL] = CCS_MAC_CATEGORY_FILE,
46+ [CCS_MAC_FILE_CHROOT] = CCS_MAC_CATEGORY_FILE,
47+ [CCS_MAC_FILE_MOUNT] = CCS_MAC_CATEGORY_FILE,
48+ [CCS_MAC_FILE_UMOUNT] = CCS_MAC_CATEGORY_FILE,
49+ [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
50+#ifdef CONFIG_CCSECURITY_MISC
51+ /* CONFIG::misc group */
52+ [CCS_MAC_ENVIRON] = CCS_MAC_CATEGORY_MISC,
53+#endif
54+#ifdef CONFIG_CCSECURITY_NETWORK
55+ /* CONFIG::network group */
56+ [CCS_MAC_NETWORK_INET_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
57+ [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
58+ [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
59+ [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
60+ [CCS_MAC_NETWORK_INET_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
61+ [CCS_MAC_NETWORK_INET_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
62+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
63+ [CCS_MAC_NETWORK_INET_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
64+#endif
65+ [CCS_MAC_NETWORK_INET_RAW_BIND] = CCS_MAC_CATEGORY_NETWORK,
66+ [CCS_MAC_NETWORK_INET_RAW_SEND] = CCS_MAC_CATEGORY_NETWORK,
67+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
68+ [CCS_MAC_NETWORK_INET_RAW_RECV] = CCS_MAC_CATEGORY_NETWORK,
69+#endif
70+ [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
71+ [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
72+ [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
73+ [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
74+ [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
75+ [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
76+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
77+ [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
78+#endif
79+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = CCS_MAC_CATEGORY_NETWORK,
80+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
81+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
82+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
83+#endif
84+#ifdef CONFIG_CCSECURITY_IPC
85+ /* CONFIG::ipc group */
86+ [CCS_MAC_SIGNAL] = CCS_MAC_CATEGORY_IPC,
87+#endif
88+#ifdef CONFIG_CCSECURITY_CAPABILITY
89+ /* CONFIG::capability group */
90+ [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
91+ [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
92+ [CCS_MAC_CAPABILITY_SYS_REBOOT] = CCS_MAC_CATEGORY_CAPABILITY,
93+ [CCS_MAC_CAPABILITY_SYS_VHANGUP] = CCS_MAC_CATEGORY_CAPABILITY,
94+ [CCS_MAC_CAPABILITY_SYS_SETTIME] = CCS_MAC_CATEGORY_CAPABILITY,
95+ [CCS_MAC_CAPABILITY_SYS_NICE] = CCS_MAC_CATEGORY_CAPABILITY,
96+ [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = CCS_MAC_CATEGORY_CAPABILITY,
97+ [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = CCS_MAC_CATEGORY_CAPABILITY,
98+ [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = CCS_MAC_CATEGORY_CAPABILITY,
99+ [CCS_MAC_CAPABILITY_SYS_PTRACE] = CCS_MAC_CATEGORY_CAPABILITY,
100+#endif
101+};
102+
103+/* String table for operation mode. */
104+static const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
105+ [CCS_CONFIG_DISABLED] = "disabled",
106+ [CCS_CONFIG_LEARNING] = "learning",
107+ [CCS_CONFIG_PERMISSIVE] = "permissive",
108+ [CCS_CONFIG_ENFORCING] = "enforcing"
109+};
110+
111+/* String table for /proc/ccs/profile interface. */
112+static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
113+ + CCS_MAX_MAC_CATEGORY_INDEX] = {
114+ /* CONFIG::file group */
115+ [CCS_MAC_FILE_EXECUTE] = "execute",
116+ [CCS_MAC_FILE_OPEN] = "open",
117+ [CCS_MAC_FILE_CREATE] = "create",
118+ [CCS_MAC_FILE_UNLINK] = "unlink",
119+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
120+ [CCS_MAC_FILE_GETATTR] = "getattr",
121+#endif
122+ [CCS_MAC_FILE_MKDIR] = "mkdir",
123+ [CCS_MAC_FILE_RMDIR] = "rmdir",
124+ [CCS_MAC_FILE_MKFIFO] = "mkfifo",
125+ [CCS_MAC_FILE_MKSOCK] = "mksock",
126+ [CCS_MAC_FILE_TRUNCATE] = "truncate",
127+ [CCS_MAC_FILE_SYMLINK] = "symlink",
128+ [CCS_MAC_FILE_MKBLOCK] = "mkblock",
129+ [CCS_MAC_FILE_MKCHAR] = "mkchar",
130+ [CCS_MAC_FILE_LINK] = "link",
131+ [CCS_MAC_FILE_RENAME] = "rename",
132+ [CCS_MAC_FILE_CHMOD] = "chmod",
133+ [CCS_MAC_FILE_CHOWN] = "chown",
134+ [CCS_MAC_FILE_CHGRP] = "chgrp",
135+ [CCS_MAC_FILE_IOCTL] = "ioctl",
136+ [CCS_MAC_FILE_CHROOT] = "chroot",
137+ [CCS_MAC_FILE_MOUNT] = "mount",
138+ [CCS_MAC_FILE_UMOUNT] = "unmount",
139+ [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
140+#ifdef CONFIG_CCSECURITY_MISC
141+ /* CONFIG::misc group */
142+ [CCS_MAC_ENVIRON] = "env",
143+#endif
144+#ifdef CONFIG_CCSECURITY_NETWORK
145+ /* CONFIG::network group */
146+ [CCS_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind",
147+ [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen",
148+ [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect",
149+ [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = "inet_stream_accept",
150+ [CCS_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind",
151+ [CCS_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
152+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
153+ [CCS_MAC_NETWORK_INET_DGRAM_RECV] = "inet_dgram_recv",
154+#endif
155+ [CCS_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
156+ [CCS_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
157+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
158+ [CCS_MAC_NETWORK_INET_RAW_RECV] = "inet_raw_recv",
159+#endif
160+ [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
161+ [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
162+ [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
163+ [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = "unix_stream_accept",
164+ [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind",
165+ [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send",
166+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
167+ [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = "unix_dgram_recv",
168+#endif
169+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
170+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
171+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
172+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = "unix_seqpacket_accept",
173+#endif
174+#ifdef CONFIG_CCSECURITY_IPC
175+ /* CONFIG::ipc group */
176+ [CCS_MAC_SIGNAL] = "signal",
177+#endif
178+#ifdef CONFIG_CCSECURITY_CAPABILITY
179+ /* CONFIG::capability group */
180+ [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = "use_route",
181+ [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
182+ [CCS_MAC_CAPABILITY_SYS_REBOOT] = "SYS_REBOOT",
183+ [CCS_MAC_CAPABILITY_SYS_VHANGUP] = "SYS_VHANGUP",
184+ [CCS_MAC_CAPABILITY_SYS_SETTIME] = "SYS_TIME",
185+ [CCS_MAC_CAPABILITY_SYS_NICE] = "SYS_NICE",
186+ [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
187+ [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
188+ [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
189+ [CCS_MAC_CAPABILITY_SYS_PTRACE] = "SYS_PTRACE",
190+#endif
191+ /* CONFIG group */
192+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE] = "file",
193+#ifdef CONFIG_CCSECURITY_NETWORK
194+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK] = "network",
195+#endif
196+#ifdef CONFIG_CCSECURITY_MISC
197+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC] = "misc",
198+#endif
199+#ifdef CONFIG_CCSECURITY_IPC
200+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC] = "ipc",
201+#endif
202+#ifdef CONFIG_CCSECURITY_CAPABILITY
203+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
204+#endif
205+};
206+
207+/* String table for path operation. */
208+static const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
209+ [CCS_TYPE_EXECUTE] = "execute",
210+ [CCS_TYPE_READ] = "read",
211+ [CCS_TYPE_WRITE] = "write",
212+ [CCS_TYPE_APPEND] = "append",
213+ [CCS_TYPE_UNLINK] = "unlink",
214+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
215+ [CCS_TYPE_GETATTR] = "getattr",
216+#endif
217+ [CCS_TYPE_RMDIR] = "rmdir",
218+ [CCS_TYPE_TRUNCATE] = "truncate",
219+ [CCS_TYPE_SYMLINK] = "symlink",
220+ [CCS_TYPE_CHROOT] = "chroot",
221+ [CCS_TYPE_UMOUNT] = "unmount",
222+};
223+
224+#ifdef CONFIG_CCSECURITY_NETWORK
225+
226+/* String table for socket's operation. */
227+static const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = {
228+ [CCS_NETWORK_BIND] = "bind",
229+ [CCS_NETWORK_LISTEN] = "listen",
230+ [CCS_NETWORK_CONNECT] = "connect",
231+ [CCS_NETWORK_ACCEPT] = "accept",
232+ [CCS_NETWORK_SEND] = "send",
233+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
234+ [CCS_NETWORK_RECV] = "recv",
235+#endif
236+};
237+
238+/* String table for socket's protocols. */
239+static const char * const ccs_proto_keyword[CCS_SOCK_MAX] = {
240+ [SOCK_STREAM] = "stream",
241+ [SOCK_DGRAM] = "dgram",
242+ [SOCK_RAW] = "raw",
243+ [SOCK_SEQPACKET] = "seqpacket",
244+ [0] = " ", /* Dummy for avoiding NULL pointer dereference. */
245+ [4] = " ", /* Dummy for avoiding NULL pointer dereference. */
246+};
247+
248+#endif
249+
250+/* String table for categories. */
251+static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
252+ [CCS_MAC_CATEGORY_FILE] = "file",
253+#ifdef CONFIG_CCSECURITY_NETWORK
254+ [CCS_MAC_CATEGORY_NETWORK] = "network",
255+#endif
256+#ifdef CONFIG_CCSECURITY_MISC
257+ [CCS_MAC_CATEGORY_MISC] = "misc",
258+#endif
259+#ifdef CONFIG_CCSECURITY_IPC
260+ [CCS_MAC_CATEGORY_IPC] = "ipc",
261+#endif
262+#ifdef CONFIG_CCSECURITY_CAPABILITY
263+ [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
264+#endif
265+};
266+
267+/* String table for conditions. */
268+static const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
269+ [CCS_TASK_UID] = "task.uid",
270+ [CCS_TASK_EUID] = "task.euid",
271+ [CCS_TASK_SUID] = "task.suid",
272+ [CCS_TASK_FSUID] = "task.fsuid",
273+ [CCS_TASK_GID] = "task.gid",
274+ [CCS_TASK_EGID] = "task.egid",
275+ [CCS_TASK_SGID] = "task.sgid",
276+ [CCS_TASK_FSGID] = "task.fsgid",
277+ [CCS_TASK_PID] = "task.pid",
278+ [CCS_TASK_PPID] = "task.ppid",
279+ [CCS_EXEC_ARGC] = "exec.argc",
280+ [CCS_EXEC_ENVC] = "exec.envc",
281+ [CCS_TYPE_IS_SOCKET] = "socket",
282+ [CCS_TYPE_IS_SYMLINK] = "symlink",
283+ [CCS_TYPE_IS_FILE] = "file",
284+ [CCS_TYPE_IS_BLOCK_DEV] = "block",
285+ [CCS_TYPE_IS_DIRECTORY] = "directory",
286+ [CCS_TYPE_IS_CHAR_DEV] = "char",
287+ [CCS_TYPE_IS_FIFO] = "fifo",
288+ [CCS_MODE_SETUID] = "setuid",
289+ [CCS_MODE_SETGID] = "setgid",
290+ [CCS_MODE_STICKY] = "sticky",
291+ [CCS_MODE_OWNER_READ] = "owner_read",
292+ [CCS_MODE_OWNER_WRITE] = "owner_write",
293+ [CCS_MODE_OWNER_EXECUTE] = "owner_execute",
294+ [CCS_MODE_GROUP_READ] = "group_read",
295+ [CCS_MODE_GROUP_WRITE] = "group_write",
296+ [CCS_MODE_GROUP_EXECUTE] = "group_execute",
297+ [CCS_MODE_OTHERS_READ] = "others_read",
298+ [CCS_MODE_OTHERS_WRITE] = "others_write",
299+ [CCS_MODE_OTHERS_EXECUTE] = "others_execute",
300+ [CCS_TASK_TYPE] = "task.type",
301+ [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
302+ [CCS_EXEC_REALPATH] = "exec.realpath",
303+ [CCS_SYMLINK_TARGET] = "symlink.target",
304+ [CCS_PATH1_UID] = "path1.uid",
305+ [CCS_PATH1_GID] = "path1.gid",
306+ [CCS_PATH1_INO] = "path1.ino",
307+ [CCS_PATH1_MAJOR] = "path1.major",
308+ [CCS_PATH1_MINOR] = "path1.minor",
309+ [CCS_PATH1_PERM] = "path1.perm",
310+ [CCS_PATH1_TYPE] = "path1.type",
311+ [CCS_PATH1_DEV_MAJOR] = "path1.dev_major",
312+ [CCS_PATH1_DEV_MINOR] = "path1.dev_minor",
313+ [CCS_PATH2_UID] = "path2.uid",
314+ [CCS_PATH2_GID] = "path2.gid",
315+ [CCS_PATH2_INO] = "path2.ino",
316+ [CCS_PATH2_MAJOR] = "path2.major",
317+ [CCS_PATH2_MINOR] = "path2.minor",
318+ [CCS_PATH2_PERM] = "path2.perm",
319+ [CCS_PATH2_TYPE] = "path2.type",
320+ [CCS_PATH2_DEV_MAJOR] = "path2.dev_major",
321+ [CCS_PATH2_DEV_MINOR] = "path2.dev_minor",
322+ [CCS_PATH1_PARENT_UID] = "path1.parent.uid",
323+ [CCS_PATH1_PARENT_GID] = "path1.parent.gid",
324+ [CCS_PATH1_PARENT_INO] = "path1.parent.ino",
325+ [CCS_PATH1_PARENT_PERM] = "path1.parent.perm",
326+ [CCS_PATH2_PARENT_UID] = "path2.parent.uid",
327+ [CCS_PATH2_PARENT_GID] = "path2.parent.gid",
328+ [CCS_PATH2_PARENT_INO] = "path2.parent.ino",
329+ [CCS_PATH2_PARENT_PERM] = "path2.parent.perm",
330+};
331+
332+/* String table for PREFERENCE keyword. */
333+static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
334+ [CCS_PREF_MAX_AUDIT_LOG] = "max_audit_log",
335+ [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
336+ [CCS_PREF_ENFORCING_PENALTY] = "enforcing_penalty",
337+};
338+
339+/* String table for domain flags. */
340+const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
341+ [CCS_DIF_QUOTA_WARNED] = "quota_exceeded\n",
342+ [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
343+};
344+
345+/* String table for domain transition control keywords. */
346+static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
347+ [CCS_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ",
348+ [CCS_TRANSITION_CONTROL_RESET] = "reset_domain ",
349+ [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
350+ [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
351+ [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
352+ [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
353+};
354+
355+/* String table for grouping keywords. */
356+static const char * const ccs_group_name[CCS_MAX_GROUP] = {
357+ [CCS_PATH_GROUP] = "path_group ",
358+ [CCS_NUMBER_GROUP] = "number_group ",
359+#ifdef CONFIG_CCSECURITY_NETWORK
360+ [CCS_ADDRESS_GROUP] = "address_group ",
361+#endif
362+};
363+
364+/* String table for /proc/ccs/stat interface. */
365+static const char * const ccs_policy_headers[CCS_MAX_POLICY_STAT] = {
366+ [CCS_STAT_POLICY_UPDATES] = "update:",
367+ [CCS_STAT_POLICY_LEARNING] = "violation in learning mode:",
368+ [CCS_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
369+ [CCS_STAT_POLICY_ENFORCING] = "violation in enforcing mode:",
370+};
371+
372+/* String table for /proc/ccs/stat interface. */
373+static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
374+ [CCS_MEMORY_POLICY] = "policy:",
375+ [CCS_MEMORY_AUDIT] = "audit log:",
376+ [CCS_MEMORY_QUERY] = "query message:",
377+};
378+
379+/***** SECTION2: Structure definition *****/
380+
381+struct iattr;
382+
383+/* Structure for query. */
384+struct ccs_query {
385+ struct list_head list;
386+ struct ccs_domain_info *domain;
387+ char *query;
388+ size_t query_len;
389+ unsigned int serial;
390+ u8 timer;
391+ u8 answer;
392+ u8 retry;
393+};
394+
395+/* Structure for audit log. */
396+struct ccs_log {
397+ struct list_head list;
398+ char *log;
399+ int size;
400+};
401+
402+/***** SECTION3: Prototype definition section *****/
403+
404+int ccs_audit_log(struct ccs_request_info *r);
405+struct ccs_domain_info *ccs_assign_domain(const char *domainname,
406+ const bool transit);
407+u8 ccs_get_config(const u8 profile, const u8 index);
408+void ccs_transition_failed(const char *domainname);
409+void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...);
410+
411+static bool ccs_correct_domain(const unsigned char *domainname);
412+static bool ccs_correct_path(const char *filename);
413+static bool ccs_correct_word(const char *string);
414+static bool ccs_correct_word2(const char *string, size_t len);
415+static bool ccs_domain_def(const unsigned char *buffer);
416+static bool ccs_domain_quota_ok(struct ccs_request_info *r);
417+static bool ccs_flush(struct ccs_io_buffer *head);
418+static bool ccs_get_audit(const struct ccs_request_info *r);
419+static bool ccs_has_more_namespace(struct ccs_io_buffer *head);
420+static bool ccs_manager(void);
421+static bool ccs_namespace_jump(const char *domainname);
422+static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv);
423+static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp);
424+static bool ccs_parse_name_union(struct ccs_acl_param *param,
425+ struct ccs_name_union *ptr);
426+static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
427+ struct ccs_name_union *ptr);
428+static bool ccs_parse_number_union(struct ccs_acl_param *param,
429+ struct ccs_number_union *ptr);
430+static bool ccs_permstr(const char *string, const char *keyword);
431+static bool ccs_print_condition(struct ccs_io_buffer *head,
432+ const struct ccs_condition *cond);
433+static bool ccs_print_entry(struct ccs_io_buffer *head,
434+ const struct ccs_acl_info *acl);
435+static bool ccs_print_group(struct ccs_io_buffer *head,
436+ const struct ccs_group *group);
437+static bool ccs_read_acl(struct ccs_io_buffer *head, struct list_head *list);
438+static bool ccs_read_group(struct ccs_io_buffer *head, const int idx);
439+static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx);
440+static bool ccs_same_condition(const struct ccs_condition *a,
441+ const struct ccs_condition *b);
442+static bool ccs_select_domain(struct ccs_io_buffer *head, const char *data);
443+static bool ccs_set_lf(struct ccs_io_buffer *head);
444+static bool ccs_str_starts(char **src, const char *find);
445+static char *ccs_get_transit_preference(struct ccs_acl_param *param,
446+ struct ccs_condition *e);
447+static char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt,
448+ va_list args);
449+static char *ccs_print_bprm(struct linux_binprm *bprm,
450+ struct ccs_page_dump *dump);
451+static char *ccs_print_header(struct ccs_request_info *r);
452+static char *ccs_read_token(struct ccs_acl_param *param);
453+static const char *ccs_yesno(const unsigned int value);
454+static const struct ccs_path_info *ccs_get_domainname
455+(struct ccs_acl_param *param);
456+static const struct ccs_path_info *ccs_get_dqword(char *start);
457+static int __init ccs_init_module(void);
458+static int ccs_delete_domain(char *domainname);
459+static int ccs_open(struct inode *inode, struct file *file);
460+static int ccs_parse_policy(struct ccs_io_buffer *head, char *line);
461+static int ccs_release(struct inode *inode, struct file *file);
462+static int ccs_set_mode(char *name, const char *value,
463+ struct ccs_profile *profile);
464+static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
465+ __printf(2, 3);
466+static int ccs_truncate(char *str);
467+static int ccs_update_acl(const int size, struct ccs_acl_param *param);
468+static int ccs_update_manager_entry(const char *manager, const bool is_delete);
469+static int ccs_update_policy(const int size, struct ccs_acl_param *param);
470+static int ccs_write_acl(struct ccs_policy_namespace *ns,
471+ struct list_head *list, char *data,
472+ const bool is_delete);
473+static int ccs_write_aggregator(struct ccs_acl_param *param);
474+static int ccs_write_answer(struct ccs_io_buffer *head);
475+static int ccs_write_domain(struct ccs_io_buffer *head);
476+static int ccs_write_exception(struct ccs_io_buffer *head);
477+static int ccs_write_file(struct ccs_acl_param *param);
478+static int ccs_write_group(struct ccs_acl_param *param, const u8 type);
479+static int ccs_write_manager(struct ccs_io_buffer *head);
480+static int ccs_write_pid(struct ccs_io_buffer *head);
481+static int ccs_write_profile(struct ccs_io_buffer *head);
482+static int ccs_write_stat(struct ccs_io_buffer *head);
483+static int ccs_write_task(struct ccs_acl_param *param);
484+static int ccs_write_transition_control(struct ccs_acl_param *param,
485+ const u8 type);
486+static s8 ccs_find_yesno(const char *string, const char *find);
487+static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
488+ loff_t *ppos);
489+static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
490+ loff_t *ppos);
491+static ssize_t ccs_write(struct file *file, const char __user *buf,
492+ size_t count, loff_t *ppos);
493+static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry);
494+static struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param);
495+static struct ccs_domain_info *ccs_find_domain(const char *domainname);
496+static struct ccs_domain_info *ccs_find_domain_by_qid(unsigned int serial);
497+static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
498+ const u8 idx);
499+static struct ccs_policy_namespace *ccs_assign_namespace
500+(const char *domainname);
501+static struct ccs_policy_namespace *ccs_find_namespace(const char *name,
502+ const unsigned int len);
503+static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
504+ const unsigned int profile);
505+static struct ccs_profile *ccs_profile(const u8 profile);
506+static u8 ccs_condition_type(const char *word);
507+static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3);
508+static u8 ccs_parse_ulong(unsigned long *result, char **str);
509+static unsigned int ccs_poll(struct file *file, poll_table *wait);
510+static void __init ccs_create_entry(const char *name, const umode_t mode,
511+ struct proc_dir_entry *parent,
512+ const u8 key);
513+static void __init ccs_load_builtin_policy(void);
514+static void __init ccs_policy_io_init(void);
515+static void __init ccs_proc_init(void);
516+static void ccs_add_entry(char *header);
517+static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
518+ __printf(3, 4);
519+static void ccs_addprintf(char *buffer, int len, const char *fmt, ...);
520+static void ccs_check_profile(void);
521+static void ccs_convert_time(time_t time, struct ccs_time *stamp);
522+static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns);
523+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
524+ __printf(2, 3);
525+static void ccs_normalize_line(unsigned char *buffer);
526+static void ccs_print_config(struct ccs_io_buffer *head, const u8 config);
527+static void ccs_print_name_union(struct ccs_io_buffer *head,
528+ const struct ccs_name_union *ptr);
529+static void ccs_print_name_union_quoted(struct ccs_io_buffer *head,
530+ const struct ccs_name_union *ptr);
531+static void ccs_print_namespace(struct ccs_io_buffer *head);
532+static void ccs_print_number_union(struct ccs_io_buffer *head,
533+ const struct ccs_number_union *ptr);
534+static void ccs_print_number_union_nospace(struct ccs_io_buffer *head,
535+ const struct ccs_number_union *ptr);
536+static void ccs_read_domain(struct ccs_io_buffer *head);
537+static void ccs_read_exception(struct ccs_io_buffer *head);
538+static void ccs_read_log(struct ccs_io_buffer *head);
539+static void ccs_read_manager(struct ccs_io_buffer *head);
540+static void ccs_read_pid(struct ccs_io_buffer *head);
541+static void ccs_read_profile(struct ccs_io_buffer *head);
542+static void ccs_read_query(struct ccs_io_buffer *head);
543+static void ccs_read_stat(struct ccs_io_buffer *head);
544+static void ccs_read_version(struct ccs_io_buffer *head);
545+static void ccs_set_group(struct ccs_io_buffer *head, const char *category);
546+static void ccs_set_namespace_cursor(struct ccs_io_buffer *head);
547+static void ccs_set_slash(struct ccs_io_buffer *head);
548+static void ccs_set_space(struct ccs_io_buffer *head);
549+static void ccs_set_string(struct ccs_io_buffer *head, const char *string);
550+static void ccs_set_uint(unsigned int *i, const char *string,
551+ const char *find);
552+static void ccs_update_stat(const u8 index);
553+static void ccs_update_task_domain(struct ccs_request_info *r);
554+static void ccs_write_log2(struct ccs_request_info *r, int len,
555+ const char *fmt, va_list args);
556+
557+#ifdef CONFIG_CCSECURITY_PORTRESERVE
558+static bool __ccs_lport_reserved(const u16 port);
559+static int ccs_write_reserved_port(struct ccs_acl_param *param);
560+#endif
561+
562+#ifdef CONFIG_CCSECURITY_NETWORK
563+static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
564+ struct ccs_ipaddr_union *ptr);
565+static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
566+ const u32 *ip);
567+static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
568+ const struct in6_addr *ip);
569+static int ccs_write_inet_network(struct ccs_acl_param *param);
570+static int ccs_write_unix_network(struct ccs_acl_param *param);
571+static void ccs_print_ip(char *buf, const unsigned int size,
572+ const struct ccs_ipaddr_union *ptr);
573+#endif
574+
575+#ifdef CONFIG_CCSECURITY_CAPABILITY
576+static int ccs_write_capability(struct ccs_acl_param *param);
577+#endif
578+
579+#ifdef CONFIG_CCSECURITY_MISC
580+static int ccs_write_misc(struct ccs_acl_param *param);
581+#endif
582+
583+#ifdef CONFIG_CCSECURITY_IPC
584+static int ccs_write_ipc(struct ccs_acl_param *param);
585+#endif
586+
587+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
588+static ssize_t ccs_write_self(struct file *file, const char __user *buf,
589+ size_t count, loff_t *ppos);
590+#endif
591+
592+/***** SECTION4: Standalone functions section *****/
593+
594+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
595+
596+/**
597+ * fatal_signal_pending - Check whether SIGKILL is pending or not.
598+ *
599+ * @p: Pointer to "struct task_struct".
600+ *
601+ * Returns true if SIGKILL is pending on @p, false otherwise.
602+ *
603+ * This is for compatibility with older kernels.
604+ */
605+#define fatal_signal_pending(p) (signal_pending(p) && \
606+ sigismember(&p->pending.signal, SIGKILL))
607+
608+#endif
609+
610+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
611+
612+/**
613+ * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
614+ *
615+ * @wq: The waitqueue to wait on.
616+ * @condition: A C expression for the event to wait for.
617+ * @ret: Timeout, in jiffies.
618+ *
619+ * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
620+ * signal, and the remaining jiffies otherwise if the condition evaluated to
621+ * true before the timeout elapsed.
622+ *
623+ * This is for compatibility with older kernels.
624+ */
625+#define __wait_event_interruptible_timeout(wq, condition, ret) \
626+do { \
627+ wait_queue_t __wait; \
628+ init_waitqueue_entry(&__wait, current); \
629+ \
630+ add_wait_queue(&wq, &__wait); \
631+ for (;;) { \
632+ set_current_state(TASK_INTERRUPTIBLE); \
633+ if (condition) \
634+ break; \
635+ if (!signal_pending(current)) { \
636+ ret = schedule_timeout(ret); \
637+ if (!ret) \
638+ break; \
639+ continue; \
640+ } \
641+ ret = -ERESTARTSYS; \
642+ break; \
643+ } \
644+ current->state = TASK_RUNNING; \
645+ remove_wait_queue(&wq, &__wait); \
646+} while (0)
647+
648+/**
649+ * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
650+ *
651+ * @wq: The waitqueue to wait on.
652+ * @condition: A C expression for the event to wait for.
653+ * @timeout: Timeout, in jiffies.
654+ *
655+ * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
656+ * signal, and the remaining jiffies otherwise if the condition evaluated to
657+ * true before the timeout elapsed.
658+ *
659+ * This is for compatibility with older kernels.
660+ */
661+#define wait_event_interruptible_timeout(wq, condition, timeout) \
662+({ \
663+ long __ret = timeout; \
664+ if (!(condition)) \
665+ __wait_event_interruptible_timeout(wq, condition, __ret); \
666+ __ret; \
667+})
668+
669+#endif
670+
671+/**
672+ * ccs_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
673+ *
674+ * @time: Seconds since 1970/01/01 00:00:00.
675+ * @stamp: Pointer to "struct ccs_time".
676+ *
677+ * Returns nothing.
678+ *
679+ * This function does not handle Y2038 problem.
680+ */
681+static void ccs_convert_time(time_t time, struct ccs_time *stamp)
682+{
683+ static const u16 ccs_eom[2][12] = {
684+ { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
685+ { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
686+ };
687+ u16 y;
688+ u8 m;
689+ bool r;
690+ stamp->sec = time % 60;
691+ time /= 60;
692+ stamp->min = time % 60;
693+ time /= 60;
694+ stamp->hour = time % 24;
695+ time /= 24;
696+ for (y = 1970; ; y++) {
697+ const unsigned short days = (y & 3) ? 365 : 366;
698+ if (time < days)
699+ break;
700+ time -= days;
701+ }
702+ r = (y & 3) == 0;
703+ for (m = 0; m < 11 && time >= ccs_eom[r][m]; m++);
704+ if (m)
705+ time -= ccs_eom[r][m - 1];
706+ stamp->year = y;
707+ stamp->month = ++m;
708+ stamp->day = ++time;
709+}
710+
711+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)
712+#if !defined(RHEL_VERSION) || RHEL_VERSION != 3
713+
714+/**
715+ * PDE - Get "struct proc_dir_entry".
716+ *
717+ * @inode: Pointer to "struct inode".
718+ *
719+ * Returns pointer to "struct proc_dir_entry".
720+ *
721+ * This is for compatibility with older kernels.
722+ */
723+static inline struct proc_dir_entry *PDE(const struct inode *inode)
724+{
725+ return (struct proc_dir_entry *) inode->u.generic_ip;
726+}
727+
728+#endif
729+#endif
730+
731+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
732+
733+/**
734+ * proc_notify_change - Update inode's attributes and reflect to the dentry.
735+ *
736+ * @dentry: Pointer to "struct dentry".
737+ * @iattr: Pointer to "struct iattr".
738+ *
739+ * Returns 0 on success, negative value otherwise.
740+ *
741+ * The 2.4 kernels don't allow chmod()/chown() for files in /proc,
742+ * while the 2.6 kernels allow.
743+ * To permit management of /proc/ccs/ interface by non-root user,
744+ * I modified to allow chmod()/chown() of /proc/ccs/ interface like 2.6 kernels
745+ * by adding "struct inode_operations"->setattr hook.
746+ */
747+static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
748+{
749+ struct inode *inode = dentry->d_inode;
750+ struct proc_dir_entry *de = PDE(inode);
751+ int error;
752+
753+ error = inode_change_ok(inode, iattr);
754+ if (error)
755+ goto out;
756+
757+ error = inode_setattr(inode, iattr);
758+ if (error)
759+ goto out;
760+
761+ de->uid = inode->i_uid;
762+ de->gid = inode->i_gid;
763+ de->mode = inode->i_mode;
764+out:
765+ return error;
766+}
767+
768+#endif
769+
770+#ifdef CONFIG_CCSECURITY_NETWORK
771+
772+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && defined(CONFIG_NET)
773+#define ccs_in4_pton in4_pton
774+#define ccs_in6_pton in6_pton
775+#else
776+/*
777+ * Routines for parsing IPv4 or IPv6 address.
778+ * These are copied from lib/hexdump.c net/core/utils.c .
779+ */
780+#include <linux/ctype.h>
781+
782+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
783+static int hex_to_bin(char ch)
784+{
785+ if ((ch >= '0') && (ch <= '9'))
786+ return ch - '0';
787+ ch = tolower(ch);
788+ if ((ch >= 'a') && (ch <= 'f'))
789+ return ch - 'a' + 10;
790+ return -1;
791+}
792+#endif
793+
794+#define IN6PTON_XDIGIT 0x00010000
795+#define IN6PTON_DIGIT 0x00020000
796+#define IN6PTON_COLON_MASK 0x00700000
797+#define IN6PTON_COLON_1 0x00100000 /* single : requested */
798+#define IN6PTON_COLON_2 0x00200000 /* second : requested */
799+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
800+#define IN6PTON_DOT 0x00800000 /* . */
801+#define IN6PTON_DELIM 0x10000000
802+#define IN6PTON_NULL 0x20000000 /* first/tail */
803+#define IN6PTON_UNKNOWN 0x40000000
804+
805+static inline int xdigit2bin(char c, int delim)
806+{
807+ int val;
808+
809+ if (c == delim || c == '\0')
810+ return IN6PTON_DELIM;
811+ if (c == ':')
812+ return IN6PTON_COLON_MASK;
813+ if (c == '.')
814+ return IN6PTON_DOT;
815+
816+ val = hex_to_bin(c);
817+ if (val >= 0)
818+ return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
819+
820+ if (delim == -1)
821+ return IN6PTON_DELIM;
822+ return IN6PTON_UNKNOWN;
823+}
824+
825+static int ccs_in4_pton(const char *src, int srclen, u8 *dst, int delim,
826+ const char **end)
827+{
828+ const char *s;
829+ u8 *d;
830+ u8 dbuf[4];
831+ int ret = 0;
832+ int i;
833+ int w = 0;
834+
835+ if (srclen < 0)
836+ srclen = strlen(src);
837+ s = src;
838+ d = dbuf;
839+ i = 0;
840+ while (1) {
841+ int c;
842+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
843+ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
844+ IN6PTON_COLON_MASK)))
845+ goto out;
846+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
847+ if (w == 0)
848+ goto out;
849+ *d++ = w & 0xff;
850+ w = 0;
851+ i++;
852+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
853+ if (i != 4)
854+ goto out;
855+ break;
856+ }
857+ goto cont;
858+ }
859+ w = (w * 10) + c;
860+ if ((w & 0xffff) > 255)
861+ goto out;
862+cont:
863+ if (i >= 4)
864+ goto out;
865+ s++;
866+ srclen--;
867+ }
868+ ret = 1;
869+ memcpy(dst, dbuf, sizeof(dbuf));
870+out:
871+ if (end)
872+ *end = s;
873+ return ret;
874+}
875+
876+static int ccs_in6_pton(const char *src, int srclen, u8 *dst, int delim,
877+ const char **end)
878+{
879+ const char *s, *tok = NULL;
880+ u8 *d, *dc = NULL;
881+ u8 dbuf[16];
882+ int ret = 0;
883+ int i;
884+ int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
885+ int w = 0;
886+
887+ memset(dbuf, 0, sizeof(dbuf));
888+
889+ s = src;
890+ d = dbuf;
891+ if (srclen < 0)
892+ srclen = strlen(src);
893+
894+ while (1) {
895+ int c;
896+
897+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
898+ if (!(c & state))
899+ goto out;
900+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
901+ /* process one 16-bit word */
902+ if (!(state & IN6PTON_NULL)) {
903+ *d++ = (w >> 8) & 0xff;
904+ *d++ = w & 0xff;
905+ }
906+ w = 0;
907+ if (c & IN6PTON_DELIM) {
908+ /* We've processed last word */
909+ break;
910+ }
911+ /*
912+ * COLON_1 => XDIGIT
913+ * COLON_2 => XDIGIT|DELIM
914+ * COLON_1_2 => COLON_2
915+ */
916+ switch (state & IN6PTON_COLON_MASK) {
917+ case IN6PTON_COLON_2:
918+ dc = d;
919+ state = IN6PTON_XDIGIT | IN6PTON_DELIM;
920+ if (dc - dbuf >= sizeof(dbuf))
921+ state |= IN6PTON_NULL;
922+ break;
923+ case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
924+ state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
925+ break;
926+ case IN6PTON_COLON_1:
927+ state = IN6PTON_XDIGIT;
928+ break;
929+ case IN6PTON_COLON_1_2:
930+ state = IN6PTON_COLON_2;
931+ break;
932+ default:
933+ state = 0;
934+ }
935+ tok = s + 1;
936+ goto cont;
937+ }
938+
939+ if (c & IN6PTON_DOT) {
940+ ret = ccs_in4_pton(tok ? tok : s, srclen +
941+ (int)(s - tok), d, delim, &s);
942+ if (ret > 0) {
943+ d += 4;
944+ break;
945+ }
946+ goto out;
947+ }
948+
949+ w = (w << 4) | (0xff & c);
950+ state = IN6PTON_COLON_1 | IN6PTON_DELIM;
951+ if (!(w & 0xf000))
952+ state |= IN6PTON_XDIGIT;
953+ if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
954+ state |= IN6PTON_COLON_1_2;
955+ state &= ~IN6PTON_DELIM;
956+ }
957+ if (d + 2 >= dbuf + sizeof(dbuf))
958+ state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
959+cont:
960+ if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
961+ d + 4 == dbuf + sizeof(dbuf))
962+ state |= IN6PTON_DOT;
963+ if (d >= dbuf + sizeof(dbuf))
964+ state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
965+ s++;
966+ srclen--;
967+ }
968+
969+ i = 15; d--;
970+
971+ if (dc) {
972+ while (d >= dc)
973+ dst[i--] = *d--;
974+ while (i >= dc - dbuf)
975+ dst[i--] = 0;
976+ while (i >= 0)
977+ dst[i--] = *d--;
978+ } else
979+ memcpy(dst, dbuf, sizeof(dbuf));
980+
981+ ret = 1;
982+out:
983+ if (end)
984+ *end = s;
985+ return ret;
986+}
987+#endif
988+
989+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
990+
991+/*
992+ * Routines for printing IPv4 or IPv6 address.
993+ * These are copied from include/linux/kernel.h include/net/ipv6.h
994+ * include/net/addrconf.h lib/hexdump.c lib/vsprintf.c and simplified.
995+ */
996+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
997+#if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5 || !defined(RHEL_MINOR) || RHEL_MINOR < 9
998+static const char hex_asc[] = "0123456789abcdef";
999+#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
1000+#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
1001+
1002+static inline char *pack_hex_byte(char *buf, u8 byte)
1003+{
1004+ *buf++ = hex_asc_hi(byte);
1005+ *buf++ = hex_asc_lo(byte);
1006+ return buf;
1007+}
1008+#endif
1009+#endif
1010+
1011+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1012+static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
1013+{
1014+ return (a->s6_addr32[0] | a->s6_addr32[1] |
1015+ (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
1016+}
1017+#endif
1018+
1019+static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
1020+{
1021+ return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
1022+}
1023+
1024+static char *ip4_string(char *p, const u8 *addr)
1025+{
1026+ /*
1027+ * Since this function is called outside vsnprintf(), I can use
1028+ * sprintf() here.
1029+ */
1030+ return p +
1031+ sprintf(p, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
1032+}
1033+
1034+static char *ip6_compressed_string(char *p, const char *addr)
1035+{
1036+ int i, j, range;
1037+ unsigned char zerolength[8];
1038+ int longest = 1;
1039+ int colonpos = -1;
1040+ u16 word;
1041+ u8 hi, lo;
1042+ bool needcolon = false;
1043+ bool useIPv4;
1044+ struct in6_addr in6;
1045+
1046+ memcpy(&in6, addr, sizeof(struct in6_addr));
1047+
1048+ useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
1049+
1050+ memset(zerolength, 0, sizeof(zerolength));
1051+
1052+ if (useIPv4)
1053+ range = 6;
1054+ else
1055+ range = 8;
1056+
1057+ /* find position of longest 0 run */
1058+ for (i = 0; i < range; i++) {
1059+ for (j = i; j < range; j++) {
1060+ if (in6.s6_addr16[j] != 0)
1061+ break;
1062+ zerolength[i]++;
1063+ }
1064+ }
1065+ for (i = 0; i < range; i++) {
1066+ if (zerolength[i] > longest) {
1067+ longest = zerolength[i];
1068+ colonpos = i;
1069+ }
1070+ }
1071+ if (longest == 1) /* don't compress a single 0 */
1072+ colonpos = -1;
1073+
1074+ /* emit address */
1075+ for (i = 0; i < range; i++) {
1076+ if (i == colonpos) {
1077+ if (needcolon || i == 0)
1078+ *p++ = ':';
1079+ *p++ = ':';
1080+ needcolon = false;
1081+ i += longest - 1;
1082+ continue;
1083+ }
1084+ if (needcolon) {
1085+ *p++ = ':';
1086+ needcolon = false;
1087+ }
1088+ /* hex u16 without leading 0s */
1089+ word = ntohs(in6.s6_addr16[i]);
1090+ hi = word >> 8;
1091+ lo = word & 0xff;
1092+ if (hi) {
1093+ if (hi > 0x0f)
1094+ p = pack_hex_byte(p, hi);
1095+ else
1096+ *p++ = hex_asc_lo(hi);
1097+ p = pack_hex_byte(p, lo);
1098+ } else if (lo > 0x0f)
1099+ p = pack_hex_byte(p, lo);
1100+ else
1101+ *p++ = hex_asc_lo(lo);
1102+ needcolon = true;
1103+ }
1104+
1105+ if (useIPv4) {
1106+ if (needcolon)
1107+ *p++ = ':';
1108+ p = ip4_string(p, &in6.s6_addr[12]);
1109+ }
1110+ *p = '\0';
1111+
1112+ return p;
1113+}
1114+#endif
1115+
1116+/**
1117+ * ccs_print_ipv4 - Print an IPv4 address.
1118+ *
1119+ * @buffer: Buffer to write to.
1120+ * @buffer_len: Size of @buffer.
1121+ * @ip: Pointer to "u32 in network byte order".
1122+ *
1123+ * Returns written length.
1124+ */
1125+static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
1126+ const u32 *ip)
1127+{
1128+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1129+ return snprintf(buffer, buffer_len, "%pI4", ip);
1130+#else
1131+ char addr[sizeof("255.255.255.255")];
1132+ ip4_string(addr, (const u8 *) ip);
1133+ return snprintf(buffer, buffer_len, "%s", addr);
1134+#endif
1135+}
1136+
1137+/**
1138+ * ccs_print_ipv6 - Print an IPv6 address.
1139+ *
1140+ * @buffer: Buffer to write to.
1141+ * @buffer_len: Size of @buffer.
1142+ * @ip: Pointer to "struct in6_addr".
1143+ *
1144+ * Returns written length.
1145+ */
1146+static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
1147+ const struct in6_addr *ip)
1148+{
1149+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1150+ return snprintf(buffer, buffer_len, "%pI6c", ip);
1151+#else
1152+ char addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
1153+ ip6_compressed_string(addr, (const u8 *) ip);
1154+ return snprintf(buffer, buffer_len, "%s", addr);
1155+#endif
1156+}
1157+
1158+/**
1159+ * ccs_print_ip - Print an IP address.
1160+ *
1161+ * @buf: Buffer to write to.
1162+ * @size: Size of @buf.
1163+ * @ptr: Pointer to "struct ipaddr_union".
1164+ *
1165+ * Returns nothing.
1166+ */
1167+static void ccs_print_ip(char *buf, const unsigned int size,
1168+ const struct ccs_ipaddr_union *ptr)
1169+{
1170+ int len;
1171+ if (ptr->is_ipv6)
1172+ len = ccs_print_ipv6(buf, size, &ptr->ip[0]);
1173+ else
1174+ len = ccs_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0]);
1175+ if (!memcmp(&ptr->ip[0], &ptr->ip[1], 16) || len >= size / 2)
1176+ return;
1177+ buf[len++] = '-';
1178+ if (ptr->is_ipv6)
1179+ ccs_print_ipv6(buf + len, size - len, &ptr->ip[1]);
1180+ else
1181+ ccs_print_ipv4(buf + len, size - len,
1182+ &ptr->ip[1].s6_addr32[0]);
1183+}
1184+
1185+#endif
1186+
1187+/***** SECTION5: Variables definition section *****/
1188+
1189+/* Permit policy management by non-root user? */
1190+static bool ccs_manage_by_non_root;
1191+
1192+/* Lock for protecting policy. */
1193+DEFINE_MUTEX(ccs_policy_lock);
1194+
1195+/* Has /sbin/init started? */
1196+bool ccs_policy_loaded;
1197+
1198+/* List of namespaces. */
1199+LIST_HEAD(ccs_namespace_list);
1200+/* True if namespace other than ccs_kernel_namespace is defined. */
1201+static bool ccs_namespace_enabled;
1202+
1203+/* Initial namespace.*/
1204+static struct ccs_policy_namespace ccs_kernel_namespace;
1205+
1206+/* List of "struct ccs_condition". */
1207+LIST_HEAD(ccs_condition_list);
1208+
1209+#ifdef CONFIG_CCSECURITY_PORTRESERVE
1210+/* Bitmap for reserved local port numbers.*/
1211+static u8 ccs_reserved_port_map[8192];
1212+#endif
1213+
1214+/* Wait queue for kernel -> userspace notification. */
1215+static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
1216+/* Wait queue for userspace -> kernel notification. */
1217+static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
1218+
1219+/* The list for "struct ccs_query". */
1220+static LIST_HEAD(ccs_query_list);
1221+
1222+/* Lock for manipulating ccs_query_list. */
1223+static DEFINE_SPINLOCK(ccs_query_list_lock);
1224+
1225+/* Number of "struct file" referring /proc/ccs/query interface. */
1226+static atomic_t ccs_query_observers = ATOMIC_INIT(0);
1227+
1228+/* Wait queue for /proc/ccs/audit. */
1229+static DECLARE_WAIT_QUEUE_HEAD(ccs_log_wait);
1230+
1231+/* The list for "struct ccs_log". */
1232+static LIST_HEAD(ccs_log);
1233+
1234+/* Lock for "struct list_head ccs_log". */
1235+static DEFINE_SPINLOCK(ccs_log_lock);
1236+
1237+/* Length of "stuct list_head ccs_log". */
1238+static unsigned int ccs_log_count;
1239+
1240+/* Timestamp counter for last updated. */
1241+static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
1242+
1243+/* Counter for number of updates. */
1244+static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
1245+
1246+/* Operations for /proc/ccs/self_domain interface. */
1247+static
1248+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1249+const
1250+#endif
1251+struct file_operations ccs_self_operations = {
1252+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
1253+ .write = ccs_write_self,
1254+#endif
1255+ .read = ccs_read_self,
1256+};
1257+
1258+/* Operations for /proc/ccs/ interface. */
1259+static
1260+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1261+const
1262+#endif
1263+struct file_operations ccs_operations = {
1264+ .open = ccs_open,
1265+ .release = ccs_release,
1266+ .poll = ccs_poll,
1267+ .read = ccs_read,
1268+ .write = ccs_write,
1269+};
1270+
1271+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
1272+
1273+/* The inode operations for /proc/ccs/ directory. */
1274+static struct inode_operations ccs_dir_inode_operations;
1275+
1276+/* The inode operations for files under /proc/ccs/ directory. */
1277+static struct inode_operations ccs_file_inode_operations;
1278+
1279+#endif
1280+
1281+/***** SECTION6: Dependent functions section *****/
1282+
1283+/**
1284+ * list_for_each_cookie - iterate over a list with cookie.
1285+ *
1286+ * @pos: Pointer to "struct list_head".
1287+ * @head: Pointer to "struct list_head".
1288+ */
1289+#define list_for_each_cookie(pos, head) \
1290+ for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
1291+ pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
1292+
1293+/**
1294+ * ccs_read_token - Read a word from a line.
1295+ *
1296+ * @param: Pointer to "struct ccs_acl_param".
1297+ *
1298+ * Returns a word on success, "" otherwise.
1299+ *
1300+ * To allow the caller to skip NULL check, this function returns "" rather than
1301+ * NULL if there is no more words to read.
1302+ */
1303+static char *ccs_read_token(struct ccs_acl_param *param)
1304+{
1305+ char *pos = param->data;
1306+ char *del = strchr(pos, ' ');
1307+ if (del)
1308+ *del++ = '\0';
1309+ else
1310+ del = pos + strlen(pos);
1311+ param->data = del;
1312+ return pos;
1313+}
1314+
1315+/**
1316+ * ccs_make_byte - Make byte value from three octal characters.
1317+ *
1318+ * @c1: The first character.
1319+ * @c2: The second character.
1320+ * @c3: The third character.
1321+ *
1322+ * Returns byte value.
1323+ */
1324+static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
1325+{
1326+ return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
1327+}
1328+
1329+/**
1330+ * ccs_correct_word2 - Check whether the given string follows the naming rules.
1331+ *
1332+ * @string: The byte sequence to check. Not '\0'-terminated.
1333+ * @len: Length of @string.
1334+ *
1335+ * Returns true if @string follows the naming rules, false otherwise.
1336+ */
1337+static bool ccs_correct_word2(const char *string, size_t len)
1338+{
1339+ const char *const start = string;
1340+ bool in_repetition = false;
1341+ unsigned char c;
1342+ unsigned char d;
1343+ unsigned char e;
1344+ if (!len)
1345+ goto out;
1346+ while (len--) {
1347+ c = *string++;
1348+ if (c == '\\') {
1349+ if (!len--)
1350+ goto out;
1351+ c = *string++;
1352+ switch (c) {
1353+ case '\\': /* "\\" */
1354+ continue;
1355+ case '$': /* "\$" */
1356+ case '+': /* "\+" */
1357+ case '?': /* "\?" */
1358+ case '*': /* "\*" */
1359+ case '@': /* "\@" */
1360+ case 'x': /* "\x" */
1361+ case 'X': /* "\X" */
1362+ case 'a': /* "\a" */
1363+ case 'A': /* "\A" */
1364+ case '-': /* "\-" */
1365+ continue;
1366+ case '{': /* "/\{" */
1367+ if (string - 3 < start || *(string - 3) != '/')
1368+ break;
1369+ in_repetition = true;
1370+ continue;
1371+ case '}': /* "\}/" */
1372+ if (*string != '/')
1373+ break;
1374+ if (!in_repetition)
1375+ break;
1376+ in_repetition = false;
1377+ continue;
1378+ case '0': /* "\ooo" */
1379+ case '1':
1380+ case '2':
1381+ case '3':
1382+ if (!len-- || !len--)
1383+ break;
1384+ d = *string++;
1385+ e = *string++;
1386+ if (d < '0' || d > '7' || e < '0' || e > '7')
1387+ break;
1388+ c = ccs_make_byte(c, d, e);
1389+ if (c <= ' ' || c >= 127)
1390+ continue;
1391+ }
1392+ goto out;
1393+ } else if (in_repetition && c == '/') {
1394+ goto out;
1395+ } else if (c <= ' ' || c >= 127) {
1396+ goto out;
1397+ }
1398+ }
1399+ if (in_repetition)
1400+ goto out;
1401+ return true;
1402+out:
1403+ return false;
1404+}
1405+
1406+/**
1407+ * ccs_correct_word - Check whether the given string follows the naming rules.
1408+ *
1409+ * @string: The string to check.
1410+ *
1411+ * Returns true if @string follows the naming rules, false otherwise.
1412+ */
1413+static bool ccs_correct_word(const char *string)
1414+{
1415+ return ccs_correct_word2(string, strlen(string));
1416+}
1417+
1418+/**
1419+ * ccs_get_group - Allocate memory for "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group".
1420+ *
1421+ * @param: Pointer to "struct ccs_acl_param".
1422+ * @idx: Index number.
1423+ *
1424+ * Returns pointer to "struct ccs_group" on success, NULL otherwise.
1425+ */
1426+static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
1427+ const u8 idx)
1428+{
1429+ struct ccs_group e = { };
1430+ struct ccs_group *group = NULL;
1431+ struct list_head *list;
1432+ const char *group_name = ccs_read_token(param);
1433+ bool found = false;
1434+ if (!ccs_correct_word(group_name) || idx >= CCS_MAX_GROUP)
1435+ return NULL;
1436+ e.group_name = ccs_get_name(group_name);
1437+ if (!e.group_name)
1438+ return NULL;
1439+ if (mutex_lock_interruptible(&ccs_policy_lock))
1440+ goto out;
1441+ list = &param->ns->group_list[idx];
1442+ list_for_each_entry(group, list, head.list) {
1443+ if (e.group_name != group->group_name ||
1444+ atomic_read(&group->head.users) == CCS_GC_IN_PROGRESS)
1445+ continue;
1446+ atomic_inc(&group->head.users);
1447+ found = true;
1448+ break;
1449+ }
1450+ if (!found) {
1451+ struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
1452+ if (entry) {
1453+ INIT_LIST_HEAD(&entry->member_list);
1454+ atomic_set(&entry->head.users, 1);
1455+ list_add_tail_rcu(&entry->head.list, list);
1456+ group = entry;
1457+ found = true;
1458+ }
1459+ }
1460+ mutex_unlock(&ccs_policy_lock);
1461+out:
1462+ ccs_put_name(e.group_name);
1463+ return found ? group : NULL;
1464+}
1465+
1466+/**
1467+ * ccs_parse_name_union - Parse a ccs_name_union.
1468+ *
1469+ * @param: Pointer to "struct ccs_acl_param".
1470+ * @ptr: Pointer to "struct ccs_name_union".
1471+ *
1472+ * Returns true on success, false otherwise.
1473+ */
1474+static bool ccs_parse_name_union(struct ccs_acl_param *param,
1475+ struct ccs_name_union *ptr)
1476+{
1477+ char *filename;
1478+ if (param->data[0] == '@') {
1479+ param->data++;
1480+ ptr->group = ccs_get_group(param, CCS_PATH_GROUP);
1481+ return ptr->group != NULL;
1482+ }
1483+ filename = ccs_read_token(param);
1484+ if (!ccs_correct_word(filename))
1485+ return false;
1486+ ptr->filename = ccs_get_name(filename);
1487+ return ptr->filename != NULL;
1488+}
1489+
1490+/**
1491+ * ccs_parse_ulong - Parse an "unsigned long" value.
1492+ *
1493+ * @result: Pointer to "unsigned long".
1494+ * @str: Pointer to string to parse.
1495+ *
1496+ * Returns one of values in "enum ccs_value_type".
1497+ *
1498+ * The @src is updated to point the first character after the value
1499+ * on success.
1500+ */
1501+static u8 ccs_parse_ulong(unsigned long *result, char **str)
1502+{
1503+ const char *cp = *str;
1504+ char *ep;
1505+ int base = 10;
1506+ if (*cp == '0') {
1507+ char c = *(cp + 1);
1508+ if (c == 'x' || c == 'X') {
1509+ base = 16;
1510+ cp += 2;
1511+ } else if (c >= '0' && c <= '7') {
1512+ base = 8;
1513+ cp++;
1514+ }
1515+ }
1516+ *result = simple_strtoul(cp, &ep, base);
1517+ if (cp == ep)
1518+ return CCS_VALUE_TYPE_INVALID;
1519+ *str = ep;
1520+ switch (base) {
1521+ case 16:
1522+ return CCS_VALUE_TYPE_HEXADECIMAL;
1523+ case 8:
1524+ return CCS_VALUE_TYPE_OCTAL;
1525+ default:
1526+ return CCS_VALUE_TYPE_DECIMAL;
1527+ }
1528+}
1529+
1530+/**
1531+ * ccs_parse_number_union - Parse a ccs_number_union.
1532+ *
1533+ * @param: Pointer to "struct ccs_acl_param".
1534+ * @ptr: Pointer to "struct ccs_number_union".
1535+ *
1536+ * Returns true on success, false otherwise.
1537+ */
1538+static bool ccs_parse_number_union(struct ccs_acl_param *param,
1539+ struct ccs_number_union *ptr)
1540+{
1541+ char *data;
1542+ u8 type;
1543+ unsigned long v;
1544+ memset(ptr, 0, sizeof(*ptr));
1545+ if (param->data[0] == '@') {
1546+ param->data++;
1547+ ptr->group = ccs_get_group(param, CCS_NUMBER_GROUP);
1548+ return ptr->group != NULL;
1549+ }
1550+ data = ccs_read_token(param);
1551+ type = ccs_parse_ulong(&v, &data);
1552+ if (type == CCS_VALUE_TYPE_INVALID)
1553+ return false;
1554+ ptr->values[0] = v;
1555+ ptr->value_type[0] = type;
1556+ if (!*data) {
1557+ ptr->values[1] = v;
1558+ ptr->value_type[1] = type;
1559+ return true;
1560+ }
1561+ if (*data++ != '-')
1562+ return false;
1563+ type = ccs_parse_ulong(&v, &data);
1564+ if (type == CCS_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
1565+ return false;
1566+ ptr->values[1] = v;
1567+ ptr->value_type[1] = type;
1568+ return true;
1569+}
1570+
1571+#ifdef CONFIG_CCSECURITY_NETWORK
1572+
1573+/**
1574+ * ccs_parse_ipaddr_union - Parse an IP address.
1575+ *
1576+ * @param: Pointer to "struct ccs_acl_param".
1577+ * @ptr: Pointer to "struct ccs_ipaddr_union".
1578+ *
1579+ * Returns true on success, false otherwise.
1580+ */
1581+static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
1582+ struct ccs_ipaddr_union *ptr)
1583+{
1584+ u8 * const min = ptr->ip[0].in6_u.u6_addr8;
1585+ u8 * const max = ptr->ip[1].in6_u.u6_addr8;
1586+ char *address = ccs_read_token(param);
1587+ const char *end;
1588+ if (!strchr(address, ':') &&
1589+ ccs_in4_pton(address, -1, min, '-', &end) > 0) {
1590+ ptr->is_ipv6 = false;
1591+ if (!*end)
1592+ ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
1593+ else if (*end++ != '-' ||
1594+ ccs_in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
1595+ return false;
1596+ return true;
1597+ }
1598+ if (ccs_in6_pton(address, -1, min, '-', &end) > 0) {
1599+ ptr->is_ipv6 = true;
1600+ if (!*end)
1601+ memmove(max, min, sizeof(u16) * 8);
1602+ else if (*end++ != '-' ||
1603+ ccs_in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
1604+ return false;
1605+ return true;
1606+ }
1607+ return false;
1608+}
1609+
1610+#endif
1611+
1612+/**
1613+ * ccs_get_dqword - ccs_get_name() for a quoted string.
1614+ *
1615+ * @start: String to save.
1616+ *
1617+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
1618+ */
1619+static const struct ccs_path_info *ccs_get_dqword(char *start)
1620+{
1621+ char *cp = start + strlen(start) - 1;
1622+ if (cp == start || *start++ != '"' || *cp != '"')
1623+ return NULL;
1624+ *cp = '\0';
1625+ if (*start && !ccs_correct_word(start))
1626+ return NULL;
1627+ return ccs_get_name(start);
1628+}
1629+
1630+/**
1631+ * ccs_parse_name_union_quoted - Parse a quoted word.
1632+ *
1633+ * @param: Pointer to "struct ccs_acl_param".
1634+ * @ptr: Pointer to "struct ccs_name_union".
1635+ *
1636+ * Returns true on success, false otherwise.
1637+ */
1638+static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
1639+ struct ccs_name_union *ptr)
1640+{
1641+ char *filename = param->data;
1642+ if (*filename == '@')
1643+ return ccs_parse_name_union(param, ptr);
1644+ ptr->filename = ccs_get_dqword(filename);
1645+ return ptr->filename != NULL;
1646+}
1647+
1648+/**
1649+ * ccs_parse_argv - Parse an argv[] condition part.
1650+ *
1651+ * @left: Lefthand value.
1652+ * @right: Righthand value.
1653+ * @argv: Pointer to "struct ccs_argv".
1654+ *
1655+ * Returns true on success, false otherwise.
1656+ */
1657+static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv)
1658+{
1659+ if (ccs_parse_ulong(&argv->index, &left) != CCS_VALUE_TYPE_DECIMAL ||
1660+ *left++ != ']' || *left)
1661+ return false;
1662+ argv->value = ccs_get_dqword(right);
1663+ return argv->value != NULL;
1664+}
1665+
1666+/**
1667+ * ccs_parse_envp - Parse an envp[] condition part.
1668+ *
1669+ * @left: Lefthand value.
1670+ * @right: Righthand value.
1671+ * @envp: Pointer to "struct ccs_envp".
1672+ *
1673+ * Returns true on success, false otherwise.
1674+ */
1675+static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp)
1676+{
1677+ const struct ccs_path_info *name;
1678+ const struct ccs_path_info *value;
1679+ char *cp = left + strlen(left) - 1;
1680+ if (*cp-- != ']' || *cp != '"')
1681+ goto out;
1682+ *cp = '\0';
1683+ if (!ccs_correct_word(left))
1684+ goto out;
1685+ name = ccs_get_name(left);
1686+ if (!name)
1687+ goto out;
1688+ if (!strcmp(right, "NULL")) {
1689+ value = NULL;
1690+ } else {
1691+ value = ccs_get_dqword(right);
1692+ if (!value) {
1693+ ccs_put_name(name);
1694+ goto out;
1695+ }
1696+ }
1697+ envp->name = name;
1698+ envp->value = value;
1699+ return true;
1700+out:
1701+ return false;
1702+}
1703+
1704+/**
1705+ * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
1706+ *
1707+ * @a: Pointer to "struct ccs_condition".
1708+ * @b: Pointer to "struct ccs_condition".
1709+ *
1710+ * Returns true if @a == @b, false otherwise.
1711+ */
1712+static bool ccs_same_condition(const struct ccs_condition *a,
1713+ const struct ccs_condition *b)
1714+{
1715+ return a->size == b->size && a->condc == b->condc &&
1716+ a->numbers_count == b->numbers_count &&
1717+ a->names_count == b->names_count &&
1718+ a->argc == b->argc && a->envc == b->envc &&
1719+ a->grant_log == b->grant_log &&
1720+ a->exec_transit == b->exec_transit && a->transit == b->transit
1721+ && !memcmp(a + 1, b + 1, a->size - sizeof(*a));
1722+}
1723+
1724+/**
1725+ * ccs_condition_type - Get condition type.
1726+ *
1727+ * @word: Keyword string.
1728+ *
1729+ * Returns one of values in "enum ccs_conditions_index" on success,
1730+ * CCS_MAX_CONDITION_KEYWORD otherwise.
1731+ */
1732+static u8 ccs_condition_type(const char *word)
1733+{
1734+ u8 i;
1735+ for (i = 0; i < CCS_MAX_CONDITION_KEYWORD; i++) {
1736+ if (!strcmp(word, ccs_condition_keyword[i]))
1737+ break;
1738+ }
1739+ return i;
1740+}
1741+
1742+/**
1743+ * ccs_commit_condition - Commit "struct ccs_condition".
1744+ *
1745+ * @entry: Pointer to "struct ccs_condition".
1746+ *
1747+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1748+ *
1749+ * This function merges duplicated entries. This function returns NULL if
1750+ * @entry is not duplicated but memory quota for policy has exceeded.
1751+ */
1752+static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
1753+{
1754+ struct ccs_condition *ptr;
1755+ bool found = false;
1756+ if (mutex_lock_interruptible(&ccs_policy_lock)) {
1757+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
1758+ ptr = NULL;
1759+ found = true;
1760+ goto out;
1761+ }
1762+ list_for_each_entry(ptr, &ccs_condition_list, head.list) {
1763+ if (!ccs_same_condition(ptr, entry) ||
1764+ atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
1765+ continue;
1766+ /* Same entry found. Share this entry. */
1767+ atomic_inc(&ptr->head.users);
1768+ found = true;
1769+ break;
1770+ }
1771+ if (!found) {
1772+ if (ccs_memory_ok(entry, entry->size)) {
1773+ atomic_set(&entry->head.users, 1);
1774+ list_add(&entry->head.list, &ccs_condition_list);
1775+ } else {
1776+ found = true;
1777+ ptr = NULL;
1778+ }
1779+ }
1780+ mutex_unlock(&ccs_policy_lock);
1781+out:
1782+ if (found) {
1783+ ccs_del_condition(&entry->head.list);
1784+ kfree(entry);
1785+ entry = ptr;
1786+ }
1787+ return entry;
1788+}
1789+
1790+/**
1791+ * ccs_correct_path - Check whether the given pathname follows the naming rules.
1792+ *
1793+ * @filename: The pathname to check.
1794+ *
1795+ * Returns true if @filename follows the naming rules, false otherwise.
1796+ */
1797+static bool ccs_correct_path(const char *filename)
1798+{
1799+ return *filename == '/' && ccs_correct_word(filename);
1800+}
1801+
1802+/**
1803+ * ccs_domain_def - Check whether the given token can be a domainname.
1804+ *
1805+ * @buffer: The token to check.
1806+ *
1807+ * Returns true if @buffer possibly be a domainname, false otherwise.
1808+ */
1809+static bool ccs_domain_def(const unsigned char *buffer)
1810+{
1811+ const unsigned char *cp;
1812+ int len;
1813+ if (*buffer != '<')
1814+ return false;
1815+ cp = strchr(buffer, ' ');
1816+ if (!cp)
1817+ len = strlen(buffer);
1818+ else
1819+ len = cp - buffer;
1820+ if (buffer[len - 1] != '>' || !ccs_correct_word2(buffer + 1, len - 2))
1821+ return false;
1822+ return true;
1823+}
1824+
1825+/**
1826+ * ccs_correct_domain - Check whether the given domainname follows the naming rules.
1827+ *
1828+ * @domainname: The domainname to check.
1829+ *
1830+ * Returns true if @domainname follows the naming rules, false otherwise.
1831+ */
1832+static bool ccs_correct_domain(const unsigned char *domainname)
1833+{
1834+ if (!domainname || !ccs_domain_def(domainname))
1835+ return false;
1836+ domainname = strchr(domainname, ' ');
1837+ if (!domainname++)
1838+ return true;
1839+ while (1) {
1840+ const unsigned char *cp = strchr(domainname, ' ');
1841+ if (!cp)
1842+ break;
1843+ if (*domainname != '/' ||
1844+ !ccs_correct_word2(domainname, cp - domainname))
1845+ return false;
1846+ domainname = cp + 1;
1847+ }
1848+ return ccs_correct_path(domainname);
1849+}
1850+
1851+/**
1852+ * ccs_normalize_line - Format string.
1853+ *
1854+ * @buffer: The line to normalize.
1855+ *
1856+ * Returns nothing.
1857+ *
1858+ * Leading and trailing whitespaces are removed.
1859+ * Multiple whitespaces are packed into single space.
1860+ */
1861+static void ccs_normalize_line(unsigned char *buffer)
1862+{
1863+ unsigned char *sp = buffer;
1864+ unsigned char *dp = buffer;
1865+ bool first = true;
1866+ while (*sp && (*sp <= ' ' || *sp >= 127))
1867+ sp++;
1868+ while (*sp) {
1869+ if (!first)
1870+ *dp++ = ' ';
1871+ first = false;
1872+ while (*sp > ' ' && *sp < 127)
1873+ *dp++ = *sp++;
1874+ while (*sp && (*sp <= ' ' || *sp >= 127))
1875+ sp++;
1876+ }
1877+ *dp = '\0';
1878+}
1879+
1880+/**
1881+ * ccs_get_domainname - Read a domainname from a line.
1882+ *
1883+ * @param: Pointer to "struct ccs_acl_param".
1884+ *
1885+ * Returns a domainname on success, NULL otherwise.
1886+ */
1887+static const struct ccs_path_info *ccs_get_domainname
1888+(struct ccs_acl_param *param)
1889+{
1890+ char *start = param->data;
1891+ char *pos = start;
1892+ while (*pos) {
1893+ if (*pos++ != ' ' || *pos++ == '/')
1894+ continue;
1895+ pos -= 2;
1896+ *pos++ = '\0';
1897+ break;
1898+ }
1899+ param->data = pos;
1900+ if (ccs_correct_domain(start))
1901+ return ccs_get_name(start);
1902+ return NULL;
1903+}
1904+
1905+/**
1906+ * ccs_get_transit_preference - Parse domain transition preference for execve().
1907+ *
1908+ * @param: Pointer to "struct ccs_acl_param".
1909+ * @e: Pointer to "struct ccs_condition".
1910+ *
1911+ * Returns the condition string part.
1912+ */
1913+static char *ccs_get_transit_preference(struct ccs_acl_param *param,
1914+ struct ccs_condition *e)
1915+{
1916+ char * const pos = param->data;
1917+ bool flag;
1918+ if (*pos == '<') {
1919+ e->transit = ccs_get_domainname(param);
1920+ goto done;
1921+ }
1922+ {
1923+ char *cp = strchr(pos, ' ');
1924+ if (cp)
1925+ *cp = '\0';
1926+ flag = ccs_correct_path(pos) || !strcmp(pos, "keep") ||
1927+ !strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
1928+ !strcmp(pos, "child") || !strcmp(pos, "parent");
1929+ if (cp)
1930+ *cp = ' ';
1931+ }
1932+ if (!flag)
1933+ return pos;
1934+ e->transit = ccs_get_name(ccs_read_token(param));
1935+done:
1936+ if (e->transit) {
1937+ e->exec_transit = true;
1938+ return param->data;
1939+ }
1940+ /*
1941+ * Return a bad read-only condition string that will let
1942+ * ccs_get_condition() return NULL.
1943+ */
1944+ return "/";
1945+}
1946+
1947+/**
1948+ * ccs_get_condition - Parse condition part.
1949+ *
1950+ * @param: Pointer to "struct ccs_acl_param".
1951+ *
1952+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1953+ */
1954+struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param)
1955+{
1956+ struct ccs_condition *entry = NULL;
1957+ struct ccs_condition_element *condp = NULL;
1958+ struct ccs_number_union *numbers_p = NULL;
1959+ struct ccs_name_union *names_p = NULL;
1960+ struct ccs_argv *argv = NULL;
1961+ struct ccs_envp *envp = NULL;
1962+ struct ccs_condition e = { };
1963+ char * const start_of_string = ccs_get_transit_preference(param, &e);
1964+ char * const end_of_string = start_of_string + strlen(start_of_string);
1965+ char *pos;
1966+rerun:
1967+ pos = start_of_string;
1968+ while (1) {
1969+ u8 left = -1;
1970+ u8 right = -1;
1971+ char *left_word = pos;
1972+ char *cp;
1973+ char *right_word;
1974+ bool is_not;
1975+ if (!*left_word)
1976+ break;
1977+ /*
1978+ * Since left-hand condition does not allow use of "path_group"
1979+ * or "number_group" and environment variable's names do not
1980+ * accept '=', it is guaranteed that the original line consists
1981+ * of one or more repetition of $left$operator$right blocks
1982+ * where "$left is free from '=' and ' '" and "$operator is
1983+ * either '=' or '!='" and "$right is free from ' '".
1984+ * Therefore, we can reconstruct the original line at the end
1985+ * of dry run even if we overwrite $operator with '\0'.
1986+ */
1987+ cp = strchr(pos, ' ');
1988+ if (cp) {
1989+ *cp = '\0'; /* Will restore later. */
1990+ pos = cp + 1;
1991+ } else {
1992+ pos = "";
1993+ }
1994+ right_word = strchr(left_word, '=');
1995+ if (!right_word || right_word == left_word)
1996+ goto out;
1997+ is_not = *(right_word - 1) == '!';
1998+ if (is_not)
1999+ *(right_word++ - 1) = '\0'; /* Will restore later. */
2000+ else if (*(right_word + 1) != '=')
2001+ *right_word++ = '\0'; /* Will restore later. */
2002+ else
2003+ goto out;
2004+ dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
2005+ is_not ? "!" : "", right_word);
2006+ if (!strcmp(left_word, "grant_log")) {
2007+ if (entry) {
2008+ if (is_not ||
2009+ entry->grant_log != CCS_GRANTLOG_AUTO)
2010+ goto out;
2011+ else if (!strcmp(right_word, "yes"))
2012+ entry->grant_log = CCS_GRANTLOG_YES;
2013+ else if (!strcmp(right_word, "no"))
2014+ entry->grant_log = CCS_GRANTLOG_NO;
2015+ else
2016+ goto out;
2017+ }
2018+ continue;
2019+ }
2020+ if (!strcmp(left_word, "auto_domain_transition")) {
2021+ if (entry) {
2022+ if (is_not || entry->transit)
2023+ goto out;
2024+ entry->transit = ccs_get_dqword(right_word);
2025+ if (!entry->transit ||
2026+ (entry->transit->name[0] != '/' &&
2027+ !ccs_domain_def(entry->transit->name)))
2028+ goto out;
2029+ }
2030+ continue;
2031+ }
2032+ if (!strncmp(left_word, "exec.argv[", 10)) {
2033+ if (!argv) {
2034+ e.argc++;
2035+ e.condc++;
2036+ } else {
2037+ e.argc--;
2038+ e.condc--;
2039+ left = CCS_ARGV_ENTRY;
2040+ argv->is_not = is_not;
2041+ if (!ccs_parse_argv(left_word + 10,
2042+ right_word, argv++))
2043+ goto out;
2044+ }
2045+ goto store_value;
2046+ }
2047+ if (!strncmp(left_word, "exec.envp[\"", 11)) {
2048+ if (!envp) {
2049+ e.envc++;
2050+ e.condc++;
2051+ } else {
2052+ e.envc--;
2053+ e.condc--;
2054+ left = CCS_ENVP_ENTRY;
2055+ envp->is_not = is_not;
2056+ if (!ccs_parse_envp(left_word + 11,
2057+ right_word, envp++))
2058+ goto out;
2059+ }
2060+ goto store_value;
2061+ }
2062+ left = ccs_condition_type(left_word);
2063+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
2064+ left);
2065+ if (left == CCS_MAX_CONDITION_KEYWORD) {
2066+ if (!numbers_p) {
2067+ e.numbers_count++;
2068+ } else {
2069+ e.numbers_count--;
2070+ left = CCS_NUMBER_UNION;
2071+ param->data = left_word;
2072+ if (*left_word == '@' ||
2073+ !ccs_parse_number_union(param,
2074+ numbers_p++))
2075+ goto out;
2076+ }
2077+ }
2078+ if (!condp)
2079+ e.condc++;
2080+ else
2081+ e.condc--;
2082+ if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
2083+ if (!names_p) {
2084+ e.names_count++;
2085+ } else {
2086+ e.names_count--;
2087+ right = CCS_NAME_UNION;
2088+ param->data = right_word;
2089+ if (!ccs_parse_name_union_quoted(param,
2090+ names_p++))
2091+ goto out;
2092+ }
2093+ goto store_value;
2094+ }
2095+ right = ccs_condition_type(right_word);
2096+ if (right == CCS_MAX_CONDITION_KEYWORD) {
2097+ if (!numbers_p) {
2098+ e.numbers_count++;
2099+ } else {
2100+ e.numbers_count--;
2101+ right = CCS_NUMBER_UNION;
2102+ param->data = right_word;
2103+ if (!ccs_parse_number_union(param,
2104+ numbers_p++))
2105+ goto out;
2106+ }
2107+ }
2108+store_value:
2109+ if (!condp) {
2110+ dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
2111+ "match=%u\n", __LINE__, left, right, !is_not);
2112+ continue;
2113+ }
2114+ condp->left = left;
2115+ condp->right = right;
2116+ condp->equals = !is_not;
2117+ dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
2118+ __LINE__, condp->left, condp->right,
2119+ condp->equals);
2120+ condp++;
2121+ }
2122+ dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
2123+ __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
2124+ e.envc);
2125+ if (entry) {
2126+ BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
2127+ e.condc);
2128+ return ccs_commit_condition(entry);
2129+ }
2130+ e.size = sizeof(*entry)
2131+ + e.condc * sizeof(struct ccs_condition_element)
2132+ + e.numbers_count * sizeof(struct ccs_number_union)
2133+ + e.names_count * sizeof(struct ccs_name_union)
2134+ + e.argc * sizeof(struct ccs_argv)
2135+ + e.envc * sizeof(struct ccs_envp);
2136+ entry = kzalloc(e.size, CCS_GFP_FLAGS);
2137+ if (!entry)
2138+ goto out2;
2139+ *entry = e;
2140+ e.transit = NULL;
2141+ condp = (struct ccs_condition_element *) (entry + 1);
2142+ numbers_p = (struct ccs_number_union *) (condp + e.condc);
2143+ names_p = (struct ccs_name_union *) (numbers_p + e.numbers_count);
2144+ argv = (struct ccs_argv *) (names_p + e.names_count);
2145+ envp = (struct ccs_envp *) (argv + e.argc);
2146+ {
2147+ bool flag = false;
2148+ for (pos = start_of_string; pos < end_of_string; pos++) {
2149+ if (*pos)
2150+ continue;
2151+ if (flag) /* Restore " ". */
2152+ *pos = ' ';
2153+ else if (*(pos + 1) == '=') /* Restore "!=". */
2154+ *pos = '!';
2155+ else /* Restore "=". */
2156+ *pos = '=';
2157+ flag = !flag;
2158+ }
2159+ }
2160+ goto rerun;
2161+out:
2162+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
2163+ if (entry) {
2164+ ccs_del_condition(&entry->head.list);
2165+ kfree(entry);
2166+ }
2167+out2:
2168+ ccs_put_name(e.transit);
2169+ return NULL;
2170+}
2171+
2172+/**
2173+ * ccs_yesno - Return "yes" or "no".
2174+ *
2175+ * @value: Bool value.
2176+ *
2177+ * Returns "yes" if @value is not 0, "no" otherwise.
2178+ */
2179+static const char *ccs_yesno(const unsigned int value)
2180+{
2181+ return value ? "yes" : "no";
2182+}
2183+
2184+/**
2185+ * ccs_addprintf - strncat()-like-snprintf().
2186+ *
2187+ * @buffer: Buffer to write to. Must be '\0'-terminated.
2188+ * @len: Size of @buffer.
2189+ * @fmt: The printf()'s format string, followed by parameters.
2190+ *
2191+ * Returns nothing.
2192+ */
2193+static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
2194+{
2195+ va_list args;
2196+ const int pos = strlen(buffer);
2197+ va_start(args, fmt);
2198+ vsnprintf(buffer + pos, len - pos - 1, fmt, args);
2199+ va_end(args);
2200+}
2201+
2202+/**
2203+ * ccs_flush - Flush queued string to userspace's buffer.
2204+ *
2205+ * @head: Pointer to "struct ccs_io_buffer".
2206+ *
2207+ * Returns true if all data was flushed, false otherwise.
2208+ */
2209+static bool ccs_flush(struct ccs_io_buffer *head)
2210+{
2211+ while (head->r.w_pos) {
2212+ const char *w = head->r.w[0];
2213+ size_t len = strlen(w);
2214+ if (len) {
2215+ if (len > head->read_user_buf_avail)
2216+ len = head->read_user_buf_avail;
2217+ if (!len)
2218+ return false;
2219+ if (copy_to_user(head->read_user_buf, w, len))
2220+ return false;
2221+ head->read_user_buf_avail -= len;
2222+ head->read_user_buf += len;
2223+ w += len;
2224+ }
2225+ head->r.w[0] = w;
2226+ if (*w)
2227+ return false;
2228+ /* Add '\0' for audit logs and query. */
2229+ if (head->type == CCS_AUDIT || head->type == CCS_QUERY) {
2230+ if (!head->read_user_buf_avail ||
2231+ copy_to_user(head->read_user_buf, "", 1))
2232+ return false;
2233+ head->read_user_buf_avail--;
2234+ head->read_user_buf++;
2235+ }
2236+ head->r.w_pos--;
2237+ for (len = 0; len < head->r.w_pos; len++)
2238+ head->r.w[len] = head->r.w[len + 1];
2239+ }
2240+ head->r.avail = 0;
2241+ return true;
2242+}
2243+
2244+/**
2245+ * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
2246+ *
2247+ * @head: Pointer to "struct ccs_io_buffer".
2248+ * @string: String to print.
2249+ *
2250+ * Returns nothing.
2251+ *
2252+ * Note that @string has to be kept valid until @head is kfree()d.
2253+ * This means that char[] allocated on stack memory cannot be passed to
2254+ * this function. Use ccs_io_printf() for char[] allocated on stack memory.
2255+ */
2256+static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
2257+{
2258+ if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
2259+ head->r.w[head->r.w_pos++] = string;
2260+ ccs_flush(head);
2261+ } else
2262+ printk(KERN_WARNING "Too many words in a line.\n");
2263+}
2264+
2265+/**
2266+ * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
2267+ *
2268+ * @head: Pointer to "struct ccs_io_buffer".
2269+ * @fmt: The printf()'s format string, followed by parameters.
2270+ *
2271+ * Returns nothing.
2272+ */
2273+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
2274+{
2275+ va_list args;
2276+ size_t len;
2277+ size_t pos = head->r.avail;
2278+ int size = head->readbuf_size - pos;
2279+ if (size <= 0)
2280+ return;
2281+ va_start(args, fmt);
2282+ len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
2283+ va_end(args);
2284+ if (pos + len >= head->readbuf_size) {
2285+ printk(KERN_WARNING "Too many words in a line.\n");
2286+ return;
2287+ }
2288+ head->r.avail += len;
2289+ ccs_set_string(head, head->read_buf + pos);
2290+}
2291+
2292+/**
2293+ * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
2294+ *
2295+ * @head: Pointer to "struct ccs_io_buffer".
2296+ *
2297+ * Returns nothing.
2298+ */
2299+static void ccs_set_space(struct ccs_io_buffer *head)
2300+{
2301+ ccs_set_string(head, " ");
2302+}
2303+
2304+/**
2305+ * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
2306+ *
2307+ * @head: Pointer to "struct ccs_io_buffer".
2308+ *
2309+ * Returns true if all data was flushed, false otherwise.
2310+ */
2311+static bool ccs_set_lf(struct ccs_io_buffer *head)
2312+{
2313+ ccs_set_string(head, "\n");
2314+ return !head->r.w_pos;
2315+}
2316+
2317+/**
2318+ * ccs_set_slash - Put a shash to "struct ccs_io_buffer" structure.
2319+ *
2320+ * @head: Pointer to "struct ccs_io_buffer".
2321+ *
2322+ * Returns nothing.
2323+ */
2324+static void ccs_set_slash(struct ccs_io_buffer *head)
2325+{
2326+ ccs_set_string(head, "/");
2327+}
2328+
2329+/**
2330+ * ccs_init_policy_namespace - Initialize namespace.
2331+ *
2332+ * @ns: Pointer to "struct ccs_policy_namespace".
2333+ *
2334+ * Returns nothing.
2335+ */
2336+static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns)
2337+{
2338+ unsigned int idx;
2339+ for (idx = 0; idx < CCS_MAX_ACL_GROUPS; idx++)
2340+ INIT_LIST_HEAD(&ns->acl_group[idx]);
2341+ for (idx = 0; idx < CCS_MAX_GROUP; idx++)
2342+ INIT_LIST_HEAD(&ns->group_list[idx]);
2343+ for (idx = 0; idx < CCS_MAX_POLICY; idx++)
2344+ INIT_LIST_HEAD(&ns->policy_list[idx]);
2345+ ns->profile_version = 20100903;
2346+ ccs_namespace_enabled = !list_empty(&ccs_namespace_list);
2347+ list_add_tail_rcu(&ns->namespace_list, &ccs_namespace_list);
2348+}
2349+
2350+/**
2351+ * ccs_print_namespace - Print namespace header.
2352+ *
2353+ * @head: Pointer to "struct ccs_io_buffer".
2354+ *
2355+ * Returns nothing.
2356+ */
2357+static void ccs_print_namespace(struct ccs_io_buffer *head)
2358+{
2359+ if (!ccs_namespace_enabled)
2360+ return;
2361+ ccs_set_string(head,
2362+ container_of(head->r.ns, struct ccs_policy_namespace,
2363+ namespace_list)->name);
2364+ ccs_set_space(head);
2365+}
2366+
2367+/**
2368+ * ccs_assign_profile - Create a new profile.
2369+ *
2370+ * @ns: Pointer to "struct ccs_policy_namespace".
2371+ * @profile: Profile number to create.
2372+ *
2373+ * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
2374+ */
2375+static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
2376+ const unsigned int profile)
2377+{
2378+ struct ccs_profile *ptr;
2379+ struct ccs_profile *entry;
2380+ if (profile >= CCS_MAX_PROFILES)
2381+ return NULL;
2382+ ptr = ns->profile_ptr[profile];
2383+ if (ptr)
2384+ return ptr;
2385+ entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
2386+ if (mutex_lock_interruptible(&ccs_policy_lock))
2387+ goto out;
2388+ ptr = ns->profile_ptr[profile];
2389+ if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
2390+ ptr = entry;
2391+ ptr->default_config = CCS_CONFIG_DISABLED |
2392+ CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
2393+ memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
2394+ sizeof(ptr->config));
2395+ ptr->pref[CCS_PREF_MAX_AUDIT_LOG] =
2396+ CONFIG_CCSECURITY_MAX_AUDIT_LOG;
2397+ ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
2398+ CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
2399+ mb(); /* Avoid out-of-order execution. */
2400+ ns->profile_ptr[profile] = ptr;
2401+ entry = NULL;
2402+ }
2403+ mutex_unlock(&ccs_policy_lock);
2404+out:
2405+ kfree(entry);
2406+ return ptr;
2407+}
2408+
2409+/**
2410+ * ccs_check_profile - Check all profiles currently assigned to domains are defined.
2411+ *
2412+ * Returns nothing.
2413+ */
2414+static void ccs_check_profile(void)
2415+{
2416+ struct ccs_domain_info *domain;
2417+ const int idx = ccs_read_lock();
2418+ ccs_policy_loaded = true;
2419+ printk(KERN_INFO "CCSecurity: 1.8.3+ 2015/04/21\n");
2420+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2421+ const u8 profile = domain->profile;
2422+ const struct ccs_policy_namespace *ns = domain->ns;
2423+ if (ns->profile_version != 20100903)
2424+ printk(KERN_ERR
2425+ "Profile version %u is not supported.\n",
2426+ ns->profile_version);
2427+ else if (!ns->profile_ptr[profile])
2428+ printk(KERN_ERR
2429+ "Profile %u (used by '%s') is not defined.\n",
2430+ profile, domain->domainname->name);
2431+ else
2432+ continue;
2433+ printk(KERN_ERR
2434+ "Userland tools for TOMOYO 1.8 must be installed and "
2435+ "policy must be initialized.\n");
2436+ printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
2437+ "for more information.\n");
2438+ panic("STOP!");
2439+ }
2440+ ccs_read_unlock(idx);
2441+ printk(KERN_INFO "Mandatory Access Control activated.\n");
2442+}
2443+
2444+/**
2445+ * ccs_profile - Find a profile.
2446+ *
2447+ * @profile: Profile number to find.
2448+ *
2449+ * Returns pointer to "struct ccs_profile".
2450+ */
2451+static struct ccs_profile *ccs_profile(const u8 profile)
2452+{
2453+ static struct ccs_profile ccs_null_profile;
2454+ struct ccs_profile *ptr = ccs_current_namespace()->
2455+ profile_ptr[profile];
2456+ if (!ptr)
2457+ ptr = &ccs_null_profile;
2458+ return ptr;
2459+}
2460+
2461+/**
2462+ * ccs_get_config - Get config for specified profile's specified functionality.
2463+ *
2464+ * @profile: Profile number.
2465+ * @index: Index number of functionality.
2466+ *
2467+ * Returns config.
2468+ *
2469+ * First, check for CONFIG::category::functionality.
2470+ * If CONFIG::category::functionality is set to use default, then check
2471+ * CONFIG::category. If CONFIG::category is set to use default, then use
2472+ * CONFIG. CONFIG cannot be set to use default.
2473+ */
2474+u8 ccs_get_config(const u8 profile, const u8 index)
2475+{
2476+ u8 config;
2477+ const struct ccs_profile *p;
2478+ if (!ccs_policy_loaded)
2479+ return CCS_CONFIG_DISABLED;
2480+ p = ccs_profile(profile);
2481+ config = p->config[index];
2482+ if (config == CCS_CONFIG_USE_DEFAULT)
2483+ config = p->config[ccs_index2category[index]
2484+ + CCS_MAX_MAC_INDEX];
2485+ if (config == CCS_CONFIG_USE_DEFAULT)
2486+ config = p->default_config;
2487+ return config;
2488+}
2489+
2490+/**
2491+ * ccs_find_yesno - Find values for specified keyword.
2492+ *
2493+ * @string: String to check.
2494+ * @find: Name of keyword.
2495+ *
2496+ * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
2497+ */
2498+static s8 ccs_find_yesno(const char *string, const char *find)
2499+{
2500+ const char *cp = strstr(string, find);
2501+ if (cp) {
2502+ cp += strlen(find);
2503+ if (!strncmp(cp, "=yes", 4))
2504+ return 1;
2505+ else if (!strncmp(cp, "=no", 3))
2506+ return 0;
2507+ }
2508+ return -1;
2509+}
2510+
2511+/**
2512+ * ccs_set_uint - Set value for specified preference.
2513+ *
2514+ * @i: Pointer to "unsigned int".
2515+ * @string: String to check.
2516+ * @find: Name of keyword.
2517+ *
2518+ * Returns nothing.
2519+ */
2520+static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
2521+{
2522+ const char *cp = strstr(string, find);
2523+ if (cp)
2524+ sscanf(cp + strlen(find), "=%u", i);
2525+}
2526+
2527+/**
2528+ * ccs_str_starts - Check whether the given string starts with the given keyword.
2529+ *
2530+ * @src: Pointer to pointer to the string.
2531+ * @find: Pointer to the keyword.
2532+ *
2533+ * Returns true if @src starts with @find, false otherwise.
2534+ *
2535+ * The @src is updated to point the first character after the @find
2536+ * if @src starts with @find.
2537+ */
2538+static bool ccs_str_starts(char **src, const char *find)
2539+{
2540+ const int len = strlen(find);
2541+ char *tmp = *src;
2542+ if (strncmp(tmp, find, len))
2543+ return false;
2544+ tmp += len;
2545+ *src = tmp;
2546+ return true;
2547+}
2548+
2549+/**
2550+ * ccs_print_group - Print group's name.
2551+ *
2552+ * @head: Pointer to "struct ccs_io_buffer".
2553+ * @group: Pointer to "struct ccsgroup". Maybe NULL.
2554+ *
2555+ * Returns true if @group is not NULL. false otherwise.
2556+ */
2557+static bool ccs_print_group(struct ccs_io_buffer *head,
2558+ const struct ccs_group *group)
2559+{
2560+ if (group) {
2561+ ccs_set_string(head, "@");
2562+ ccs_set_string(head, group->group_name->name);
2563+ return true;
2564+ }
2565+ return false;
2566+}
2567+
2568+/**
2569+ * ccs_set_mode - Set mode for specified profile.
2570+ *
2571+ * @name: Name of functionality.
2572+ * @value: Mode for @name.
2573+ * @profile: Pointer to "struct ccs_profile".
2574+ *
2575+ * Returns 0 on success, negative value otherwise.
2576+ */
2577+static int ccs_set_mode(char *name, const char *value,
2578+ struct ccs_profile *profile)
2579+{
2580+ u8 i;
2581+ u8 config;
2582+ if (!strcmp(name, "CONFIG")) {
2583+ i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
2584+ config = profile->default_config;
2585+ } else if (ccs_str_starts(&name, "CONFIG::")) {
2586+ config = 0;
2587+ for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
2588+ i++) {
2589+ int len = 0;
2590+ if (i < CCS_MAX_MAC_INDEX) {
2591+ const u8 c = ccs_index2category[i];
2592+ const char *category =
2593+ ccs_category_keywords[c];
2594+ len = strlen(category);
2595+ if (strncmp(name, category, len) ||
2596+ name[len++] != ':' || name[len++] != ':')
2597+ continue;
2598+ }
2599+ if (strcmp(name + len, ccs_mac_keywords[i]))
2600+ continue;
2601+ config = profile->config[i];
2602+ break;
2603+ }
2604+ if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
2605+ return -EINVAL;
2606+ } else {
2607+ return -EINVAL;
2608+ }
2609+ if (strstr(value, "use_default")) {
2610+ config = CCS_CONFIG_USE_DEFAULT;
2611+ } else {
2612+ u8 mode;
2613+ for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
2614+ if (strstr(value, ccs_mode[mode]))
2615+ /*
2616+ * Update lower 3 bits in order to distinguish
2617+ * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
2618+ */
2619+ config = (config & ~7) | mode;
2620+ if (config != CCS_CONFIG_USE_DEFAULT) {
2621+ switch (ccs_find_yesno(value, "grant_log")) {
2622+ case 1:
2623+ config |= CCS_CONFIG_WANT_GRANT_LOG;
2624+ break;
2625+ case 0:
2626+ config &= ~CCS_CONFIG_WANT_GRANT_LOG;
2627+ break;
2628+ }
2629+ switch (ccs_find_yesno(value, "reject_log")) {
2630+ case 1:
2631+ config |= CCS_CONFIG_WANT_REJECT_LOG;
2632+ break;
2633+ case 0:
2634+ config &= ~CCS_CONFIG_WANT_REJECT_LOG;
2635+ break;
2636+ }
2637+ }
2638+ }
2639+ if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
2640+ profile->config[i] = config;
2641+ else if (config != CCS_CONFIG_USE_DEFAULT)
2642+ profile->default_config = config;
2643+ return 0;
2644+}
2645+
2646+/**
2647+ * ccs_write_profile - Write profile table.
2648+ *
2649+ * @head: Pointer to "struct ccs_io_buffer".
2650+ *
2651+ * Returns 0 on success, negative value otherwise.
2652+ */
2653+static int ccs_write_profile(struct ccs_io_buffer *head)
2654+{
2655+ char *data = head->write_buf;
2656+ unsigned int i;
2657+ char *cp;
2658+ struct ccs_profile *profile;
2659+ if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
2660+ == 1)
2661+ return 0;
2662+ i = simple_strtoul(data, &cp, 10);
2663+ if (*cp != '-')
2664+ return -EINVAL;
2665+ data = cp + 1;
2666+ profile = ccs_assign_profile(head->w.ns, i);
2667+ if (!profile)
2668+ return -EINVAL;
2669+ cp = strchr(data, '=');
2670+ if (!cp)
2671+ return -EINVAL;
2672+ *cp++ = '\0';
2673+ if (!strcmp(data, "COMMENT")) {
2674+ static DEFINE_SPINLOCK(lock);
2675+ const struct ccs_path_info *new_comment = ccs_get_name(cp);
2676+ const struct ccs_path_info *old_comment;
2677+ if (!new_comment)
2678+ return -ENOMEM;
2679+ spin_lock(&lock);
2680+ old_comment = profile->comment;
2681+ profile->comment = new_comment;
2682+ spin_unlock(&lock);
2683+ ccs_put_name(old_comment);
2684+ return 0;
2685+ }
2686+ if (!strcmp(data, "PREFERENCE")) {
2687+ for (i = 0; i < CCS_MAX_PREF; i++)
2688+ ccs_set_uint(&profile->pref[i], cp,
2689+ ccs_pref_keywords[i]);
2690+ return 0;
2691+ }
2692+ return ccs_set_mode(data, cp, profile);
2693+}
2694+
2695+/**
2696+ * ccs_print_config - Print mode for specified functionality.
2697+ *
2698+ * @head: Pointer to "struct ccs_io_buffer".
2699+ * @config: Mode for that functionality.
2700+ *
2701+ * Returns nothing.
2702+ *
2703+ * Caller prints functionality's name.
2704+ */
2705+static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)
2706+{
2707+ ccs_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
2708+ ccs_mode[config & 3],
2709+ ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),
2710+ ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));
2711+}
2712+
2713+/**
2714+ * ccs_read_profile - Read profile table.
2715+ *
2716+ * @head: Pointer to "struct ccs_io_buffer".
2717+ *
2718+ * Returns nothing.
2719+ */
2720+static void ccs_read_profile(struct ccs_io_buffer *head)
2721+{
2722+ u8 index;
2723+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
2724+ namespace_list);
2725+ const struct ccs_profile *profile;
2726+ if (head->r.eof)
2727+ return;
2728+next:
2729+ index = head->r.index;
2730+ profile = ns->profile_ptr[index];
2731+ switch (head->r.step) {
2732+ case 0:
2733+ ccs_print_namespace(head);
2734+ ccs_io_printf(head, "PROFILE_VERSION=%u\n",
2735+ ns->profile_version);
2736+ head->r.step++;
2737+ break;
2738+ case 1:
2739+ for ( ; head->r.index < CCS_MAX_PROFILES; head->r.index++)
2740+ if (ns->profile_ptr[head->r.index])
2741+ break;
2742+ if (head->r.index == CCS_MAX_PROFILES) {
2743+ head->r.eof = true;
2744+ return;
2745+ }
2746+ head->r.step++;
2747+ break;
2748+ case 2:
2749+ {
2750+ u8 i;
2751+ const struct ccs_path_info *comment = profile->comment;
2752+ ccs_print_namespace(head);
2753+ ccs_io_printf(head, "%u-COMMENT=", index);
2754+ ccs_set_string(head, comment ? comment->name : "");
2755+ ccs_set_lf(head);
2756+ ccs_print_namespace(head);
2757+ ccs_io_printf(head, "%u-PREFERENCE={ ", index);
2758+ for (i = 0; i < CCS_MAX_PREF; i++)
2759+ ccs_io_printf(head, "%s=%u ",
2760+ ccs_pref_keywords[i],
2761+ profile->pref[i]);
2762+ ccs_set_string(head, "}\n");
2763+ head->r.step++;
2764+ }
2765+ break;
2766+ case 3:
2767+ {
2768+ ccs_print_namespace(head);
2769+ ccs_io_printf(head, "%u-%s", index, "CONFIG");
2770+ ccs_print_config(head, profile->default_config);
2771+ head->r.bit = 0;
2772+ head->r.step++;
2773+ }
2774+ break;
2775+ case 4:
2776+ for ( ; head->r.bit < CCS_MAX_MAC_INDEX
2777+ + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
2778+ const u8 i = head->r.bit;
2779+ const u8 config = profile->config[i];
2780+ if (config == CCS_CONFIG_USE_DEFAULT)
2781+ continue;
2782+ ccs_print_namespace(head);
2783+ if (i < CCS_MAX_MAC_INDEX)
2784+ ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
2785+ ccs_category_keywords
2786+ [ccs_index2category[i]],
2787+ ccs_mac_keywords[i]);
2788+ else
2789+ ccs_io_printf(head, "%u-CONFIG::%s", index,
2790+ ccs_mac_keywords[i]);
2791+ ccs_print_config(head, config);
2792+ head->r.bit++;
2793+ break;
2794+ }
2795+ if (head->r.bit == CCS_MAX_MAC_INDEX
2796+ + CCS_MAX_MAC_CATEGORY_INDEX) {
2797+ head->r.index++;
2798+ head->r.step = 1;
2799+ }
2800+ break;
2801+ }
2802+ if (ccs_flush(head))
2803+ goto next;
2804+}
2805+
2806+/**
2807+ * ccs_update_policy - Update an entry for exception policy.
2808+ *
2809+ * @size: Size of new entry in bytes.
2810+ * @param: Pointer to "struct ccs_acl_param".
2811+ *
2812+ * Returns 0 on success, negative value otherwise.
2813+ *
2814+ * Caller holds ccs_read_lock().
2815+ */
2816+static int ccs_update_policy(const int size, struct ccs_acl_param *param)
2817+{
2818+ struct ccs_acl_head *new_entry = &param->e.acl_head;
2819+ int error = param->is_delete ? -ENOENT : -ENOMEM;
2820+ struct ccs_acl_head *entry;
2821+ struct list_head *list = param->list;
2822+ BUG_ON(size < sizeof(*entry));
2823+ if (mutex_lock_interruptible(&ccs_policy_lock))
2824+ return -ENOMEM;
2825+ list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
2826+ if (entry->is_deleted == CCS_GC_IN_PROGRESS)
2827+ continue;
2828+ if (memcmp(entry + 1, new_entry + 1, size - sizeof(*entry)))
2829+ continue;
2830+ entry->is_deleted = param->is_delete;
2831+ error = 0;
2832+ break;
2833+ }
2834+ if (error && !param->is_delete) {
2835+ entry = ccs_commit_ok(new_entry, size);
2836+ if (entry) {
2837+ list_add_tail_rcu(&entry->list, list);
2838+ error = 0;
2839+ }
2840+ }
2841+ mutex_unlock(&ccs_policy_lock);
2842+ return error;
2843+}
2844+
2845+/**
2846+ * ccs_update_manager_entry - Add a manager entry.
2847+ *
2848+ * @manager: The path to manager or the domainnamme.
2849+ * @is_delete: True if it is a delete request.
2850+ *
2851+ * Returns 0 on success, negative value otherwise.
2852+ */
2853+static int ccs_update_manager_entry(const char *manager,
2854+ const bool is_delete)
2855+{
2856+ struct ccs_acl_param param = {
2857+ /* .ns = &ccs_kernel_namespace, */
2858+ .is_delete = is_delete,
2859+ .list = &ccs_kernel_namespace.policy_list[CCS_ID_MANAGER],
2860+ };
2861+ struct ccs_manager *e = &param.e.manager;
2862+ int error = is_delete ? -ENOENT : -ENOMEM;
2863+ /* Forced zero clear for using memcmp() at ccs_update_policy(). */
2864+ memset(&param.e, 0, sizeof(param.e));
2865+ if (!ccs_correct_domain(manager) && !ccs_correct_word(manager))
2866+ return -EINVAL;
2867+ e->manager = ccs_get_name(manager);
2868+ if (e->manager) {
2869+ error = ccs_update_policy(sizeof(*e), &param);
2870+ ccs_put_name(e->manager);
2871+ }
2872+ return error;
2873+}
2874+
2875+/**
2876+ * ccs_write_manager - Write manager policy.
2877+ *
2878+ * @head: Pointer to "struct ccs_io_buffer".
2879+ *
2880+ * Returns 0 on success, negative value otherwise.
2881+ */
2882+static int ccs_write_manager(struct ccs_io_buffer *head)
2883+{
2884+ const char *data = head->write_buf;
2885+ if (!strcmp(data, "manage_by_non_root")) {
2886+ ccs_manage_by_non_root = !head->w.is_delete;
2887+ return 0;
2888+ }
2889+ return ccs_update_manager_entry(data, head->w.is_delete);
2890+}
2891+
2892+/**
2893+ * ccs_read_manager - Read manager policy.
2894+ *
2895+ * @head: Pointer to "struct ccs_io_buffer".
2896+ *
2897+ * Returns nothing.
2898+ *
2899+ * Caller holds ccs_read_lock().
2900+ */
2901+static void ccs_read_manager(struct ccs_io_buffer *head)
2902+{
2903+ if (head->r.eof)
2904+ return;
2905+ list_for_each_cookie(head->r.acl, &ccs_kernel_namespace.
2906+ policy_list[CCS_ID_MANAGER]) {
2907+ struct ccs_manager *ptr =
2908+ list_entry(head->r.acl, typeof(*ptr), head.list);
2909+ if (ptr->head.is_deleted)
2910+ continue;
2911+ if (!ccs_flush(head))
2912+ return;
2913+ ccs_set_string(head, ptr->manager->name);
2914+ ccs_set_lf(head);
2915+ }
2916+ head->r.eof = true;
2917+}
2918+
2919+/**
2920+ * ccs_manager - Check whether the current process is a policy manager.
2921+ *
2922+ * Returns true if the current process is permitted to modify policy
2923+ * via /proc/ccs/ interface.
2924+ *
2925+ * Caller holds ccs_read_lock().
2926+ */
2927+static bool ccs_manager(void)
2928+{
2929+ struct ccs_manager *ptr;
2930+ struct ccs_path_info exe;
2931+ struct ccs_security *task = ccs_current_security();
2932+ const struct ccs_path_info *domainname
2933+ = ccs_current_domain()->domainname;
2934+ bool found = false;
2935+ if (!ccs_policy_loaded)
2936+ return true;
2937+ if (task->ccs_flags & CCS_TASK_IS_MANAGER)
2938+ return true;
2939+ if (!ccs_manage_by_non_root &&
2940+ (!uid_eq(current_uid(), GLOBAL_ROOT_UID) ||
2941+ !uid_eq(current_euid(), GLOBAL_ROOT_UID)))
2942+ return false;
2943+ exe.name = ccs_get_exe();
2944+ if (!exe.name)
2945+ return false;
2946+ ccs_fill_path_info(&exe);
2947+ list_for_each_entry_srcu(ptr, &ccs_kernel_namespace.
2948+ policy_list[CCS_ID_MANAGER], head.list,
2949+ &ccs_ss) {
2950+ if (ptr->head.is_deleted)
2951+ continue;
2952+ if (ccs_pathcmp(domainname, ptr->manager) &&
2953+ ccs_pathcmp(&exe, ptr->manager))
2954+ continue;
2955+ /* Set manager flag. */
2956+ task->ccs_flags |= CCS_TASK_IS_MANAGER;
2957+ found = true;
2958+ break;
2959+ }
2960+ if (!found) { /* Reduce error messages. */
2961+ static pid_t ccs_last_pid;
2962+ const pid_t pid = current->pid;
2963+ if (ccs_last_pid != pid) {
2964+ printk(KERN_WARNING "%s ( %s ) is not permitted to "
2965+ "update policies.\n", domainname->name,
2966+ exe.name);
2967+ ccs_last_pid = pid;
2968+ }
2969+ }
2970+ kfree(exe.name);
2971+ return found;
2972+}
2973+
2974+/**
2975+ * ccs_find_domain - Find a domain by the given name.
2976+ *
2977+ * @domainname: The domainname to find.
2978+ *
2979+ * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
2980+ *
2981+ * Caller holds ccs_read_lock().
2982+ */
2983+static struct ccs_domain_info *ccs_find_domain(const char *domainname)
2984+{
2985+ struct ccs_domain_info *domain;
2986+ struct ccs_path_info name;
2987+ name.name = domainname;
2988+ ccs_fill_path_info(&name);
2989+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2990+ if (!domain->is_deleted &&
2991+ !ccs_pathcmp(&name, domain->domainname))
2992+ return domain;
2993+ }
2994+ return NULL;
2995+}
2996+
2997+/**
2998+ * ccs_select_domain - Parse select command.
2999+ *
3000+ * @head: Pointer to "struct ccs_io_buffer".
3001+ * @data: String to parse.
3002+ *
3003+ * Returns true on success, false otherwise.
3004+ *
3005+ * Caller holds ccs_read_lock().
3006+ */
3007+static bool ccs_select_domain(struct ccs_io_buffer *head, const char *data)
3008+{
3009+ unsigned int pid;
3010+ struct ccs_domain_info *domain = NULL;
3011+ bool global_pid = false;
3012+ if (strncmp(data, "select ", 7))
3013+ return false;
3014+ data += 7;
3015+ if (sscanf(data, "pid=%u", &pid) == 1 ||
3016+ (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
3017+ struct task_struct *p;
3018+ ccs_tasklist_lock();
3019+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3020+ if (global_pid)
3021+ p = ccsecurity_exports.find_task_by_pid_ns(pid,
3022+ &init_pid_ns);
3023+ else
3024+ p = ccsecurity_exports.find_task_by_vpid(pid);
3025+#else
3026+ p = find_task_by_pid(pid);
3027+#endif
3028+ if (p)
3029+ domain = ccs_task_domain(p);
3030+ ccs_tasklist_unlock();
3031+ } else if (!strncmp(data, "domain=", 7)) {
3032+ if (*(data + 7) == '<')
3033+ domain = ccs_find_domain(data + 7);
3034+ } else if (sscanf(data, "Q=%u", &pid) == 1) {
3035+ domain = ccs_find_domain_by_qid(pid);
3036+ } else
3037+ return false;
3038+ head->w.domain = domain;
3039+ /* Accessing read_buf is safe because head->io_sem is held. */
3040+ if (!head->read_buf)
3041+ return true; /* Do nothing if open(O_WRONLY). */
3042+ memset(&head->r, 0, sizeof(head->r));
3043+ head->r.print_this_domain_only = true;
3044+ if (domain)
3045+ head->r.domain = &domain->list;
3046+ else
3047+ head->r.eof = true;
3048+ ccs_io_printf(head, "# select %s\n", data);
3049+ if (domain && domain->is_deleted)
3050+ ccs_set_string(head, "# This is a deleted domain.\n");
3051+ return true;
3052+}
3053+
3054+/**
3055+ * ccs_update_acl - Update "struct ccs_acl_info" entry.
3056+ *
3057+ * @size: Size of new entry in bytes.
3058+ * @param: Pointer to "struct ccs_acl_param".
3059+ *
3060+ * Returns 0 on success, negative value otherwise.
3061+ *
3062+ * Caller holds ccs_read_lock().
3063+ */
3064+static int ccs_update_acl(const int size, struct ccs_acl_param *param)
3065+{
3066+ struct ccs_acl_info *new_entry = &param->e.acl_info;
3067+ const bool is_delete = param->is_delete;
3068+ int error = is_delete ? -ENOENT : -ENOMEM;
3069+ struct ccs_acl_info *entry;
3070+ struct list_head * const list = param->list;
3071+ BUG_ON(size < sizeof(*entry));
3072+ if (param->data[0]) {
3073+ new_entry->cond = ccs_get_condition(param);
3074+ if (!new_entry->cond)
3075+ return -EINVAL;
3076+ /*
3077+ * Domain transition preference is allowed for only
3078+ * "file execute"/"task auto_execute_handler"/
3079+ * "task denied_auto_execute_handler" entries.
3080+ */
3081+ if (new_entry->cond->exec_transit &&
3082+ !(new_entry->type == CCS_TYPE_PATH_ACL &&
3083+ new_entry->perm == 1 << CCS_TYPE_EXECUTE)
3084+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3085+ && new_entry->type != CCS_TYPE_AUTO_EXECUTE_HANDLER &&
3086+ new_entry->type != CCS_TYPE_DENIED_EXECUTE_HANDLER
3087+#endif
3088+ )
3089+ return -EINVAL;
3090+ }
3091+ if (mutex_lock_interruptible(&ccs_policy_lock))
3092+ return -ENOMEM;
3093+ list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
3094+ if (entry->is_deleted == CCS_GC_IN_PROGRESS)
3095+ continue;
3096+ if (entry->type != new_entry->type ||
3097+ entry->cond != new_entry->cond ||
3098+ memcmp(entry + 1, new_entry + 1, size - sizeof(*entry)))
3099+ continue;
3100+ if (is_delete)
3101+ entry->perm &= ~new_entry->perm;
3102+ else
3103+ entry->perm |= new_entry->perm;
3104+ entry->is_deleted = !entry->perm;
3105+ error = 0;
3106+ break;
3107+ }
3108+ if (error && !is_delete) {
3109+ entry = ccs_commit_ok(new_entry, size);
3110+ if (entry) {
3111+ list_add_tail_rcu(&entry->list, list);
3112+ error = 0;
3113+ }
3114+ }
3115+ mutex_unlock(&ccs_policy_lock);
3116+ return error;
3117+}
3118+
3119+/**
3120+ * ccs_permstr - Find permission keywords.
3121+ *
3122+ * @string: String representation for permissions in foo/bar/buz format.
3123+ * @keyword: Keyword to find from @string/
3124+ *
3125+ * Returns ture if @keyword was found in @string, false otherwise.
3126+ *
3127+ * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
3128+ */
3129+static bool ccs_permstr(const char *string, const char *keyword)
3130+{
3131+ const char *cp = strstr(string, keyword);
3132+ if (cp)
3133+ return cp == string || *(cp - 1) == '/';
3134+ return false;
3135+}
3136+
3137+/**
3138+ * ccs_write_task - Update task related list.
3139+ *
3140+ * @param: Pointer to "struct ccs_acl_param".
3141+ *
3142+ * Returns 0 on success, negative value otherwise.
3143+ *
3144+ * Caller holds ccs_read_lock().
3145+ */
3146+static int ccs_write_task(struct ccs_acl_param *param)
3147+{
3148+ int error;
3149+ const bool is_auto = ccs_str_starts(&param->data,
3150+ "auto_domain_transition ");
3151+ if (!is_auto && !ccs_str_starts(&param->data,
3152+ "manual_domain_transition ")) {
3153+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3154+ struct ccs_handler_acl *e = &param->e.handler_acl;
3155+ char *handler;
3156+ if (ccs_str_starts(&param->data, "auto_execute_handler "))
3157+ e->head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
3158+ else if (ccs_str_starts(&param->data,
3159+ "denied_execute_handler "))
3160+ e->head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
3161+ else
3162+ return -EINVAL;
3163+ handler = ccs_read_token(param);
3164+ if (!ccs_correct_path(handler))
3165+ return -EINVAL;
3166+ e->handler = ccs_get_name(handler);
3167+ if (!e->handler)
3168+ return -ENOMEM;
3169+ if (e->handler->is_patterned)
3170+ return -EINVAL; /* No patterns allowed. */
3171+ return ccs_update_acl(sizeof(*e), param);
3172+#else
3173+ error = -EINVAL;
3174+#endif
3175+ } else {
3176+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
3177+ struct ccs_task_acl *e = &param->e.task_acl;
3178+ e->head.type = is_auto ?
3179+ CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL;
3180+ e->domainname = ccs_get_domainname(param);
3181+ if (!e->domainname)
3182+ return -EINVAL;
3183+ return ccs_update_acl(sizeof(*e), param);
3184+#else
3185+ error = -EINVAL;
3186+#endif
3187+ }
3188+ return error;
3189+}
3190+
3191+#ifdef CONFIG_CCSECURITY_NETWORK
3192+
3193+/**
3194+ * ccs_write_inet_network - Write "struct ccs_inet_acl" list.
3195+ *
3196+ * @param: Pointer to "struct ccs_acl_param".
3197+ *
3198+ * Returns 0 on success, negative value otherwise.
3199+ *
3200+ * Caller holds ccs_read_lock().
3201+ */
3202+static int ccs_write_inet_network(struct ccs_acl_param *param)
3203+{
3204+ struct ccs_inet_acl *e = &param->e.inet_acl;
3205+ u8 type;
3206+ const char *protocol = ccs_read_token(param);
3207+ const char *operation = ccs_read_token(param);
3208+ e->head.type = CCS_TYPE_INET_ACL;
3209+ for (type = 0; type < CCS_SOCK_MAX; type++)
3210+ if (!strcmp(protocol, ccs_proto_keyword[type]))
3211+ break;
3212+ if (type == CCS_SOCK_MAX)
3213+ return -EINVAL;
3214+ e->protocol = type;
3215+ e->head.perm = 0;
3216+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
3217+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
3218+ e->head.perm |= 1 << type;
3219+ if (!e->head.perm)
3220+ return -EINVAL;
3221+ if (param->data[0] == '@') {
3222+ param->data++;
3223+ e->address.group = ccs_get_group(param, CCS_ADDRESS_GROUP);
3224+ if (!e->address.group)
3225+ return -ENOMEM;
3226+ } else {
3227+ if (!ccs_parse_ipaddr_union(param, &e->address))
3228+ return -EINVAL;
3229+ }
3230+ if (!ccs_parse_number_union(param, &e->port) ||
3231+ e->port.values[1] > 65535)
3232+ return -EINVAL;
3233+ return ccs_update_acl(sizeof(*e), param);
3234+}
3235+
3236+/**
3237+ * ccs_write_unix_network - Write "struct ccs_unix_acl" list.
3238+ *
3239+ * @param: Pointer to "struct ccs_acl_param".
3240+ *
3241+ * Returns 0 on success, negative value otherwise.
3242+ */
3243+static int ccs_write_unix_network(struct ccs_acl_param *param)
3244+{
3245+ struct ccs_unix_acl *e = &param->e.unix_acl;
3246+ u8 type;
3247+ const char *protocol = ccs_read_token(param);
3248+ const char *operation = ccs_read_token(param);
3249+ e->head.type = CCS_TYPE_UNIX_ACL;
3250+ for (type = 0; type < CCS_SOCK_MAX; type++)
3251+ if (!strcmp(protocol, ccs_proto_keyword[type]))
3252+ break;
3253+ if (type == CCS_SOCK_MAX)
3254+ return -EINVAL;
3255+ e->protocol = type;
3256+ e->head.perm = 0;
3257+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
3258+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
3259+ e->head.perm |= 1 << type;
3260+ if (!e->head.perm)
3261+ return -EINVAL;
3262+ if (!ccs_parse_name_union(param, &e->name))
3263+ return -EINVAL;
3264+ return ccs_update_acl(sizeof(*e), param);
3265+}
3266+
3267+#endif
3268+
3269+/**
3270+ * ccs_write_file - Update file related list.
3271+ *
3272+ * @param: Pointer to "struct ccs_acl_param".
3273+ *
3274+ * Returns 0 on success, negative value otherwise.
3275+ *
3276+ * Caller holds ccs_read_lock().
3277+ */
3278+static int ccs_write_file(struct ccs_acl_param *param)
3279+{
3280+ u16 perm = 0;
3281+ u8 type;
3282+ const char *operation = ccs_read_token(param);
3283+ for (type = 0; type < CCS_MAX_PATH_OPERATION; type++)
3284+ if (ccs_permstr(operation, ccs_path_keyword[type]))
3285+ perm |= 1 << type;
3286+ if (perm) {
3287+ struct ccs_path_acl *e = &param->e.path_acl;
3288+ e->head.type = CCS_TYPE_PATH_ACL;
3289+ e->head.perm = perm;
3290+ if (!ccs_parse_name_union(param, &e->name))
3291+ return -EINVAL;
3292+ return ccs_update_acl(sizeof(*e), param);
3293+ }
3294+ for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++)
3295+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pp2mac[type]]))
3296+ perm |= 1 << type;
3297+ if (perm) {
3298+ struct ccs_path2_acl *e = &param->e.path2_acl;
3299+ e->head.type = CCS_TYPE_PATH2_ACL;
3300+ e->head.perm = perm;
3301+ if (!ccs_parse_name_union(param, &e->name1) ||
3302+ !ccs_parse_name_union(param, &e->name2))
3303+ return -EINVAL;
3304+ return ccs_update_acl(sizeof(*e), param);
3305+ }
3306+ for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++)
3307+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pn2mac[type]]))
3308+ perm |= 1 << type;
3309+ if (perm) {
3310+ struct ccs_path_number_acl *e = &param->e.path_number_acl;
3311+ e->head.type = CCS_TYPE_PATH_NUMBER_ACL;
3312+ e->head.perm = perm;
3313+ if (!ccs_parse_name_union(param, &e->name) ||
3314+ !ccs_parse_number_union(param, &e->number))
3315+ return -EINVAL;
3316+ return ccs_update_acl(sizeof(*e), param);
3317+ }
3318+ for (type = 0; type < CCS_MAX_MKDEV_OPERATION; type++)
3319+ if (ccs_permstr(operation,
3320+ ccs_mac_keywords[ccs_pnnn2mac[type]]))
3321+ perm |= 1 << type;
3322+ if (perm) {
3323+ struct ccs_mkdev_acl *e = &param->e.mkdev_acl;
3324+ e->head.type = CCS_TYPE_MKDEV_ACL;
3325+ e->head.perm = perm;
3326+ if (!ccs_parse_name_union(param, &e->name) ||
3327+ !ccs_parse_number_union(param, &e->mode) ||
3328+ !ccs_parse_number_union(param, &e->major) ||
3329+ !ccs_parse_number_union(param, &e->minor))
3330+ return -EINVAL;
3331+ return ccs_update_acl(sizeof(*e), param);
3332+ }
3333+ if (ccs_permstr(operation, ccs_mac_keywords[CCS_MAC_FILE_MOUNT])) {
3334+ struct ccs_mount_acl *e = &param->e.mount_acl;
3335+ e->head.type = CCS_TYPE_MOUNT_ACL;
3336+ if (!ccs_parse_name_union(param, &e->dev_name) ||
3337+ !ccs_parse_name_union(param, &e->dir_name) ||
3338+ !ccs_parse_name_union(param, &e->fs_type) ||
3339+ !ccs_parse_number_union(param, &e->flags))
3340+ return -EINVAL;
3341+ return ccs_update_acl(sizeof(*e), param);
3342+ }
3343+ return -EINVAL;
3344+}
3345+
3346+#ifdef CONFIG_CCSECURITY_MISC
3347+
3348+/**
3349+ * ccs_write_misc - Update environment variable list.
3350+ *
3351+ * @param: Pointer to "struct ccs_acl_param".
3352+ *
3353+ * Returns 0 on success, negative value otherwise.
3354+ */
3355+static int ccs_write_misc(struct ccs_acl_param *param)
3356+{
3357+ if (ccs_str_starts(&param->data, "env ")) {
3358+ struct ccs_env_acl *e = &param->e.env_acl;
3359+ const char *data = ccs_read_token(param);
3360+ e->head.type = CCS_TYPE_ENV_ACL;
3361+ if (!ccs_correct_word(data) || strchr(data, '='))
3362+ return -EINVAL;
3363+ e->env = ccs_get_name(data);
3364+ if (!e->env)
3365+ return -ENOMEM;
3366+ return ccs_update_acl(sizeof(*e), param);
3367+ }
3368+ return -EINVAL;
3369+}
3370+
3371+#endif
3372+
3373+#ifdef CONFIG_CCSECURITY_IPC
3374+
3375+/**
3376+ * ccs_write_ipc - Update "struct ccs_signal_acl" list.
3377+ *
3378+ * @param: Pointer to "struct ccs_acl_param".
3379+ *
3380+ * Returns 0 on success, negative value otherwise.
3381+ */
3382+static int ccs_write_ipc(struct ccs_acl_param *param)
3383+{
3384+ struct ccs_signal_acl *e = &param->e.signal_acl;
3385+ e->head.type = CCS_TYPE_SIGNAL_ACL;
3386+ if (!ccs_parse_number_union(param, &e->sig))
3387+ return -EINVAL;
3388+ e->domainname = ccs_get_domainname(param);
3389+ if (!e->domainname)
3390+ return -EINVAL;
3391+ return ccs_update_acl(sizeof(*e), param);
3392+}
3393+
3394+#endif
3395+
3396+#ifdef CONFIG_CCSECURITY_CAPABILITY
3397+
3398+/**
3399+ * ccs_write_capability - Write "struct ccs_capability_acl" list.
3400+ *
3401+ * @param: Pointer to "struct ccs_acl_param".
3402+ *
3403+ * Returns 0 on success, negative value otherwise.
3404+ *
3405+ * Caller holds ccs_read_lock().
3406+ */
3407+static int ccs_write_capability(struct ccs_acl_param *param)
3408+{
3409+ struct ccs_capability_acl *e = &param->e.capability_acl;
3410+ const char *operation = ccs_read_token(param);
3411+ u8 type;
3412+ e->head.type = CCS_TYPE_CAPABILITY_ACL;
3413+ for (type = 0; type < CCS_MAX_CAPABILITY_INDEX; type++) {
3414+ if (strcmp(operation, ccs_mac_keywords[ccs_c2mac[type]]))
3415+ continue;
3416+ e->operation = type;
3417+ return ccs_update_acl(sizeof(*e), param);
3418+ }
3419+ return -EINVAL;
3420+}
3421+
3422+#endif
3423+
3424+/**
3425+ * ccs_write_acl - Write "struct ccs_acl_info" list.
3426+ *
3427+ * @ns: Pointer to "struct ccs_policy_namespace".
3428+ * @list: Pointer to "struct list_head".
3429+ * @data: Policy to be interpreted.
3430+ * @is_delete: True if it is a delete request.
3431+ *
3432+ * Returns 0 on success, negative value otherwise.
3433+ *
3434+ * Caller holds ccs_read_lock().
3435+ */
3436+static int ccs_write_acl(struct ccs_policy_namespace *ns,
3437+ struct list_head *list, char *data,
3438+ const bool is_delete)
3439+{
3440+ struct ccs_acl_param param = {
3441+ .ns = ns,
3442+ .list = list,
3443+ .data = data,
3444+ .is_delete = is_delete,
3445+ };
3446+ static const struct {
3447+ const char *keyword;
3448+ int (*write) (struct ccs_acl_param *);
3449+ } ccs_callback[] = {
3450+ { "file ", ccs_write_file },
3451+#ifdef CONFIG_CCSECURITY_NETWORK
3452+ { "network inet ", ccs_write_inet_network },
3453+ { "network unix ", ccs_write_unix_network },
3454+#endif
3455+#ifdef CONFIG_CCSECURITY_MISC
3456+ { "misc ", ccs_write_misc },
3457+#endif
3458+#ifdef CONFIG_CCSECURITY_CAPABILITY
3459+ { "capability ", ccs_write_capability },
3460+#endif
3461+#ifdef CONFIG_CCSECURITY_IPC
3462+ { "ipc signal ", ccs_write_ipc },
3463+#endif
3464+ { "task ", ccs_write_task },
3465+ };
3466+ u8 i;
3467+ /* Forced zero clear for using memcmp() at ccs_update_acl(). */
3468+ memset(&param.e, 0, sizeof(param.e));
3469+ param.e.acl_info.perm = 1;
3470+ for (i = 0; i < ARRAY_SIZE(ccs_callback); i++) {
3471+ int error;
3472+ if (!ccs_str_starts(&param.data, ccs_callback[i].keyword))
3473+ continue;
3474+ error = ccs_callback[i].write(&param);
3475+ ccs_del_acl(&param.e.acl_info.list);
3476+ return error;
3477+ }
3478+ return -EINVAL;
3479+}
3480+
3481+/**
3482+ * ccs_delete_domain - Delete a domain.
3483+ *
3484+ * @domainname: The name of domain.
3485+ *
3486+ * Returns 0.
3487+ */
3488+static int ccs_delete_domain(char *domainname)
3489+{
3490+ struct ccs_domain_info *domain;
3491+ struct ccs_path_info name;
3492+ name.name = domainname;
3493+ ccs_fill_path_info(&name);
3494+ if (mutex_lock_interruptible(&ccs_policy_lock))
3495+ return 0;
3496+ /* Is there an active domain? */
3497+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
3498+ /* Never delete ccs_kernel_domain. */
3499+ if (domain == &ccs_kernel_domain)
3500+ continue;
3501+ if (domain->is_deleted ||
3502+ ccs_pathcmp(domain->domainname, &name))
3503+ continue;
3504+ domain->is_deleted = true;
3505+ break;
3506+ }
3507+ mutex_unlock(&ccs_policy_lock);
3508+ return 0;
3509+}
3510+
3511+/**
3512+ * ccs_write_domain - Write domain policy.
3513+ *
3514+ * @head: Pointer to "struct ccs_io_buffer".
3515+ *
3516+ * Returns 0 on success, negative value otherwise.
3517+ *
3518+ * Caller holds ccs_read_lock().
3519+ */
3520+static int ccs_write_domain(struct ccs_io_buffer *head)
3521+{
3522+ char *data = head->write_buf;
3523+ struct ccs_policy_namespace *ns;
3524+ struct ccs_domain_info *domain = head->w.domain;
3525+ const bool is_delete = head->w.is_delete;
3526+ const bool is_select = !is_delete && ccs_str_starts(&data, "select ");
3527+ unsigned int idx;
3528+ if (*data == '<') {
3529+ domain = NULL;
3530+ if (is_delete)
3531+ ccs_delete_domain(data);
3532+ else if (is_select)
3533+ domain = ccs_find_domain(data);
3534+ else
3535+ domain = ccs_assign_domain(data, false);
3536+ head->w.domain = domain;
3537+ return 0;
3538+ }
3539+ if (!domain)
3540+ return -EINVAL;
3541+ ns = domain->ns;
3542+ if (sscanf(data, "use_profile %u\n", &idx) == 1 &&
3543+ idx < CCS_MAX_PROFILES) {
3544+ if (!ccs_policy_loaded || ns->profile_ptr[(u8) idx])
3545+ if (!is_delete)
3546+ domain->profile = (u8) idx;
3547+ return 0;
3548+ }
3549+ if (sscanf(data, "use_group %u\n", &idx) == 1 &&
3550+ idx < CCS_MAX_ACL_GROUPS) {
3551+ if (!is_delete)
3552+ domain->group = (u8) idx;
3553+ return 0;
3554+ }
3555+ for (idx = 0; idx < CCS_MAX_DOMAIN_INFO_FLAGS; idx++) {
3556+ const char *cp = ccs_dif[idx];
3557+ if (strncmp(data, cp, strlen(cp) - 1))
3558+ continue;
3559+ domain->flags[idx] = !is_delete;
3560+ return 0;
3561+ }
3562+ return ccs_write_acl(ns, &domain->acl_info_list, data, is_delete);
3563+}
3564+
3565+/**
3566+ * ccs_print_name_union - Print a ccs_name_union.
3567+ *
3568+ * @head: Pointer to "struct ccs_io_buffer".
3569+ * @ptr: Pointer to "struct ccs_name_union".
3570+ *
3571+ * Returns nothing.
3572+ */
3573+static void ccs_print_name_union(struct ccs_io_buffer *head,
3574+ const struct ccs_name_union *ptr)
3575+{
3576+ ccs_set_space(head);
3577+ if (!ccs_print_group(head, ptr->group))
3578+ ccs_set_string(head, ptr->filename->name);
3579+}
3580+
3581+/**
3582+ * ccs_print_name_union_quoted - Print a ccs_name_union with a quote.
3583+ *
3584+ * @head: Pointer to "struct ccs_io_buffer".
3585+ * @ptr: Pointer to "struct ccs_name_union".
3586+ *
3587+ * Returns nothing.
3588+ */
3589+static void ccs_print_name_union_quoted(struct ccs_io_buffer *head,
3590+ const struct ccs_name_union *ptr)
3591+{
3592+ if (!ccs_print_group(head, ptr->group)) {
3593+ ccs_set_string(head, "\"");
3594+ ccs_set_string(head, ptr->filename->name);
3595+ ccs_set_string(head, "\"");
3596+ }
3597+}
3598+
3599+/**
3600+ * ccs_print_number_union_nospace - Print a ccs_number_union without a space.
3601+ *
3602+ * @head: Pointer to "struct ccs_io_buffer".
3603+ * @ptr: Pointer to "struct ccs_number_union".
3604+ *
3605+ * Returns nothing.
3606+ */
3607+static void ccs_print_number_union_nospace(struct ccs_io_buffer *head,
3608+ const struct ccs_number_union *ptr)
3609+{
3610+ if (!ccs_print_group(head, ptr->group)) {
3611+ int i;
3612+ unsigned long min = ptr->values[0];
3613+ const unsigned long max = ptr->values[1];
3614+ u8 min_type = ptr->value_type[0];
3615+ const u8 max_type = ptr->value_type[1];
3616+ char buffer[128];
3617+ buffer[0] = '\0';
3618+ for (i = 0; i < 2; i++) {
3619+ switch (min_type) {
3620+ case CCS_VALUE_TYPE_HEXADECIMAL:
3621+ ccs_addprintf(buffer, sizeof(buffer), "0x%lX",
3622+ min);
3623+ break;
3624+ case CCS_VALUE_TYPE_OCTAL:
3625+ ccs_addprintf(buffer, sizeof(buffer), "0%lo",
3626+ min);
3627+ break;
3628+ default:
3629+ ccs_addprintf(buffer, sizeof(buffer), "%lu",
3630+ min);
3631+ break;
3632+ }
3633+ if (min == max && min_type == max_type)
3634+ break;
3635+ ccs_addprintf(buffer, sizeof(buffer), "-");
3636+ min_type = max_type;
3637+ min = max;
3638+ }
3639+ ccs_io_printf(head, "%s", buffer);
3640+ }
3641+}
3642+
3643+/**
3644+ * ccs_print_number_union - Print a ccs_number_union.
3645+ *
3646+ * @head: Pointer to "struct ccs_io_buffer".
3647+ * @ptr: Pointer to "struct ccs_number_union".
3648+ *
3649+ * Returns nothing.
3650+ */
3651+static void ccs_print_number_union(struct ccs_io_buffer *head,
3652+ const struct ccs_number_union *ptr)
3653+{
3654+ ccs_set_space(head);
3655+ ccs_print_number_union_nospace(head, ptr);
3656+}
3657+
3658+/**
3659+ * ccs_print_condition - Print condition part.
3660+ *
3661+ * @head: Pointer to "struct ccs_io_buffer".
3662+ * @cond: Pointer to "struct ccs_condition".
3663+ *
3664+ * Returns true on success, false otherwise.
3665+ */
3666+static bool ccs_print_condition(struct ccs_io_buffer *head,
3667+ const struct ccs_condition *cond)
3668+{
3669+ switch (head->r.cond_step) {
3670+ case 0:
3671+ head->r.cond_index = 0;
3672+ head->r.cond_step++;
3673+ if (cond->transit && cond->exec_transit) {
3674+ ccs_set_space(head);
3675+ ccs_set_string(head, cond->transit->name);
3676+ }
3677+ /* fall through */
3678+ case 1:
3679+ {
3680+ const u16 condc = cond->condc;
3681+ const struct ccs_condition_element *condp =
3682+ (typeof(condp)) (cond + 1);
3683+ const struct ccs_number_union *numbers_p =
3684+ (typeof(numbers_p)) (condp + condc);
3685+ const struct ccs_name_union *names_p =
3686+ (typeof(names_p))
3687+ (numbers_p + cond->numbers_count);
3688+ const struct ccs_argv *argv =
3689+ (typeof(argv)) (names_p + cond->names_count);
3690+ const struct ccs_envp *envp =
3691+ (typeof(envp)) (argv + cond->argc);
3692+ u16 skip;
3693+ for (skip = 0; skip < head->r.cond_index; skip++) {
3694+ const u8 left = condp->left;
3695+ const u8 right = condp->right;
3696+ condp++;
3697+ switch (left) {
3698+ case CCS_ARGV_ENTRY:
3699+ argv++;
3700+ continue;
3701+ case CCS_ENVP_ENTRY:
3702+ envp++;
3703+ continue;
3704+ case CCS_NUMBER_UNION:
3705+ numbers_p++;
3706+ break;
3707+ }
3708+ switch (right) {
3709+ case CCS_NAME_UNION:
3710+ names_p++;
3711+ break;
3712+ case CCS_NUMBER_UNION:
3713+ numbers_p++;
3714+ break;
3715+ }
3716+ }
3717+ while (head->r.cond_index < condc) {
3718+ const u8 match = condp->equals;
3719+ const u8 left = condp->left;
3720+ const u8 right = condp->right;
3721+ if (!ccs_flush(head))
3722+ return false;
3723+ condp++;
3724+ head->r.cond_index++;
3725+ ccs_set_space(head);
3726+ switch (left) {
3727+ case CCS_ARGV_ENTRY:
3728+ ccs_io_printf(head,
3729+ "exec.argv[%lu]%s=\"",
3730+ argv->index,
3731+ argv->is_not ? "!" : "");
3732+ ccs_set_string(head,
3733+ argv->value->name);
3734+ ccs_set_string(head, "\"");
3735+ argv++;
3736+ continue;
3737+ case CCS_ENVP_ENTRY:
3738+ ccs_set_string(head, "exec.envp[\"");
3739+ ccs_set_string(head, envp->name->name);
3740+ ccs_io_printf(head, "\"]%s=",
3741+ envp->is_not ? "!" : "");
3742+ if (envp->value) {
3743+ ccs_set_string(head, "\"");
3744+ ccs_set_string(head, envp->
3745+ value->name);
3746+ ccs_set_string(head, "\"");
3747+ } else {
3748+ ccs_set_string(head, "NULL");
3749+ }
3750+ envp++;
3751+ continue;
3752+ case CCS_NUMBER_UNION:
3753+ ccs_print_number_union_nospace
3754+ (head, numbers_p++);
3755+ break;
3756+ default:
3757+ ccs_set_string(head,
3758+ ccs_condition_keyword[left]);
3759+ break;
3760+ }
3761+ ccs_set_string(head, match ? "=" : "!=");
3762+ switch (right) {
3763+ case CCS_NAME_UNION:
3764+ ccs_print_name_union_quoted
3765+ (head, names_p++);
3766+ break;
3767+ case CCS_NUMBER_UNION:
3768+ ccs_print_number_union_nospace
3769+ (head, numbers_p++);
3770+ break;
3771+ default:
3772+ ccs_set_string(head,
3773+ ccs_condition_keyword[right]);
3774+ break;
3775+ }
3776+ }
3777+ }
3778+ head->r.cond_step++;
3779+ /* fall through */
3780+ case 2:
3781+ if (!ccs_flush(head))
3782+ break;
3783+ head->r.cond_step++;
3784+ /* fall through */
3785+ case 3:
3786+ if (cond->grant_log != CCS_GRANTLOG_AUTO)
3787+ ccs_io_printf(head, " grant_log=%s",
3788+ ccs_yesno(cond->grant_log ==
3789+ CCS_GRANTLOG_YES));
3790+ if (cond->transit && !cond->exec_transit) {
3791+ const char *name = cond->transit->name;
3792+ ccs_set_string(head, " auto_domain_transition=\"");
3793+ ccs_set_string(head, name);
3794+ ccs_set_string(head, "\"");
3795+ }
3796+ ccs_set_lf(head);
3797+ return true;
3798+ }
3799+ return false;
3800+}
3801+
3802+/**
3803+ * ccs_set_group - Print "acl_group " header keyword and category name.
3804+ *
3805+ * @head: Pointer to "struct ccs_io_buffer".
3806+ * @category: Category name.
3807+ *
3808+ * Returns nothing.
3809+ */
3810+static void ccs_set_group(struct ccs_io_buffer *head, const char *category)
3811+{
3812+ if (head->type == CCS_EXCEPTION_POLICY) {
3813+ ccs_print_namespace(head);
3814+ ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index);
3815+ }
3816+ ccs_set_string(head, category);
3817+}
3818+
3819+/**
3820+ * ccs_print_entry - Print an ACL entry.
3821+ *
3822+ * @head: Pointer to "struct ccs_io_buffer".
3823+ * @acl: Pointer to an ACL entry.
3824+ *
3825+ * Returns true on success, false otherwise.
3826+ */
3827+static bool ccs_print_entry(struct ccs_io_buffer *head,
3828+ const struct ccs_acl_info *acl)
3829+{
3830+ const u8 acl_type = acl->type;
3831+ const bool may_trigger_transition = acl->cond && acl->cond->transit;
3832+ bool first = true;
3833+ u8 bit;
3834+ if (head->r.print_cond_part)
3835+ goto print_cond_part;
3836+ if (acl->is_deleted)
3837+ return true;
3838+ if (!ccs_flush(head))
3839+ return false;
3840+ else if (acl_type == CCS_TYPE_PATH_ACL) {
3841+ struct ccs_path_acl *ptr
3842+ = container_of(acl, typeof(*ptr), head);
3843+ for (bit = 0; bit < CCS_MAX_PATH_OPERATION; bit++) {
3844+ if (!(acl->perm & (1 << bit)))
3845+ continue;
3846+ if (head->r.print_transition_related_only &&
3847+ bit != CCS_TYPE_EXECUTE && !may_trigger_transition)
3848+ continue;
3849+ if (first) {
3850+ ccs_set_group(head, "file ");
3851+ first = false;
3852+ } else {
3853+ ccs_set_slash(head);
3854+ }
3855+ ccs_set_string(head, ccs_path_keyword[bit]);
3856+ }
3857+ if (first)
3858+ return true;
3859+ ccs_print_name_union(head, &ptr->name);
3860+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3861+ } else if (acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
3862+ acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {
3863+ struct ccs_handler_acl *ptr
3864+ = container_of(acl, typeof(*ptr), head);
3865+ ccs_set_group(head, "task ");
3866+ ccs_set_string(head, acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER
3867+ ? "auto_execute_handler " :
3868+ "denied_execute_handler ");
3869+ ccs_set_string(head, ptr->handler->name);
3870+#endif
3871+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
3872+ } else if (acl_type == CCS_TYPE_AUTO_TASK_ACL ||
3873+ acl_type == CCS_TYPE_MANUAL_TASK_ACL) {
3874+ struct ccs_task_acl *ptr =
3875+ container_of(acl, typeof(*ptr), head);
3876+ ccs_set_group(head, "task ");
3877+ ccs_set_string(head, acl_type == CCS_TYPE_AUTO_TASK_ACL ?
3878+ "auto_domain_transition " :
3879+ "manual_domain_transition ");
3880+ ccs_set_string(head, ptr->domainname->name);
3881+#endif
3882+ } else if (head->r.print_transition_related_only &&
3883+ !may_trigger_transition) {
3884+ return true;
3885+ } else if (acl_type == CCS_TYPE_MKDEV_ACL) {
3886+ struct ccs_mkdev_acl *ptr =
3887+ container_of(acl, typeof(*ptr), head);
3888+ for (bit = 0; bit < CCS_MAX_MKDEV_OPERATION; bit++) {
3889+ if (!(acl->perm & (1 << bit)))
3890+ continue;
3891+ if (first) {
3892+ ccs_set_group(head, "file ");
3893+ first = false;
3894+ } else {
3895+ ccs_set_slash(head);
3896+ }
3897+ ccs_set_string(head, ccs_mac_keywords
3898+ [ccs_pnnn2mac[bit]]);
3899+ }
3900+ if (first)
3901+ return true;
3902+ ccs_print_name_union(head, &ptr->name);
3903+ ccs_print_number_union(head, &ptr->mode);
3904+ ccs_print_number_union(head, &ptr->major);
3905+ ccs_print_number_union(head, &ptr->minor);
3906+ } else if (acl_type == CCS_TYPE_PATH2_ACL) {
3907+ struct ccs_path2_acl *ptr =
3908+ container_of(acl, typeof(*ptr), head);
3909+ for (bit = 0; bit < CCS_MAX_PATH2_OPERATION; bit++) {
3910+ if (!(acl->perm & (1 << bit)))
3911+ continue;
3912+ if (first) {
3913+ ccs_set_group(head, "file ");
3914+ first = false;
3915+ } else {
3916+ ccs_set_slash(head);
3917+ }
3918+ ccs_set_string(head, ccs_mac_keywords
3919+ [ccs_pp2mac[bit]]);
3920+ }
3921+ if (first)
3922+ return true;
3923+ ccs_print_name_union(head, &ptr->name1);
3924+ ccs_print_name_union(head, &ptr->name2);
3925+ } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {
3926+ struct ccs_path_number_acl *ptr =
3927+ container_of(acl, typeof(*ptr), head);
3928+ for (bit = 0; bit < CCS_MAX_PATH_NUMBER_OPERATION; bit++) {
3929+ if (!(acl->perm & (1 << bit)))
3930+ continue;
3931+ if (first) {
3932+ ccs_set_group(head, "file ");
3933+ first = false;
3934+ } else {
3935+ ccs_set_slash(head);
3936+ }
3937+ ccs_set_string(head, ccs_mac_keywords
3938+ [ccs_pn2mac[bit]]);
3939+ }
3940+ if (first)
3941+ return true;
3942+ ccs_print_name_union(head, &ptr->name);
3943+ ccs_print_number_union(head, &ptr->number);
3944+#ifdef CONFIG_CCSECURITY_MISC
3945+ } else if (acl_type == CCS_TYPE_ENV_ACL) {
3946+ struct ccs_env_acl *ptr =
3947+ container_of(acl, typeof(*ptr), head);
3948+ ccs_set_group(head, "misc env ");
3949+ ccs_set_string(head, ptr->env->name);
3950+#endif
3951+#ifdef CONFIG_CCSECURITY_CAPABILITY
3952+ } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {
3953+ struct ccs_capability_acl *ptr =
3954+ container_of(acl, typeof(*ptr), head);
3955+ ccs_set_group(head, "capability ");
3956+ ccs_set_string(head, ccs_mac_keywords
3957+ [ccs_c2mac[ptr->operation]]);
3958+#endif
3959+#ifdef CONFIG_CCSECURITY_NETWORK
3960+ } else if (acl_type == CCS_TYPE_INET_ACL) {
3961+ struct ccs_inet_acl *ptr =
3962+ container_of(acl, typeof(*ptr), head);
3963+ for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
3964+ if (!(acl->perm & (1 << bit)))
3965+ continue;
3966+ if (first) {
3967+ ccs_set_group(head, "network inet ");
3968+ ccs_set_string(head, ccs_proto_keyword
3969+ [ptr->protocol]);
3970+ ccs_set_space(head);
3971+ first = false;
3972+ } else {
3973+ ccs_set_slash(head);
3974+ }
3975+ ccs_set_string(head, ccs_socket_keyword[bit]);
3976+ }
3977+ if (first)
3978+ return true;
3979+ ccs_set_space(head);
3980+ if (!ccs_print_group(head, ptr->address.group)) {
3981+ char buf[128];
3982+ ccs_print_ip(buf, sizeof(buf), &ptr->address);
3983+ ccs_io_printf(head, "%s", buf);
3984+ }
3985+ ccs_print_number_union(head, &ptr->port);
3986+ } else if (acl_type == CCS_TYPE_UNIX_ACL) {
3987+ struct ccs_unix_acl *ptr =
3988+ container_of(acl, typeof(*ptr), head);
3989+ for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
3990+ if (!(acl->perm & (1 << bit)))
3991+ continue;
3992+ if (first) {
3993+ ccs_set_group(head, "network unix ");
3994+ ccs_set_string(head, ccs_proto_keyword
3995+ [ptr->protocol]);
3996+ ccs_set_space(head);
3997+ first = false;
3998+ } else {
3999+ ccs_set_slash(head);
4000+ }
4001+ ccs_set_string(head, ccs_socket_keyword[bit]);
4002+ }
4003+ if (first)
4004+ return true;
4005+ ccs_print_name_union(head, &ptr->name);
4006+#endif
4007+#ifdef CONFIG_CCSECURITY_IPC
4008+ } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {
4009+ struct ccs_signal_acl *ptr =
4010+ container_of(acl, typeof(*ptr), head);
4011+ ccs_set_group(head, "ipc signal ");
4012+ ccs_print_number_union_nospace(head, &ptr->sig);
4013+ ccs_set_space(head);
4014+ ccs_set_string(head, ptr->domainname->name);
4015+#endif
4016+ } else if (acl_type == CCS_TYPE_MOUNT_ACL) {
4017+ struct ccs_mount_acl *ptr =
4018+ container_of(acl, typeof(*ptr), head);
4019+ ccs_set_group(head, "file mount");
4020+ ccs_print_name_union(head, &ptr->dev_name);
4021+ ccs_print_name_union(head, &ptr->dir_name);
4022+ ccs_print_name_union(head, &ptr->fs_type);
4023+ ccs_print_number_union(head, &ptr->flags);
4024+ }
4025+ if (acl->cond) {
4026+ head->r.print_cond_part = true;
4027+ head->r.cond_step = 0;
4028+ if (!ccs_flush(head))
4029+ return false;
4030+print_cond_part:
4031+ if (!ccs_print_condition(head, acl->cond))
4032+ return false;
4033+ head->r.print_cond_part = false;
4034+ } else {
4035+ ccs_set_lf(head);
4036+ }
4037+ return true;
4038+}
4039+
4040+/**
4041+ * ccs_read_acl - Read "struct ccs_acl_info" list.
4042+ *
4043+ * @head: Pointer to "struct ccs_io_buffer".
4044+ * @list: Pointer to "struct list_head".
4045+ *
4046+ * Returns true on success, false otherwise.
4047+ *
4048+ * Caller holds ccs_read_lock().
4049+ */
4050+static bool ccs_read_acl(struct ccs_io_buffer *head, struct list_head *list)
4051+{
4052+ list_for_each_cookie(head->r.acl, list) {
4053+ struct ccs_acl_info *ptr =
4054+ list_entry(head->r.acl, typeof(*ptr), list);
4055+ if (!ccs_print_entry(head, ptr))
4056+ return false;
4057+ }
4058+ head->r.acl = NULL;
4059+ return true;
4060+}
4061+
4062+/**
4063+ * ccs_read_domain - Read domain policy.
4064+ *
4065+ * @head: Pointer to "struct ccs_io_buffer".
4066+ *
4067+ * Returns nothing.
4068+ *
4069+ * Caller holds ccs_read_lock().
4070+ */
4071+static void ccs_read_domain(struct ccs_io_buffer *head)
4072+{
4073+ if (head->r.eof)
4074+ return;
4075+ list_for_each_cookie(head->r.domain, &ccs_domain_list) {
4076+ struct ccs_domain_info *domain =
4077+ list_entry(head->r.domain, typeof(*domain), list);
4078+ switch (head->r.step) {
4079+ u8 i;
4080+ case 0:
4081+ if (domain->is_deleted &&
4082+ !head->r.print_this_domain_only)
4083+ continue;
4084+ /* Print domainname and flags. */
4085+ ccs_set_string(head, domain->domainname->name);
4086+ ccs_set_lf(head);
4087+ ccs_io_printf(head, "use_profile %u\n",
4088+ domain->profile);
4089+ ccs_io_printf(head, "use_group %u\n", domain->group);
4090+ for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)
4091+ if (domain->flags[i])
4092+ ccs_set_string(head, ccs_dif[i]);
4093+ head->r.step++;
4094+ ccs_set_lf(head);
4095+ /* fall through */
4096+ case 1:
4097+ if (!ccs_read_acl(head, &domain->acl_info_list))
4098+ return;
4099+ head->r.step++;
4100+ if (!ccs_set_lf(head))
4101+ return;
4102+ /* fall through */
4103+ case 2:
4104+ head->r.step = 0;
4105+ if (head->r.print_this_domain_only)
4106+ goto done;
4107+ }
4108+ }
4109+done:
4110+ head->r.eof = true;
4111+}
4112+
4113+/**
4114+ * ccs_write_pid - Specify PID to obtain domainname.
4115+ *
4116+ * @head: Pointer to "struct ccs_io_buffer".
4117+ *
4118+ * Returns 0.
4119+ */
4120+static int ccs_write_pid(struct ccs_io_buffer *head)
4121+{
4122+ head->r.eof = false;
4123+ return 0;
4124+}
4125+
4126+/**
4127+ * ccs_read_pid - Read information of a process.
4128+ *
4129+ * @head: Pointer to "struct ccs_io_buffer".
4130+ *
4131+ * Returns the domainname which the specified PID is in or
4132+ * process information of the specified PID on success,
4133+ * empty string otherwise.
4134+ *
4135+ * Caller holds ccs_read_lock().
4136+ */
4137+static void ccs_read_pid(struct ccs_io_buffer *head)
4138+{
4139+ char *buf = head->write_buf;
4140+ bool task_info = false;
4141+ bool global_pid = false;
4142+ unsigned int pid;
4143+ struct task_struct *p;
4144+ struct ccs_domain_info *domain = NULL;
4145+ u32 ccs_flags = 0;
4146+ /* Accessing write_buf is safe because head->io_sem is held. */
4147+ if (!buf) {
4148+ head->r.eof = true;
4149+ return; /* Do nothing if open(O_RDONLY). */
4150+ }
4151+ if (head->r.w_pos || head->r.eof)
4152+ return;
4153+ head->r.eof = true;
4154+ if (ccs_str_starts(&buf, "info "))
4155+ task_info = true;
4156+ if (ccs_str_starts(&buf, "global-pid "))
4157+ global_pid = true;
4158+ pid = (unsigned int) simple_strtoul(buf, NULL, 10);
4159+ ccs_tasklist_lock();
4160+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
4161+ if (global_pid)
4162+ p = ccsecurity_exports.find_task_by_pid_ns(pid, &init_pid_ns);
4163+ else
4164+ p = ccsecurity_exports.find_task_by_vpid(pid);
4165+#else
4166+ p = find_task_by_pid(pid);
4167+#endif
4168+ if (p) {
4169+ domain = ccs_task_domain(p);
4170+ ccs_flags = ccs_task_flags(p);
4171+ }
4172+ ccs_tasklist_unlock();
4173+ if (!domain)
4174+ return;
4175+ if (!task_info) {
4176+ ccs_io_printf(head, "%u %u ", pid, domain->profile);
4177+ ccs_set_string(head, domain->domainname->name);
4178+ } else {
4179+ ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
4180+ ccs_yesno(ccs_flags &
4181+ CCS_TASK_IS_MANAGER),
4182+ ccs_yesno(ccs_flags &
4183+ CCS_TASK_IS_EXECUTE_HANDLER));
4184+ }
4185+}
4186+
4187+/**
4188+ * ccs_write_group - Write "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
4189+ *
4190+ * @param: Pointer to "struct ccs_acl_param".
4191+ * @type: Type of this group.
4192+ *
4193+ * Returns 0 on success, negative value otherwise.
4194+ */
4195+static int ccs_write_group(struct ccs_acl_param *param, const u8 type)
4196+{
4197+ struct ccs_group *group = ccs_get_group(param, type);
4198+ int error = -EINVAL;
4199+ if (!group)
4200+ return -ENOMEM;
4201+ param->list = &group->member_list;
4202+ if (type == CCS_PATH_GROUP) {
4203+ struct ccs_path_group *e = &param->e.path_group;
4204+ e->member_name = ccs_get_name(ccs_read_token(param));
4205+ if (!e->member_name) {
4206+ error = -ENOMEM;
4207+ goto out;
4208+ }
4209+ error = ccs_update_policy(sizeof(*e), param);
4210+ ccs_put_name(e->member_name);
4211+ } else if (type == CCS_NUMBER_GROUP) {
4212+ struct ccs_number_group *e = &param->e.number_group;
4213+ if (param->data[0] == '@' ||
4214+ !ccs_parse_number_union(param, &e->number))
4215+ goto out;
4216+ error = ccs_update_policy(sizeof(*e), param);
4217+#ifdef CONFIG_CCSECURITY_NETWORK
4218+ } else {
4219+ struct ccs_address_group *e = &param->e.address_group;
4220+ if (param->data[0] == '@' ||
4221+ !ccs_parse_ipaddr_union(param, &e->address))
4222+ goto out;
4223+ error = ccs_update_policy(sizeof(*e), param);
4224+#endif
4225+ }
4226+out:
4227+ ccs_put_group(group);
4228+ return error;
4229+}
4230+
4231+#ifdef CONFIG_CCSECURITY_PORTRESERVE
4232+/**
4233+ * ccs_lport_reserved - Check whether local port is reserved or not.
4234+ *
4235+ * @port: Port number.
4236+ *
4237+ * Returns true if local port is reserved, false otherwise.
4238+ */
4239+static bool __ccs_lport_reserved(const u16 port)
4240+{
4241+ return ccs_reserved_port_map[port >> 3] & (1 << (port & 7))
4242+ ? true : false;
4243+}
4244+
4245+/**
4246+ * ccs_write_reserved_port - Update "struct ccs_reserved" list.
4247+ *
4248+ * @param: Pointer to "struct ccs_acl_param".
4249+ *
4250+ * Returns 0 on success, negative value otherwise.
4251+ *
4252+ * Caller holds ccs_read_lock().
4253+ */
4254+static int ccs_write_reserved_port(struct ccs_acl_param *param)
4255+{
4256+ struct ccs_reserved *e = &param->e.reserved;
4257+ struct ccs_policy_namespace *ns = param->ns;
4258+ int error;
4259+ u8 *tmp;
4260+ if (param->data[0] == '@' ||
4261+ !ccs_parse_number_union(param, &e->port) ||
4262+ e->port.values[1] > 65535 || param->data[0])
4263+ return -EINVAL;
4264+ param->list = &ns->policy_list[CCS_ID_RESERVEDPORT];
4265+ error = ccs_update_policy(sizeof(*e), param);
4266+ if (error)
4267+ return error;
4268+ tmp = kzalloc(sizeof(ccs_reserved_port_map), CCS_GFP_FLAGS);
4269+ if (!tmp)
4270+ return -ENOMEM;
4271+ list_for_each_entry_srcu(ns, &ccs_namespace_list, namespace_list,
4272+ &ccs_ss) {
4273+ struct ccs_reserved *ptr;
4274+ struct list_head *list = &ns->policy_list[CCS_ID_RESERVEDPORT];
4275+ list_for_each_entry_srcu(ptr, list, head.list, &ccs_ss) {
4276+ unsigned int port;
4277+ if (ptr->head.is_deleted)
4278+ continue;
4279+ for (port = ptr->port.values[0];
4280+ port <= ptr->port.values[1]; port++)
4281+ tmp[port >> 3] |= 1 << (port & 7);
4282+ }
4283+ }
4284+ memmove(ccs_reserved_port_map, tmp, sizeof(ccs_reserved_port_map));
4285+ kfree(tmp);
4286+ /*
4287+ * Since this feature is no-op by default, we don't need to register
4288+ * this callback hook unless the first entry is added.
4289+ */
4290+ ccsecurity_ops.lport_reserved = __ccs_lport_reserved;
4291+ return 0;
4292+}
4293+#endif
4294+
4295+/**
4296+ * ccs_write_aggregator - Write "struct ccs_aggregator" list.
4297+ *
4298+ * @param: Pointer to "struct ccs_acl_param".
4299+ *
4300+ * Returns 0 on success, negative value otherwise.
4301+ */
4302+static int ccs_write_aggregator(struct ccs_acl_param *param)
4303+{
4304+ struct ccs_aggregator *e = &param->e.aggregator;
4305+ int error = param->is_delete ? -ENOENT : -ENOMEM;
4306+ const char *original_name = ccs_read_token(param);
4307+ const char *aggregated_name = ccs_read_token(param);
4308+ if (!ccs_correct_word(original_name) ||
4309+ !ccs_correct_path(aggregated_name))
4310+ return -EINVAL;
4311+ e->original_name = ccs_get_name(original_name);
4312+ e->aggregated_name = ccs_get_name(aggregated_name);
4313+ if (!e->original_name || !e->aggregated_name ||
4314+ e->aggregated_name->is_patterned) /* No patterns allowed. */
4315+ goto out;
4316+ param->list = &param->ns->policy_list[CCS_ID_AGGREGATOR];
4317+ error = ccs_update_policy(sizeof(*e), param);
4318+out:
4319+ ccs_put_name(e->original_name);
4320+ ccs_put_name(e->aggregated_name);
4321+ return error;
4322+}
4323+
4324+/**
4325+ * ccs_write_transition_control - Write "struct ccs_transition_control" list.
4326+ *
4327+ * @param: Pointer to "struct ccs_acl_param".
4328+ * @type: Type of this entry.
4329+ *
4330+ * Returns 0 on success, negative value otherwise.
4331+ */
4332+static int ccs_write_transition_control(struct ccs_acl_param *param,
4333+ const u8 type)
4334+{
4335+ struct ccs_transition_control *e = &param->e.transition_control;
4336+ int error = param->is_delete ? -ENOENT : -ENOMEM;
4337+ char *program = param->data;
4338+ char *domainname = strstr(program, " from ");
4339+ e->type = type;
4340+ if (domainname) {
4341+ *domainname = '\0';
4342+ domainname += 6;
4343+ } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
4344+ type == CCS_TRANSITION_CONTROL_KEEP) {
4345+ domainname = program;
4346+ program = NULL;
4347+ }
4348+ if (program && strcmp(program, "any")) {
4349+ if (!ccs_correct_path(program))
4350+ return -EINVAL;
4351+ e->program = ccs_get_name(program);
4352+ if (!e->program)
4353+ goto out;
4354+ }
4355+ if (domainname && strcmp(domainname, "any")) {
4356+ if (!ccs_correct_domain(domainname)) {
4357+ if (!ccs_correct_path(domainname))
4358+ goto out;
4359+ e->is_last_name = true;
4360+ }
4361+ e->domainname = ccs_get_name(domainname);
4362+ if (!e->domainname)
4363+ goto out;
4364+ }
4365+ param->list = &param->ns->policy_list[CCS_ID_TRANSITION_CONTROL];
4366+ error = ccs_update_policy(sizeof(*e), param);
4367+out:
4368+ ccs_put_name(e->domainname);
4369+ ccs_put_name(e->program);
4370+ return error;
4371+}
4372+
4373+/**
4374+ * ccs_write_exception - Write exception policy.
4375+ *
4376+ * @head: Pointer to "struct ccs_io_buffer".
4377+ *
4378+ * Returns 0 on success, negative value otherwise.
4379+ */
4380+static int ccs_write_exception(struct ccs_io_buffer *head)
4381+{
4382+ const bool is_delete = head->w.is_delete;
4383+ struct ccs_acl_param param = {
4384+ .ns = head->w.ns,
4385+ .is_delete = is_delete,
4386+ .data = head->write_buf,
4387+ };
4388+ u8 i;
4389+ /* Forced zero clear for using memcmp() at ccs_update_policy(). */
4390+ memset(&param.e, 0, sizeof(param.e));
4391+ if (ccs_str_starts(&param.data, "aggregator "))
4392+ return ccs_write_aggregator(&param);
4393+#ifdef CONFIG_CCSECURITY_PORTRESERVE
4394+ if (ccs_str_starts(&param.data, "deny_autobind "))
4395+ return ccs_write_reserved_port(&param);
4396+#endif
4397+ for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)
4398+ if (ccs_str_starts(&param.data, ccs_transition_type[i]))
4399+ return ccs_write_transition_control(&param, i);
4400+ for (i = 0; i < CCS_MAX_GROUP; i++)
4401+ if (ccs_str_starts(&param.data, ccs_group_name[i]))
4402+ return ccs_write_group(&param, i);
4403+ if (ccs_str_starts(&param.data, "acl_group ")) {
4404+ unsigned int group;
4405+ char *data;
4406+ group = simple_strtoul(param.data, &data, 10);
4407+ if (group < CCS_MAX_ACL_GROUPS && *data++ == ' ')
4408+ return ccs_write_acl(head->w.ns,
4409+ &head->w.ns->acl_group[group],
4410+ data, is_delete);
4411+ }
4412+ return -EINVAL;
4413+}
4414+
4415+/**
4416+ * ccs_read_group - Read "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
4417+ *
4418+ * @head: Pointer to "struct ccs_io_buffer".
4419+ * @idx: Index number.
4420+ *
4421+ * Returns true on success, false otherwise.
4422+ *
4423+ * Caller holds ccs_read_lock().
4424+ */
4425+static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)
4426+{
4427+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
4428+ namespace_list);
4429+ struct list_head *list = &ns->group_list[idx];
4430+ list_for_each_cookie(head->r.group, list) {
4431+ struct ccs_group *group =
4432+ list_entry(head->r.group, typeof(*group), head.list);
4433+ list_for_each_cookie(head->r.acl, &group->member_list) {
4434+ struct ccs_acl_head *ptr =
4435+ list_entry(head->r.acl, typeof(*ptr), list);
4436+ if (ptr->is_deleted)
4437+ continue;
4438+ if (!ccs_flush(head))
4439+ return false;
4440+ ccs_print_namespace(head);
4441+ ccs_set_string(head, ccs_group_name[idx]);
4442+ ccs_set_string(head, group->group_name->name);
4443+ if (idx == CCS_PATH_GROUP) {
4444+ ccs_set_space(head);
4445+ ccs_set_string(head, container_of
4446+ (ptr, struct ccs_path_group,
4447+ head)->member_name->name);
4448+ } else if (idx == CCS_NUMBER_GROUP) {
4449+ ccs_print_number_union(head, &container_of
4450+ (ptr, struct ccs_number_group,
4451+ head)->number);
4452+#ifdef CONFIG_CCSECURITY_NETWORK
4453+ } else if (idx == CCS_ADDRESS_GROUP) {
4454+ char buffer[128];
4455+ struct ccs_address_group *member =
4456+ container_of(ptr, typeof(*member),
4457+ head);
4458+ ccs_print_ip(buffer, sizeof(buffer),
4459+ &member->address);
4460+ ccs_io_printf(head, " %s", buffer);
4461+#endif
4462+ }
4463+ ccs_set_lf(head);
4464+ }
4465+ head->r.acl = NULL;
4466+ }
4467+ head->r.group = NULL;
4468+ return true;
4469+}
4470+
4471+/**
4472+ * ccs_read_policy - Read "struct ccs_..._entry" list.
4473+ *
4474+ * @head: Pointer to "struct ccs_io_buffer".
4475+ * @idx: Index number.
4476+ *
4477+ * Returns true on success, false otherwise.
4478+ *
4479+ * Caller holds ccs_read_lock().
4480+ */
4481+static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)
4482+{
4483+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
4484+ namespace_list);
4485+ struct list_head *list = &ns->policy_list[idx];
4486+ list_for_each_cookie(head->r.acl, list) {
4487+ struct ccs_acl_head *acl =
4488+ container_of(head->r.acl, typeof(*acl), list);
4489+ if (acl->is_deleted)
4490+ continue;
4491+ if (head->r.print_transition_related_only &&
4492+ idx != CCS_ID_TRANSITION_CONTROL)
4493+ continue;
4494+ if (!ccs_flush(head))
4495+ return false;
4496+ switch (idx) {
4497+ case CCS_ID_TRANSITION_CONTROL:
4498+ {
4499+ struct ccs_transition_control *ptr =
4500+ container_of(acl, typeof(*ptr), head);
4501+ ccs_print_namespace(head);
4502+ ccs_set_string(head,
4503+ ccs_transition_type[ptr->type]);
4504+ ccs_set_string(head, ptr->program ?
4505+ ptr->program->name : "any");
4506+ ccs_set_string(head, " from ");
4507+ ccs_set_string(head, ptr->domainname ?
4508+ ptr->domainname->name : "any");
4509+ }
4510+ break;
4511+ case CCS_ID_AGGREGATOR:
4512+ {
4513+ struct ccs_aggregator *ptr =
4514+ container_of(acl, typeof(*ptr), head);
4515+ ccs_print_namespace(head);
4516+ ccs_set_string(head, "aggregator ");
4517+ ccs_set_string(head, ptr->original_name->name);
4518+ ccs_set_space(head);
4519+ ccs_set_string(head,
4520+ ptr->aggregated_name->name);
4521+ }
4522+ break;
4523+#ifdef CONFIG_CCSECURITY_PORTRESERVE
4524+ case CCS_ID_RESERVEDPORT:
4525+ {
4526+ struct ccs_reserved *ptr =
4527+ container_of(acl, typeof(*ptr), head);
4528+ ccs_print_namespace(head);
4529+ ccs_set_string(head, "deny_autobind ");
4530+ ccs_print_number_union_nospace(head,
4531+ &ptr->port);
4532+ }
4533+ break;
4534+#endif
4535+ default:
4536+ continue;
4537+ }
4538+ ccs_set_lf(head);
4539+ }
4540+ head->r.acl = NULL;
4541+ return true;
4542+}
4543+
4544+/**
4545+ * ccs_read_exception - Read exception policy.
4546+ *
4547+ * @head: Pointer to "struct ccs_io_buffer".
4548+ *
4549+ * Returns nothing.
4550+ *
4551+ * Caller holds ccs_read_lock().
4552+ */
4553+static void ccs_read_exception(struct ccs_io_buffer *head)
4554+{
4555+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
4556+ namespace_list);
4557+ if (head->r.eof)
4558+ return;
4559+ while (head->r.step < CCS_MAX_POLICY &&
4560+ ccs_read_policy(head, head->r.step))
4561+ head->r.step++;
4562+ if (head->r.step < CCS_MAX_POLICY)
4563+ return;
4564+ while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP &&
4565+ ccs_read_group(head, head->r.step - CCS_MAX_POLICY))
4566+ head->r.step++;
4567+ if (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP)
4568+ return;
4569+ while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP
4570+ + CCS_MAX_ACL_GROUPS) {
4571+ head->r.acl_group_index =
4572+ head->r.step - CCS_MAX_POLICY - CCS_MAX_GROUP;
4573+ if (!ccs_read_acl(head, &ns->acl_group
4574+ [head->r.acl_group_index]))
4575+ return;
4576+ head->r.step++;
4577+ }
4578+ head->r.eof = true;
4579+}
4580+
4581+/**
4582+ * ccs_truncate - Truncate a line.
4583+ *
4584+ * @str: String to truncate.
4585+ *
4586+ * Returns length of truncated @str.
4587+ */
4588+static int ccs_truncate(char *str)
4589+{
4590+ char *start = str;
4591+ while (*(unsigned char *) str > (unsigned char) ' ')
4592+ str++;
4593+ *str = '\0';
4594+ return strlen(start) + 1;
4595+}
4596+
4597+/**
4598+ * ccs_add_entry - Add an ACL to current thread's domain. Used by learning mode.
4599+ *
4600+ * @header: Lines containing ACL.
4601+ *
4602+ * Returns nothing.
4603+ */
4604+static void ccs_add_entry(char *header)
4605+{
4606+ char *buffer;
4607+ char *realpath = NULL;
4608+ char *argv0 = NULL;
4609+ char *symlink = NULL;
4610+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4611+ char *handler;
4612+#endif
4613+ char *cp = strchr(header, '\n');
4614+ int len;
4615+ if (!cp)
4616+ return;
4617+ cp = strchr(cp + 1, '\n');
4618+ if (!cp)
4619+ return;
4620+ *cp++ = '\0';
4621+ len = strlen(cp) + 1;
4622+ /* strstr() will return NULL if ordering is wrong. */
4623+ if (*cp == 'f') {
4624+ argv0 = strstr(header, " argv[]={ \"");
4625+ if (argv0) {
4626+ argv0 += 10;
4627+ len += ccs_truncate(argv0) + 14;
4628+ }
4629+ realpath = strstr(header, " exec={ realpath=\"");
4630+ if (realpath) {
4631+ realpath += 8;
4632+ len += ccs_truncate(realpath) + 6;
4633+ }
4634+ symlink = strstr(header, " symlink.target=\"");
4635+ if (symlink)
4636+ len += ccs_truncate(symlink + 1) + 1;
4637+ }
4638+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4639+ handler = strstr(header, "type=execute_handler");
4640+ if (handler)
4641+ len += ccs_truncate(handler) + 6;
4642+#endif
4643+ buffer = kmalloc(len, CCS_GFP_FLAGS);
4644+ if (!buffer)
4645+ return;
4646+ snprintf(buffer, len - 1, "%s", cp);
4647+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4648+ if (handler)
4649+ ccs_addprintf(buffer, len, " task.%s", handler);
4650+#endif
4651+ if (realpath)
4652+ ccs_addprintf(buffer, len, " exec.%s", realpath);
4653+ if (argv0)
4654+ ccs_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
4655+ if (symlink)
4656+ ccs_addprintf(buffer, len, "%s", symlink);
4657+ ccs_normalize_line(buffer);
4658+ {
4659+ struct ccs_domain_info *domain = ccs_current_domain();
4660+ if (!ccs_write_acl(domain->ns, &domain->acl_info_list,
4661+ buffer, false))
4662+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
4663+ }
4664+ kfree(buffer);
4665+}
4666+
4667+/**
4668+ * ccs_domain_quota_ok - Check for domain's quota.
4669+ *
4670+ * @r: Pointer to "struct ccs_request_info".
4671+ *
4672+ * Returns true if the domain is not exceeded quota, false otherwise.
4673+ *
4674+ * Caller holds ccs_read_lock().
4675+ */
4676+static bool ccs_domain_quota_ok(struct ccs_request_info *r)
4677+{
4678+ unsigned int count = 0;
4679+ struct ccs_domain_info * const domain = ccs_current_domain();
4680+ struct ccs_acl_info *ptr;
4681+ if (r->mode != CCS_CONFIG_LEARNING)
4682+ return false;
4683+ if (!domain)
4684+ return true;
4685+ list_for_each_entry_srcu(ptr, &domain->acl_info_list, list, &ccs_ss) {
4686+ u16 perm;
4687+ u8 i;
4688+ if (ptr->is_deleted)
4689+ continue;
4690+ switch (ptr->type) {
4691+ case CCS_TYPE_PATH_ACL:
4692+ case CCS_TYPE_PATH2_ACL:
4693+ case CCS_TYPE_PATH_NUMBER_ACL:
4694+ case CCS_TYPE_MKDEV_ACL:
4695+#ifdef CONFIG_CCSECURITY_NETWORK
4696+ case CCS_TYPE_INET_ACL:
4697+ case CCS_TYPE_UNIX_ACL:
4698+#endif
4699+ perm = ptr->perm;
4700+ break;
4701+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4702+ case CCS_TYPE_AUTO_EXECUTE_HANDLER:
4703+ case CCS_TYPE_DENIED_EXECUTE_HANDLER:
4704+#endif
4705+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4706+ case CCS_TYPE_AUTO_TASK_ACL:
4707+ case CCS_TYPE_MANUAL_TASK_ACL:
4708+#endif
4709+ perm = 0;
4710+ break;
4711+ default:
4712+ perm = 1;
4713+ }
4714+ for (i = 0; i < 16; i++)
4715+ if (perm & (1 << i))
4716+ count++;
4717+ }
4718+ if (count < ccs_profile(r->profile)->pref[CCS_PREF_MAX_LEARNING_ENTRY])
4719+ return true;
4720+ if (!domain->flags[CCS_DIF_QUOTA_WARNED]) {
4721+ domain->flags[CCS_DIF_QUOTA_WARNED] = true;
4722+ /* r->granted = false; */
4723+ ccs_write_log(r, "%s", ccs_dif[CCS_DIF_QUOTA_WARNED]);
4724+ printk(KERN_WARNING "WARNING: "
4725+ "Domain '%s' has too many ACLs to hold. "
4726+ "Stopped learning mode.\n", domain->domainname->name);
4727+ }
4728+ return false;
4729+}
4730+
4731+/**
4732+ * ccs_supervisor - Ask for the supervisor's decision.
4733+ *
4734+ * @r: Pointer to "struct ccs_request_info".
4735+ * @fmt: The printf()'s format string, followed by parameters.
4736+ *
4737+ * Returns 0 if the supervisor decided to permit the access request which
4738+ * violated the policy in enforcing mode, CCS_RETRY_REQUEST if the supervisor
4739+ * decided to retry the access request which violated the policy in enforcing
4740+ * mode, 0 if it is not in enforcing mode, -EPERM otherwise.
4741+ */
4742+static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
4743+{
4744+ va_list args;
4745+ int error;
4746+ int len;
4747+ static unsigned int ccs_serial;
4748+ struct ccs_query entry = { };
4749+ bool quota_exceeded = false;
4750+ va_start(args, fmt);
4751+ len = vsnprintf((char *) &len, 1, fmt, args) + 1;
4752+ va_end(args);
4753+ /* Write /proc/ccs/audit. */
4754+ va_start(args, fmt);
4755+ ccs_write_log2(r, len, fmt, args);
4756+ va_end(args);
4757+ /* Nothing more to do if granted. */
4758+ if (r->granted)
4759+ return 0;
4760+ if (r->mode)
4761+ ccs_update_stat(r->mode);
4762+ switch (r->mode) {
4763+ int i;
4764+ struct ccs_profile *p;
4765+ case CCS_CONFIG_ENFORCING:
4766+ error = -EPERM;
4767+ if (atomic_read(&ccs_query_observers))
4768+ break;
4769+ if (r->dont_sleep_on_enforce_error)
4770+ goto out;
4771+ p = ccs_profile(r->profile);
4772+ /* Check enforcing_penalty parameter. */
4773+ for (i = 0; i < p->pref[CCS_PREF_ENFORCING_PENALTY]; i++) {
4774+ set_current_state(TASK_INTERRUPTIBLE);
4775+ schedule_timeout(HZ / 10);
4776+ }
4777+ goto out;
4778+ case CCS_CONFIG_LEARNING:
4779+ error = 0;
4780+ /* Check max_learning_entry parameter. */
4781+ if (ccs_domain_quota_ok(r))
4782+ break;
4783+ /* fall through */
4784+ default:
4785+ return 0;
4786+ }
4787+ /* Get message. */
4788+ va_start(args, fmt);
4789+ entry.query = ccs_init_log(r, len, fmt, args);
4790+ va_end(args);
4791+ if (!entry.query)
4792+ goto out;
4793+ entry.query_len = strlen(entry.query) + 1;
4794+ if (!error) {
4795+ ccs_add_entry(entry.query);
4796+ goto out;
4797+ }
4798+ len = ccs_round2(entry.query_len);
4799+ entry.domain = ccs_current_domain();
4800+ spin_lock(&ccs_query_list_lock);
4801+ if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
4802+ ccs_memory_used[CCS_MEMORY_QUERY] + len
4803+ >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
4804+ quota_exceeded = true;
4805+ } else {
4806+ entry.serial = ccs_serial++;
4807+ entry.retry = r->retry;
4808+ ccs_memory_used[CCS_MEMORY_QUERY] += len;
4809+ list_add_tail(&entry.list, &ccs_query_list);
4810+ }
4811+ spin_unlock(&ccs_query_list_lock);
4812+ if (quota_exceeded)
4813+ goto out;
4814+ /* Give 10 seconds for supervisor's opinion. */
4815+ while (entry.timer < 10) {
4816+ wake_up_all(&ccs_query_wait);
4817+ if (wait_event_interruptible_timeout
4818+ (ccs_answer_wait, entry.answer ||
4819+ !atomic_read(&ccs_query_observers), HZ))
4820+ break;
4821+ else
4822+ entry.timer++;
4823+ }
4824+ spin_lock(&ccs_query_list_lock);
4825+ list_del(&entry.list);
4826+ ccs_memory_used[CCS_MEMORY_QUERY] -= len;
4827+ spin_unlock(&ccs_query_list_lock);
4828+ switch (entry.answer) {
4829+ case 3: /* Asked to retry by administrator. */
4830+ error = CCS_RETRY_REQUEST;
4831+ r->retry++;
4832+ break;
4833+ case 1:
4834+ /* Granted by administrator. */
4835+ error = 0;
4836+ break;
4837+ default:
4838+ /* Timed out or rejected by administrator. */
4839+ break;
4840+ }
4841+out:
4842+ kfree(entry.query);
4843+ return error;
4844+}
4845+
4846+/**
4847+ * ccs_audit_log - Audit permission check log.
4848+ *
4849+ * @r: Pointer to "struct ccs_request_info".
4850+ *
4851+ * Returns return value of ccs_supervisor().
4852+ */
4853+int ccs_audit_log(struct ccs_request_info *r)
4854+{
4855+ switch (r->param_type) {
4856+ u8 type;
4857+ char buf[48];
4858+#ifdef CONFIG_CCSECURITY_NETWORK
4859+ const u32 *address;
4860+#endif
4861+ case CCS_TYPE_PATH_ACL:
4862+ return ccs_supervisor(r, "file %s %s\n", ccs_path_keyword
4863+ [r->param.path.operation],
4864+ r->param.path.filename->name);
4865+ case CCS_TYPE_PATH2_ACL:
4866+ return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords
4867+ [ccs_pp2mac[r->param.path2.operation]],
4868+ r->param.path2.filename1->name,
4869+ r->param.path2.filename2->name);
4870+ case CCS_TYPE_PATH_NUMBER_ACL:
4871+ type = r->param.path_number.operation;
4872+ switch (type) {
4873+ case CCS_TYPE_CREATE:
4874+ case CCS_TYPE_MKDIR:
4875+ case CCS_TYPE_MKFIFO:
4876+ case CCS_TYPE_MKSOCK:
4877+ case CCS_TYPE_CHMOD:
4878+ snprintf(buf, sizeof(buf), "0%lo",
4879+ r->param.path_number.number);
4880+ break;
4881+ case CCS_TYPE_IOCTL:
4882+ snprintf(buf, sizeof(buf), "0x%lX",
4883+ r->param.path_number.number);
4884+ break;
4885+ default:
4886+ snprintf(buf, sizeof(buf), "%lu",
4887+ r->param.path_number.number);
4888+ break;
4889+ }
4890+ return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords
4891+ [ccs_pn2mac[type]],
4892+ r->param.path_number.filename->name,
4893+ buf);
4894+ case CCS_TYPE_MKDEV_ACL:
4895+ return ccs_supervisor(r, "file %s %s 0%o %u %u\n",
4896+ ccs_mac_keywords
4897+ [ccs_pnnn2mac[r->param.mkdev.operation]],
4898+ r->param.mkdev.filename->name,
4899+ r->param.mkdev.mode,
4900+ r->param.mkdev.major,
4901+ r->param.mkdev.minor);
4902+ case CCS_TYPE_MOUNT_ACL:
4903+ return ccs_supervisor(r, "file mount %s %s %s 0x%lX\n",
4904+ r->param.mount.dev->name,
4905+ r->param.mount.dir->name,
4906+ r->param.mount.type->name,
4907+ r->param.mount.flags);
4908+#ifdef CONFIG_CCSECURITY_MISC
4909+ case CCS_TYPE_ENV_ACL:
4910+ return ccs_supervisor(r, "misc env %s\n",
4911+ r->param.environ.name->name);
4912+#endif
4913+#ifdef CONFIG_CCSECURITY_CAPABILITY
4914+ case CCS_TYPE_CAPABILITY_ACL:
4915+ return ccs_supervisor(r, "capability %s\n", ccs_mac_keywords
4916+ [ccs_c2mac[r->param.capability.
4917+ operation]]);
4918+#endif
4919+#ifdef CONFIG_CCSECURITY_NETWORK
4920+ case CCS_TYPE_INET_ACL:
4921+ address = r->param.inet_network.address;
4922+ if (r->param.inet_network.is_ipv6)
4923+ ccs_print_ipv6(buf, sizeof(buf),
4924+ (const struct in6_addr *) address);
4925+ else
4926+ ccs_print_ipv4(buf, sizeof(buf), address);
4927+ return ccs_supervisor(r, "network inet %s %s %s %u\n",
4928+ ccs_proto_keyword[r->param.inet_network.
4929+ protocol],
4930+ ccs_socket_keyword[r->param.inet_network.
4931+ operation],
4932+ buf, r->param.inet_network.port);
4933+ case CCS_TYPE_UNIX_ACL:
4934+ return ccs_supervisor(r, "network unix %s %s %s\n",
4935+ ccs_proto_keyword[r->param.
4936+ unix_network.protocol],
4937+ ccs_socket_keyword[r->param.unix_network.
4938+ operation],
4939+ r->param.unix_network.address->name);
4940+#endif
4941+#ifdef CONFIG_CCSECURITY_IPC
4942+ case CCS_TYPE_SIGNAL_ACL:
4943+ return ccs_supervisor(r, "ipc signal %d %s\n",
4944+ r->param.signal.sig,
4945+ r->param.signal.dest_pattern);
4946+#endif
4947+ }
4948+ return 0;
4949+}
4950+
4951+/**
4952+ * ccs_find_domain_by_qid - Get domain by query id.
4953+ *
4954+ * @serial: Query ID assigned by ccs_supervisor().
4955+ *
4956+ * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
4957+ */
4958+static struct ccs_domain_info *ccs_find_domain_by_qid(unsigned int serial)
4959+{
4960+ struct ccs_query *ptr;
4961+ struct ccs_domain_info *domain = NULL;
4962+ spin_lock(&ccs_query_list_lock);
4963+ list_for_each_entry(ptr, &ccs_query_list, list) {
4964+ if (ptr->serial != serial)
4965+ continue;
4966+ domain = ptr->domain;
4967+ break;
4968+ }
4969+ spin_unlock(&ccs_query_list_lock);
4970+ return domain;
4971+}
4972+
4973+/**
4974+ * ccs_read_query - Read access requests which violated policy in enforcing mode.
4975+ *
4976+ * @head: Pointer to "struct ccs_io_buffer".
4977+ *
4978+ * Returns nothing.
4979+ */
4980+static void ccs_read_query(struct ccs_io_buffer *head)
4981+{
4982+ struct list_head *tmp;
4983+ unsigned int pos = 0;
4984+ size_t len = 0;
4985+ char *buf;
4986+ if (head->r.w_pos)
4987+ return;
4988+ kfree(head->read_buf);
4989+ head->read_buf = NULL;
4990+ spin_lock(&ccs_query_list_lock);
4991+ list_for_each(tmp, &ccs_query_list) {
4992+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
4993+ if (pos++ != head->r.query_index)
4994+ continue;
4995+ len = ptr->query_len;
4996+ break;
4997+ }
4998+ spin_unlock(&ccs_query_list_lock);
4999+ if (!len) {
5000+ head->r.query_index = 0;
5001+ return;
5002+ }
5003+ buf = kzalloc(len + 32, CCS_GFP_FLAGS);
5004+ if (!buf)
5005+ return;
5006+ pos = 0;
5007+ spin_lock(&ccs_query_list_lock);
5008+ list_for_each(tmp, &ccs_query_list) {
5009+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
5010+ if (pos++ != head->r.query_index)
5011+ continue;
5012+ /*
5013+ * Some query can be skipped because ccs_query_list
5014+ * can change, but I don't care.
5015+ */
5016+ if (len == ptr->query_len)
5017+ snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
5018+ ptr->retry, ptr->query);
5019+ break;
5020+ }
5021+ spin_unlock(&ccs_query_list_lock);
5022+ if (buf[0]) {
5023+ head->read_buf = buf;
5024+ head->r.w[head->r.w_pos++] = buf;
5025+ head->r.query_index++;
5026+ } else {
5027+ kfree(buf);
5028+ }
5029+}
5030+
5031+/**
5032+ * ccs_write_answer - Write the supervisor's decision.
5033+ *
5034+ * @head: Pointer to "struct ccs_io_buffer".
5035+ *
5036+ * Returns 0 on success, -EINVAL otherwise.
5037+ */
5038+static int ccs_write_answer(struct ccs_io_buffer *head)
5039+{
5040+ char *data = head->write_buf;
5041+ struct list_head *tmp;
5042+ unsigned int serial;
5043+ unsigned int answer;
5044+ spin_lock(&ccs_query_list_lock);
5045+ list_for_each(tmp, &ccs_query_list) {
5046+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
5047+ ptr->timer = 0;
5048+ }
5049+ spin_unlock(&ccs_query_list_lock);
5050+ if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
5051+ return -EINVAL;
5052+ spin_lock(&ccs_query_list_lock);
5053+ list_for_each(tmp, &ccs_query_list) {
5054+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
5055+ if (ptr->serial != serial)
5056+ continue;
5057+ ptr->answer = (u8) answer;
5058+ /* Remove from ccs_query_list. */
5059+ if (ptr->answer) {
5060+ list_del(&ptr->list);
5061+ INIT_LIST_HEAD(&ptr->list);
5062+ }
5063+ break;
5064+ }
5065+ spin_unlock(&ccs_query_list_lock);
5066+ wake_up_all(&ccs_answer_wait);
5067+ return 0;
5068+}
5069+
5070+/**
5071+ * ccs_read_version - Get version.
5072+ *
5073+ * @head: Pointer to "struct ccs_io_buffer".
5074+ *
5075+ * Returns nothing.
5076+ */
5077+static void ccs_read_version(struct ccs_io_buffer *head)
5078+{
5079+ if (head->r.eof)
5080+ return;
5081+ ccs_set_string(head, "1.8.3");
5082+ head->r.eof = true;
5083+}
5084+
5085+/**
5086+ * ccs_update_stat - Update statistic counters.
5087+ *
5088+ * @index: Index for policy type.
5089+ *
5090+ * Returns nothing.
5091+ */
5092+static void ccs_update_stat(const u8 index)
5093+{
5094+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
5095+ struct timeval tv;
5096+ do_gettimeofday(&tv);
5097+ /*
5098+ * I don't use atomic operations because race condition is not fatal.
5099+ */
5100+ ccs_stat_updated[index]++;
5101+ ccs_stat_modified[index] = tv.tv_sec;
5102+#else
5103+ /*
5104+ * I don't use atomic operations because race condition is not fatal.
5105+ */
5106+ ccs_stat_updated[index]++;
5107+ ccs_stat_modified[index] = get_seconds();
5108+#endif
5109+}
5110+
5111+/**
5112+ * ccs_read_stat - Read statistic data.
5113+ *
5114+ * @head: Pointer to "struct ccs_io_buffer".
5115+ *
5116+ * Returns nothing.
5117+ */
5118+static void ccs_read_stat(struct ccs_io_buffer *head)
5119+{
5120+ u8 i;
5121+ unsigned int total = 0;
5122+ if (head->r.eof)
5123+ return;
5124+ for (i = 0; i < CCS_MAX_POLICY_STAT; i++) {
5125+ ccs_io_printf(head, "Policy %-30s %10u", ccs_policy_headers[i],
5126+ ccs_stat_updated[i]);
5127+ if (ccs_stat_modified[i]) {
5128+ struct ccs_time stamp;
5129+ ccs_convert_time(ccs_stat_modified[i], &stamp);
5130+ ccs_io_printf(head, " (Last: %04u/%02u/%02u "
5131+ "%02u:%02u:%02u)",
5132+ stamp.year, stamp.month, stamp.day,
5133+ stamp.hour, stamp.min, stamp.sec);
5134+ }
5135+ ccs_set_lf(head);
5136+ }
5137+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++) {
5138+ unsigned int used = ccs_memory_used[i];
5139+ total += used;
5140+ ccs_io_printf(head, "Memory used by %-22s %10u",
5141+ ccs_memory_headers[i], used);
5142+ used = ccs_memory_quota[i];
5143+ if (used)
5144+ ccs_io_printf(head, " (Quota: %10u)", used);
5145+ ccs_set_lf(head);
5146+ }
5147+ ccs_io_printf(head, "Total memory used: %10u\n",
5148+ total);
5149+ head->r.eof = true;
5150+}
5151+
5152+/**
5153+ * ccs_write_stat - Set memory quota.
5154+ *
5155+ * @head: Pointer to "struct ccs_io_buffer".
5156+ *
5157+ * Returns 0.
5158+ */
5159+static int ccs_write_stat(struct ccs_io_buffer *head)
5160+{
5161+ char *data = head->write_buf;
5162+ u8 i;
5163+ if (ccs_str_starts(&data, "Memory used by "))
5164+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++)
5165+ if (ccs_str_starts(&data, ccs_memory_headers[i])) {
5166+ if (*data == ' ')
5167+ data++;
5168+ ccs_memory_quota[i] =
5169+ simple_strtoul(data, NULL, 10);
5170+ }
5171+ return 0;
5172+}
5173+
5174+/**
5175+ * ccs_print_bprm - Print "struct linux_binprm" for auditing.
5176+ *
5177+ * @bprm: Pointer to "struct linux_binprm".
5178+ * @dump: Pointer to "struct ccs_page_dump".
5179+ *
5180+ * Returns the contents of @bprm on success, NULL otherwise.
5181+ *
5182+ * This function uses kzalloc(), so caller must kfree() if this function
5183+ * didn't return NULL.
5184+ */
5185+static char *ccs_print_bprm(struct linux_binprm *bprm,
5186+ struct ccs_page_dump *dump)
5187+{
5188+ static const int ccs_buffer_len = 4096 * 2;
5189+ char *buffer = kzalloc(ccs_buffer_len, CCS_GFP_FLAGS);
5190+ char *cp;
5191+ char *last_start;
5192+ int len;
5193+ unsigned long pos = bprm->p;
5194+ int offset = pos % PAGE_SIZE;
5195+ int argv_count = bprm->argc;
5196+ int envp_count = bprm->envc;
5197+ bool truncated = false;
5198+ if (!buffer)
5199+ return NULL;
5200+ len = snprintf(buffer, ccs_buffer_len - 1, "argv[]={ ");
5201+ cp = buffer + len;
5202+ if (!argv_count) {
5203+ memmove(cp, "} envp[]={ ", 11);
5204+ cp += 11;
5205+ }
5206+ last_start = cp;
5207+ while (argv_count || envp_count) {
5208+ if (!ccs_dump_page(bprm, pos, dump))
5209+ goto out;
5210+ pos += PAGE_SIZE - offset;
5211+ /* Read. */
5212+ while (offset < PAGE_SIZE) {
5213+ const char *kaddr = dump->data;
5214+ const unsigned char c = kaddr[offset++];
5215+ if (cp == last_start)
5216+ *cp++ = '"';
5217+ if (cp >= buffer + ccs_buffer_len - 32) {
5218+ /* Reserve some room for "..." string. */
5219+ truncated = true;
5220+ } else if (c == '\\') {
5221+ *cp++ = '\\';
5222+ *cp++ = '\\';
5223+ } else if (c > ' ' && c < 127) {
5224+ *cp++ = c;
5225+ } else if (!c) {
5226+ *cp++ = '"';
5227+ *cp++ = ' ';
5228+ last_start = cp;
5229+ } else {
5230+ *cp++ = '\\';
5231+ *cp++ = (c >> 6) + '0';
5232+ *cp++ = ((c >> 3) & 7) + '0';
5233+ *cp++ = (c & 7) + '0';
5234+ }
5235+ if (c)
5236+ continue;
5237+ if (argv_count) {
5238+ if (--argv_count == 0) {
5239+ if (truncated) {
5240+ cp = last_start;
5241+ memmove(cp, "... ", 4);
5242+ cp += 4;
5243+ }
5244+ memmove(cp, "} envp[]={ ", 11);
5245+ cp += 11;
5246+ last_start = cp;
5247+ truncated = false;
5248+ }
5249+ } else if (envp_count) {
5250+ if (--envp_count == 0) {
5251+ if (truncated) {
5252+ cp = last_start;
5253+ memmove(cp, "... ", 4);
5254+ cp += 4;
5255+ }
5256+ }
5257+ }
5258+ if (!argv_count && !envp_count)
5259+ break;
5260+ }
5261+ offset = 0;
5262+ }
5263+ *cp++ = '}';
5264+ *cp = '\0';
5265+ return buffer;
5266+out:
5267+ snprintf(buffer, ccs_buffer_len - 1, "argv[]={ ... } envp[]= { ... }");
5268+ return buffer;
5269+}
5270+
5271+/**
5272+ * ccs_filetype - Get string representation of file type.
5273+ *
5274+ * @mode: Mode value for stat().
5275+ *
5276+ * Returns file type string.
5277+ */
5278+static inline const char *ccs_filetype(const umode_t mode)
5279+{
5280+ switch (mode & S_IFMT) {
5281+ case S_IFREG:
5282+ case 0:
5283+ return ccs_condition_keyword[CCS_TYPE_IS_FILE];
5284+ case S_IFDIR:
5285+ return ccs_condition_keyword[CCS_TYPE_IS_DIRECTORY];
5286+ case S_IFLNK:
5287+ return ccs_condition_keyword[CCS_TYPE_IS_SYMLINK];
5288+ case S_IFIFO:
5289+ return ccs_condition_keyword[CCS_TYPE_IS_FIFO];
5290+ case S_IFSOCK:
5291+ return ccs_condition_keyword[CCS_TYPE_IS_SOCKET];
5292+ case S_IFBLK:
5293+ return ccs_condition_keyword[CCS_TYPE_IS_BLOCK_DEV];
5294+ case S_IFCHR:
5295+ return ccs_condition_keyword[CCS_TYPE_IS_CHAR_DEV];
5296+ }
5297+ return "unknown"; /* This should not happen. */
5298+}
5299+
5300+/**
5301+ * ccs_print_header - Get header line of audit log.
5302+ *
5303+ * @r: Pointer to "struct ccs_request_info".
5304+ *
5305+ * Returns string representation.
5306+ *
5307+ * This function uses kmalloc(), so caller must kfree() if this function
5308+ * didn't return NULL.
5309+ */
5310+static char *ccs_print_header(struct ccs_request_info *r)
5311+{
5312+ struct ccs_time stamp;
5313+ struct ccs_obj_info *obj = r->obj;
5314+ const u32 ccs_flags = ccs_current_flags();
5315+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
5316+ const pid_t gpid = ccs_sys_getpid();
5317+#else
5318+ const pid_t gpid = task_pid_nr(current);
5319+#endif
5320+ static const int ccs_buffer_len = 4096;
5321+ char *buffer = kmalloc(ccs_buffer_len, CCS_GFP_FLAGS);
5322+ int pos;
5323+ u8 i;
5324+ if (!buffer)
5325+ return NULL;
5326+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
5327+ {
5328+ struct timeval tv;
5329+ do_gettimeofday(&tv);
5330+ ccs_convert_time(tv.tv_sec, &stamp);
5331+ }
5332+#else
5333+ ccs_convert_time(get_seconds(), &stamp);
5334+#endif
5335+ pos = snprintf(buffer, ccs_buffer_len - 1,
5336+ "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
5337+ "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
5338+ "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
5339+ "fsuid=%u fsgid=%u type%s=execute_handler }",
5340+ stamp.year, stamp.month, stamp.day, stamp.hour,
5341+ stamp.min, stamp.sec, r->profile, ccs_mode[r->mode],
5342+ ccs_yesno(r->granted), gpid, ccs_sys_getpid(),
5343+ ccs_sys_getppid(),
5344+ from_kuid(&init_user_ns, current_uid()),
5345+ from_kgid(&init_user_ns, current_gid()),
5346+ from_kuid(&init_user_ns, current_euid()),
5347+ from_kgid(&init_user_ns, current_egid()),
5348+ from_kuid(&init_user_ns, current_suid()),
5349+ from_kgid(&init_user_ns, current_sgid()),
5350+ from_kuid(&init_user_ns, current_fsuid()),
5351+ from_kgid(&init_user_ns, current_fsgid()),
5352+ ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER ? "" : "!");
5353+ if (!obj)
5354+ goto no_obj_info;
5355+ if (!obj->validate_done) {
5356+ ccs_get_attributes(obj);
5357+ obj->validate_done = true;
5358+ }
5359+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
5360+ struct ccs_mini_stat *stat;
5361+ unsigned int dev;
5362+ umode_t mode;
5363+ if (!obj->stat_valid[i])
5364+ continue;
5365+ stat = &obj->stat[i];
5366+ dev = stat->dev;
5367+ mode = stat->mode;
5368+ if (i & 1) {
5369+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
5370+ " path%u.parent={ uid=%u gid=%u "
5371+ "ino=%lu perm=0%o }", (i >> 1) + 1,
5372+ from_kuid(&init_user_ns, stat->uid),
5373+ from_kgid(&init_user_ns, stat->gid),
5374+ (unsigned long) stat->ino,
5375+ stat->mode & S_IALLUGO);
5376+ continue;
5377+ }
5378+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
5379+ " path%u={ uid=%u gid=%u ino=%lu major=%u"
5380+ " minor=%u perm=0%o type=%s", (i >> 1) + 1,
5381+ from_kuid(&init_user_ns, stat->uid),
5382+ from_kgid(&init_user_ns, stat->gid),
5383+ (unsigned long) stat->ino, MAJOR(dev),
5384+ MINOR(dev), mode & S_IALLUGO,
5385+ ccs_filetype(mode));
5386+ if (S_ISCHR(mode) || S_ISBLK(mode)) {
5387+ dev = stat->rdev;
5388+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
5389+ " dev_major=%u dev_minor=%u",
5390+ MAJOR(dev), MINOR(dev));
5391+ }
5392+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos, " }");
5393+ }
5394+no_obj_info:
5395+ if (pos < ccs_buffer_len - 1)
5396+ return buffer;
5397+ kfree(buffer);
5398+ return NULL;
5399+}
5400+
5401+/**
5402+ * ccs_init_log - Allocate buffer for audit logs.
5403+ *
5404+ * @r: Pointer to "struct ccs_request_info".
5405+ * @len: Buffer size needed for @fmt and @args.
5406+ * @fmt: The printf()'s format string.
5407+ * @args: va_list structure for @fmt.
5408+ *
5409+ * Returns pointer to allocated memory.
5410+ *
5411+ * This function uses kzalloc(), so caller must kfree() if this function
5412+ * didn't return NULL.
5413+ */
5414+static char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt,
5415+ va_list args)
5416+{
5417+ char *buf = NULL;
5418+ char *bprm_info = NULL;
5419+ char *realpath = NULL;
5420+ const char *symlink = NULL;
5421+ const char *header = NULL;
5422+ int pos;
5423+ const char *domainname = ccs_current_domain()->domainname->name;
5424+ header = ccs_print_header(r);
5425+ if (!header)
5426+ return NULL;
5427+ /* +10 is for '\n' etc. and '\0'. */
5428+ len += strlen(domainname) + strlen(header) + 10;
5429+ if (r->ee) {
5430+ struct file *file = r->ee->bprm->file;
5431+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
5432+ struct path path = { file->f_vfsmnt, file->f_dentry };
5433+ realpath = ccs_realpath(&path);
5434+#else
5435+ realpath = ccs_realpath(&file->f_path);
5436+#endif
5437+ bprm_info = ccs_print_bprm(r->ee->bprm, &r->ee->dump);
5438+ if (!realpath || !bprm_info)
5439+ goto out;
5440+ /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
5441+ len += strlen(realpath) + 80 + strlen(bprm_info);
5442+ } else if (r->obj && r->obj->symlink_target) {
5443+ symlink = r->obj->symlink_target->name;
5444+ /* +18 is for " symlink.target=\"%s\"" */
5445+ len += 18 + strlen(symlink);
5446+ }
5447+ len = ccs_round2(len);
5448+ buf = kzalloc(len, CCS_GFP_FLAGS);
5449+ if (!buf)
5450+ goto out;
5451+ len--;
5452+ pos = snprintf(buf, len, "%s", header);
5453+ if (realpath) {
5454+ struct linux_binprm *bprm = r->ee->bprm;
5455+ pos += snprintf(buf + pos, len - pos,
5456+ " exec={ realpath=\"%s\" argc=%d envc=%d %s }",
5457+ realpath, bprm->argc, bprm->envc, bprm_info);
5458+ } else if (symlink)
5459+ pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
5460+ symlink);
5461+ pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
5462+ vsnprintf(buf + pos, len - pos, fmt, args);
5463+out:
5464+ kfree(realpath);
5465+ kfree(bprm_info);
5466+ kfree(header);
5467+ return buf;
5468+}
5469+
5470+/**
5471+ * ccs_transition_failed - Print waning message and send signal when domain transition failed.
5472+ *
5473+ * @domainname: Name of domain to transit.
5474+ *
5475+ * Returns nothing.
5476+ *
5477+ * Note that if current->pid == 1, sending SIGKILL won't work.
5478+ */
5479+void ccs_transition_failed(const char *domainname)
5480+{
5481+ printk(KERN_WARNING
5482+ "ERROR: Unable to transit to '%s' domain.\n", domainname);
5483+ force_sig(SIGKILL, current);
5484+}
5485+
5486+/**
5487+ * ccs_update_task_domain - Update task's domain.
5488+ *
5489+ * @r: Pointer to "struct ccs_request_info".
5490+ *
5491+ * Returns nothing.
5492+ *
5493+ * The task will retry as hard as possible. But if domain transition failed,
5494+ * the task will be killed by SIGKILL.
5495+ */
5496+static void ccs_update_task_domain(struct ccs_request_info *r)
5497+{
5498+ char *buf;
5499+ const char *cp;
5500+ const struct ccs_acl_info *acl = r->matched_acl;
5501+ r->matched_acl = NULL;
5502+ if (!acl || !acl->cond || !acl->cond->transit ||
5503+ acl->cond->exec_transit)
5504+ return;
5505+ while (1) {
5506+ buf = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
5507+ if (buf)
5508+ break;
5509+ ssleep(1);
5510+ if (fatal_signal_pending(current))
5511+ return;
5512+ }
5513+ cp = acl->cond->transit->name;
5514+ if (*cp == '/')
5515+ snprintf(buf, CCS_EXEC_TMPSIZE - 1, "%s %s",
5516+ ccs_current_domain()->domainname->name, cp);
5517+ else
5518+ strncpy(buf, cp, CCS_EXEC_TMPSIZE - 1);
5519+ if (!ccs_assign_domain(buf, true))
5520+ ccs_transition_failed(buf);
5521+ kfree(buf);
5522+}
5523+
5524+/**
5525+ * ccs_get_audit - Get audit mode.
5526+ *
5527+ * @r: Pointer to "struct ccs_request_info".
5528+ *
5529+ * Returns true if this request should be audited, false otherwise.
5530+ */
5531+static bool ccs_get_audit(const struct ccs_request_info *r)
5532+{
5533+ const struct ccs_acl_info *matched_acl = r->matched_acl;
5534+ const u8 profile = r->profile;
5535+ const u8 index = r->type;
5536+ const bool is_granted = r->granted;
5537+ u8 mode;
5538+ struct ccs_profile *p;
5539+ if (!ccs_policy_loaded)
5540+ return false;
5541+ p = ccs_profile(profile);
5542+ if (ccs_log_count >= p->pref[CCS_PREF_MAX_AUDIT_LOG])
5543+ return false;
5544+ if (is_granted && matched_acl && matched_acl->cond &&
5545+ matched_acl->cond->grant_log != CCS_GRANTLOG_AUTO)
5546+ return matched_acl->cond->grant_log == CCS_GRANTLOG_YES;
5547+ mode = p->config[index];
5548+ if (mode == CCS_CONFIG_USE_DEFAULT)
5549+ mode = p->config
5550+ [ccs_index2category[index] + CCS_MAX_MAC_INDEX];
5551+ if (mode == CCS_CONFIG_USE_DEFAULT)
5552+ mode = p->default_config;
5553+ if (is_granted)
5554+ return mode & CCS_CONFIG_WANT_GRANT_LOG;
5555+ return mode & CCS_CONFIG_WANT_REJECT_LOG;
5556+}
5557+
5558+/**
5559+ * ccs_write_log2 - Write an audit log.
5560+ *
5561+ * @r: Pointer to "struct ccs_request_info".
5562+ * @len: Buffer size needed for @fmt and @args.
5563+ * @fmt: The printf()'s format string.
5564+ * @args: va_list structure for @fmt.
5565+ *
5566+ * Returns nothing.
5567+ */
5568+static void ccs_write_log2(struct ccs_request_info *r, int len,
5569+ const char *fmt, va_list args)
5570+{
5571+ char *buf;
5572+ struct ccs_log *entry;
5573+ bool quota_exceeded = false;
5574+ if (!ccs_get_audit(r))
5575+ goto out;
5576+ buf = ccs_init_log(r, len, fmt, args);
5577+ if (!buf)
5578+ goto out;
5579+ entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
5580+ if (!entry) {
5581+ kfree(buf);
5582+ goto out;
5583+ }
5584+ entry->log = buf;
5585+ len = ccs_round2(strlen(buf) + 1);
5586+ /*
5587+ * The entry->size is used for memory quota checks.
5588+ * Don't go beyond strlen(entry->log).
5589+ */
5590+ entry->size = len + ccs_round2(sizeof(*entry));
5591+ spin_lock(&ccs_log_lock);
5592+ if (ccs_memory_quota[CCS_MEMORY_AUDIT] &&
5593+ ccs_memory_used[CCS_MEMORY_AUDIT] + entry->size >=
5594+ ccs_memory_quota[CCS_MEMORY_AUDIT]) {
5595+ quota_exceeded = true;
5596+ } else {
5597+ ccs_memory_used[CCS_MEMORY_AUDIT] += entry->size;
5598+ list_add_tail(&entry->list, &ccs_log);
5599+ ccs_log_count++;
5600+ }
5601+ spin_unlock(&ccs_log_lock);
5602+ if (quota_exceeded) {
5603+ kfree(buf);
5604+ kfree(entry);
5605+ goto out;
5606+ }
5607+ wake_up(&ccs_log_wait);
5608+out:
5609+ ccs_update_task_domain(r);
5610+}
5611+
5612+/**
5613+ * ccs_write_log - Write an audit log.
5614+ *
5615+ * @r: Pointer to "struct ccs_request_info".
5616+ * @fmt: The printf()'s format string, followed by parameters.
5617+ *
5618+ * Returns nothing.
5619+ */
5620+void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...)
5621+{
5622+ va_list args;
5623+ int len;
5624+ va_start(args, fmt);
5625+ len = vsnprintf((char *) &len, 1, fmt, args) + 1;
5626+ va_end(args);
5627+ va_start(args, fmt);
5628+ ccs_write_log2(r, len, fmt, args);
5629+ va_end(args);
5630+}
5631+
5632+/**
5633+ * ccs_read_log - Read an audit log.
5634+ *
5635+ * @head: Pointer to "struct ccs_io_buffer".
5636+ *
5637+ * Returns nothing.
5638+ */
5639+static void ccs_read_log(struct ccs_io_buffer *head)
5640+{
5641+ struct ccs_log *ptr = NULL;
5642+ if (head->r.w_pos)
5643+ return;
5644+ kfree(head->read_buf);
5645+ head->read_buf = NULL;
5646+ spin_lock(&ccs_log_lock);
5647+ if (!list_empty(&ccs_log)) {
5648+ ptr = list_entry(ccs_log.next, typeof(*ptr), list);
5649+ list_del(&ptr->list);
5650+ ccs_log_count--;
5651+ ccs_memory_used[CCS_MEMORY_AUDIT] -= ptr->size;
5652+ }
5653+ spin_unlock(&ccs_log_lock);
5654+ if (ptr) {
5655+ head->read_buf = ptr->log;
5656+ head->r.w[head->r.w_pos++] = head->read_buf;
5657+ kfree(ptr);
5658+ }
5659+}
5660+
5661+/**
5662+ * ccs_set_namespace_cursor - Set namespace to read.
5663+ *
5664+ * @head: Pointer to "struct ccs_io_buffer".
5665+ *
5666+ * Returns nothing.
5667+ */
5668+static void ccs_set_namespace_cursor(struct ccs_io_buffer *head)
5669+{
5670+ struct list_head *ns;
5671+ if (head->type != CCS_EXCEPTION_POLICY && head->type != CCS_PROFILE)
5672+ return;
5673+ /*
5674+ * If this is the first read, or reading previous namespace finished
5675+ * and has more namespaces to read, update the namespace cursor.
5676+ */
5677+ ns = head->r.ns;
5678+ if (!ns || (head->r.eof && ns->next != &ccs_namespace_list)) {
5679+ /* Clearing is OK because ccs_flush() returned true. */
5680+ memset(&head->r, 0, sizeof(head->r));
5681+ head->r.ns = ns ? ns->next : ccs_namespace_list.next;
5682+ }
5683+}
5684+
5685+/**
5686+ * ccs_has_more_namespace - Check for unread namespaces.
5687+ *
5688+ * @head: Pointer to "struct ccs_io_buffer".
5689+ *
5690+ * Returns true if we have more entries to print, false otherwise.
5691+ */
5692+static bool ccs_has_more_namespace(struct ccs_io_buffer *head)
5693+{
5694+ return (head->type == CCS_EXCEPTION_POLICY ||
5695+ head->type == CCS_PROFILE) && head->r.eof &&
5696+ head->r.ns->next != &ccs_namespace_list;
5697+}
5698+
5699+/**
5700+ * ccs_find_namespace - Find specified namespace.
5701+ *
5702+ * @name: Name of namespace to find.
5703+ * @len: Length of @name.
5704+ *
5705+ * Returns pointer to "struct ccs_policy_namespace" if found, NULL otherwise.
5706+ *
5707+ * Caller holds ccs_read_lock().
5708+ */
5709+static struct ccs_policy_namespace *ccs_find_namespace(const char *name,
5710+ const unsigned int len)
5711+{
5712+ struct ccs_policy_namespace *ns;
5713+ list_for_each_entry_srcu(ns, &ccs_namespace_list, namespace_list,
5714+ &ccs_ss) {
5715+ if (strncmp(name, ns->name, len) ||
5716+ (name[len] && name[len] != ' '))
5717+ continue;
5718+ return ns;
5719+ }
5720+ return NULL;
5721+}
5722+
5723+/**
5724+ * ccs_assign_namespace - Create a new namespace.
5725+ *
5726+ * @domainname: Name of namespace to create.
5727+ *
5728+ * Returns pointer to "struct ccs_policy_namespace" on success, NULL otherwise.
5729+ *
5730+ * Caller holds ccs_read_lock().
5731+ */
5732+static struct ccs_policy_namespace *ccs_assign_namespace
5733+(const char *domainname)
5734+{
5735+ struct ccs_policy_namespace *ptr;
5736+ struct ccs_policy_namespace *entry;
5737+ const char *cp = domainname;
5738+ unsigned int len = 0;
5739+ while (*cp && *cp++ != ' ')
5740+ len++;
5741+ ptr = ccs_find_namespace(domainname, len);
5742+ if (ptr)
5743+ return ptr;
5744+ if (len >= CCS_EXEC_TMPSIZE - 10 || !ccs_domain_def(domainname))
5745+ return NULL;
5746+ entry = kzalloc(sizeof(*entry) + len + 1, CCS_GFP_FLAGS);
5747+ if (!entry)
5748+ return NULL;
5749+ if (mutex_lock_interruptible(&ccs_policy_lock))
5750+ goto out;
5751+ ptr = ccs_find_namespace(domainname, len);
5752+ if (!ptr && ccs_memory_ok(entry, sizeof(*entry) + len + 1)) {
5753+ char *name = (char *) (entry + 1);
5754+ ptr = entry;
5755+ memmove(name, domainname, len);
5756+ name[len] = '\0';
5757+ entry->name = name;
5758+ ccs_init_policy_namespace(entry);
5759+ entry = NULL;
5760+ }
5761+ mutex_unlock(&ccs_policy_lock);
5762+out:
5763+ kfree(entry);
5764+ return ptr;
5765+}
5766+
5767+/**
5768+ * ccs_namespace_jump - Check for namespace jump.
5769+ *
5770+ * @domainname: Name of domain.
5771+ *
5772+ * Returns true if namespace differs, false otherwise.
5773+ */
5774+static bool ccs_namespace_jump(const char *domainname)
5775+{
5776+ const char *namespace = ccs_current_namespace()->name;
5777+ const int len = strlen(namespace);
5778+ return strncmp(domainname, namespace, len) ||
5779+ (domainname[len] && domainname[len] != ' ');
5780+}
5781+
5782+/**
5783+ * ccs_assign_domain - Create a domain or a namespace.
5784+ *
5785+ * @domainname: The name of domain.
5786+ * @transit: True if transit to domain found or created.
5787+ *
5788+ * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
5789+ *
5790+ * Caller holds ccs_read_lock().
5791+ */
5792+struct ccs_domain_info *ccs_assign_domain(const char *domainname,
5793+ const bool transit)
5794+{
5795+ struct ccs_security *security = ccs_current_security();
5796+ struct ccs_domain_info e = { };
5797+ struct ccs_domain_info *entry = ccs_find_domain(domainname);
5798+ bool created = false;
5799+ if (entry) {
5800+ if (transit) {
5801+ /*
5802+ * Since namespace is created at runtime, profiles may
5803+ * not be created by the moment the process transits to
5804+ * that domain. Do not perform domain transition if
5805+ * profile for that domain is not yet created.
5806+ */
5807+ if (ccs_policy_loaded &&
5808+ !entry->ns->profile_ptr[entry->profile])
5809+ return NULL;
5810+ security->ccs_domain_info = entry;
5811+ }
5812+ return entry;
5813+ }
5814+ /* Requested domain does not exist. */
5815+ /* Don't create requested domain if domainname is invalid. */
5816+ if (strlen(domainname) >= CCS_EXEC_TMPSIZE - 10 ||
5817+ !ccs_correct_domain(domainname))
5818+ return NULL;
5819+ /*
5820+ * Since definition of profiles and acl_groups may differ across
5821+ * namespaces, do not inherit "use_profile" and "use_group" settings
5822+ * by automatically creating requested domain upon domain transition.
5823+ */
5824+ if (transit && ccs_namespace_jump(domainname))
5825+ return NULL;
5826+ e.ns = ccs_assign_namespace(domainname);
5827+ if (!e.ns)
5828+ return NULL;
5829+ /*
5830+ * "use_profile" and "use_group" settings for automatically created
5831+ * domains are inherited from current domain. These are 0 for manually
5832+ * created domains.
5833+ */
5834+ if (transit) {
5835+ const struct ccs_domain_info *domain =
5836+ security->ccs_domain_info;
5837+ e.profile = domain->profile;
5838+ e.group = domain->group;
5839+ }
5840+ e.domainname = ccs_get_name(domainname);
5841+ if (!e.domainname)
5842+ return NULL;
5843+ if (mutex_lock_interruptible(&ccs_policy_lock))
5844+ goto out;
5845+ entry = ccs_find_domain(domainname);
5846+ if (!entry) {
5847+ entry = ccs_commit_ok(&e, sizeof(e));
5848+ if (entry) {
5849+ INIT_LIST_HEAD(&entry->acl_info_list);
5850+ list_add_tail_rcu(&entry->list, &ccs_domain_list);
5851+ created = true;
5852+ }
5853+ }
5854+ mutex_unlock(&ccs_policy_lock);
5855+out:
5856+ ccs_put_name(e.domainname);
5857+ if (entry && transit) {
5858+ security->ccs_domain_info = entry;
5859+ if (created) {
5860+ struct ccs_request_info r;
5861+ ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
5862+ r.granted = false;
5863+ ccs_write_log(&r, "use_profile %u\n", entry->profile);
5864+ ccs_write_log(&r, "use_group %u\n", entry->group);
5865+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
5866+ }
5867+ }
5868+ return entry;
5869+}
5870+
5871+/**
5872+ * ccs_parse_policy - Parse a policy line.
5873+ *
5874+ * @head: Poiter to "struct ccs_io_buffer".
5875+ * @line: Line to parse.
5876+ *
5877+ * Returns 0 on success, negative value otherwise.
5878+ *
5879+ * Caller holds ccs_read_lock().
5880+ */
5881+static int ccs_parse_policy(struct ccs_io_buffer *head, char *line)
5882+{
5883+ /* Delete request? */
5884+ head->w.is_delete = !strncmp(line, "delete ", 7);
5885+ if (head->w.is_delete)
5886+ memmove(line, line + 7, strlen(line + 7) + 1);
5887+ /* Selecting namespace to update. */
5888+ if (head->type == CCS_EXCEPTION_POLICY || head->type == CCS_PROFILE) {
5889+ if (*line == '<') {
5890+ char *cp = strchr(line, ' ');
5891+ if (cp) {
5892+ *cp++ = '\0';
5893+ head->w.ns = ccs_assign_namespace(line);
5894+ memmove(line, cp, strlen(cp) + 1);
5895+ } else
5896+ head->w.ns = NULL;
5897+ } else
5898+ head->w.ns = &ccs_kernel_namespace;
5899+ /* Don't allow updating if namespace is invalid. */
5900+ if (!head->w.ns)
5901+ return -ENOENT;
5902+ }
5903+ /* Do the update. */
5904+ switch (head->type) {
5905+ case CCS_DOMAIN_POLICY:
5906+ return ccs_write_domain(head);
5907+ case CCS_EXCEPTION_POLICY:
5908+ return ccs_write_exception(head);
5909+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
5910+ case CCS_EXECUTE_HANDLER:
5911+#endif
5912+ case CCS_PROCESS_STATUS:
5913+ return ccs_write_pid(head);
5914+ case CCS_STAT:
5915+ return ccs_write_stat(head);
5916+ case CCS_PROFILE:
5917+ return ccs_write_profile(head);
5918+ case CCS_QUERY:
5919+ return ccs_write_answer(head);
5920+ case CCS_MANAGER:
5921+ return ccs_write_manager(head);
5922+ default:
5923+ return -ENOSYS;
5924+ }
5925+}
5926+
5927+/**
5928+ * ccs_policy_io_init - Register hooks for policy I/O.
5929+ *
5930+ * Returns nothing.
5931+ */
5932+static void __init ccs_policy_io_init(void)
5933+{
5934+ ccsecurity_ops.check_profile = ccs_check_profile;
5935+}
5936+
5937+/**
5938+ * ccs_load_builtin_policy - Load built-in policy.
5939+ *
5940+ * Returns nothing.
5941+ */
5942+static void __init ccs_load_builtin_policy(void)
5943+{
5944+ /*
5945+ * This include file is manually created and contains built-in policy
5946+ * named "ccs_builtin_profile", "ccs_builtin_exception_policy",
5947+ * "ccs_builtin_domain_policy", "ccs_builtin_manager",
5948+ * "ccs_builtin_stat" in the form of "static char [] __initdata".
5949+ */
5950+#include "builtin-policy.h"
5951+ u8 i;
5952+ const int idx = ccs_read_lock();
5953+ for (i = 0; i < 5; i++) {
5954+ struct ccs_io_buffer head = { };
5955+ char *start = "";
5956+ switch (i) {
5957+ case 0:
5958+ start = ccs_builtin_profile;
5959+ head.type = CCS_PROFILE;
5960+ break;
5961+ case 1:
5962+ start = ccs_builtin_exception_policy;
5963+ head.type = CCS_EXCEPTION_POLICY;
5964+ break;
5965+ case 2:
5966+ start = ccs_builtin_domain_policy;
5967+ head.type = CCS_DOMAIN_POLICY;
5968+ break;
5969+ case 3:
5970+ start = ccs_builtin_manager;
5971+ head.type = CCS_MANAGER;
5972+ break;
5973+ case 4:
5974+ start = ccs_builtin_stat;
5975+ head.type = CCS_STAT;
5976+ break;
5977+ }
5978+ while (1) {
5979+ char *end = strchr(start, '\n');
5980+ if (!end)
5981+ break;
5982+ *end = '\0';
5983+ ccs_normalize_line(start);
5984+ head.write_buf = start;
5985+ ccs_parse_policy(&head, start);
5986+ start = end + 1;
5987+ }
5988+ }
5989+ ccs_read_unlock(idx);
5990+#ifdef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
5991+ ccs_check_profile();
5992+#endif
5993+}
5994+
5995+/**
5996+ * ccs_read_self - read() for /proc/ccs/self_domain interface.
5997+ *
5998+ * @file: Pointer to "struct file".
5999+ * @buf: Domainname which current thread belongs to.
6000+ * @count: Size of @buf.
6001+ * @ppos: Bytes read by now.
6002+ *
6003+ * Returns read size on success, negative value otherwise.
6004+ */
6005+static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
6006+ loff_t *ppos)
6007+{
6008+ const char *domain = ccs_current_domain()->domainname->name;
6009+ loff_t len = strlen(domain);
6010+ loff_t pos = *ppos;
6011+ if (pos >= len || !count)
6012+ return 0;
6013+ len -= pos;
6014+ if (count < len)
6015+ len = count;
6016+ if (copy_to_user(buf, domain + pos, len))
6017+ return -EFAULT;
6018+ *ppos += len;
6019+ return len;
6020+}
6021+
6022+/**
6023+ * ccs_open - open() for /proc/ccs/ interface.
6024+ *
6025+ * @inode: Pointer to "struct inode".
6026+ * @file: Pointer to "struct file".
6027+ *
6028+ * Returns 0 on success, negative value otherwise.
6029+ */
6030+static int ccs_open(struct inode *inode, struct file *file)
6031+{
6032+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
6033+ const u8 type = (unsigned long) PDE_DATA(inode);
6034+#else
6035+ const u8 type = (unsigned long) PDE(inode)->data;
6036+#endif
6037+ struct ccs_io_buffer *head = kzalloc(sizeof(*head), CCS_GFP_FLAGS);
6038+ if (!head)
6039+ return -ENOMEM;
6040+ mutex_init(&head->io_sem);
6041+ head->type = type;
6042+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
6043+ if (type == CCS_EXECUTE_HANDLER) {
6044+ /* Allow execute_handler to read process's status. */
6045+ if (!(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
6046+ kfree(head);
6047+ return -EPERM;
6048+ }
6049+ }
6050+#endif
6051+ if ((file->f_mode & FMODE_READ) && type != CCS_AUDIT &&
6052+ type != CCS_QUERY) {
6053+ /* Don't allocate read_buf for poll() access. */
6054+ head->readbuf_size = 4096;
6055+ head->read_buf = kzalloc(head->readbuf_size, CCS_GFP_FLAGS);
6056+ if (!head->read_buf) {
6057+ kfree(head);
6058+ return -ENOMEM;
6059+ }
6060+ }
6061+ if (file->f_mode & FMODE_WRITE) {
6062+ head->writebuf_size = 4096;
6063+ head->write_buf = kzalloc(head->writebuf_size, CCS_GFP_FLAGS);
6064+ if (!head->write_buf) {
6065+ kfree(head->read_buf);
6066+ kfree(head);
6067+ return -ENOMEM;
6068+ }
6069+ }
6070+ /*
6071+ * If the file is /proc/ccs/query, increment the observer counter.
6072+ * The obserber counter is used by ccs_supervisor() to see if
6073+ * there is some process monitoring /proc/ccs/query.
6074+ */
6075+ if (type == CCS_QUERY)
6076+ atomic_inc(&ccs_query_observers);
6077+ file->private_data = head;
6078+ ccs_notify_gc(head, true);
6079+ return 0;
6080+}
6081+
6082+/**
6083+ * ccs_release - close() for /proc/ccs/ interface.
6084+ *
6085+ * @inode: Pointer to "struct inode".
6086+ * @file: Pointer to "struct file".
6087+ *
6088+ * Returns 0.
6089+ */
6090+static int ccs_release(struct inode *inode, struct file *file)
6091+{
6092+ struct ccs_io_buffer *head = file->private_data;
6093+ /*
6094+ * If the file is /proc/ccs/query, decrement the observer counter.
6095+ */
6096+ if (head->type == CCS_QUERY &&
6097+ atomic_dec_and_test(&ccs_query_observers))
6098+ wake_up_all(&ccs_answer_wait);
6099+ ccs_notify_gc(head, false);
6100+ return 0;
6101+}
6102+
6103+/**
6104+ * ccs_poll - poll() for /proc/ccs/ interface.
6105+ *
6106+ * @file: Pointer to "struct file".
6107+ * @wait: Pointer to "poll_table". Maybe NULL.
6108+ *
6109+ * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
6110+ * POLLOUT | POLLWRNORM otherwise.
6111+ */
6112+static unsigned int ccs_poll(struct file *file, poll_table *wait)
6113+{
6114+ struct ccs_io_buffer *head = file->private_data;
6115+ if (head->type == CCS_AUDIT) {
6116+ if (!ccs_memory_used[CCS_MEMORY_AUDIT]) {
6117+ poll_wait(file, &ccs_log_wait, wait);
6118+ if (!ccs_memory_used[CCS_MEMORY_AUDIT])
6119+ return POLLOUT | POLLWRNORM;
6120+ }
6121+ } else if (head->type == CCS_QUERY) {
6122+ if (list_empty(&ccs_query_list)) {
6123+ poll_wait(file, &ccs_query_wait, wait);
6124+ if (list_empty(&ccs_query_list))
6125+ return POLLOUT | POLLWRNORM;
6126+ }
6127+ }
6128+ return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
6129+}
6130+
6131+/**
6132+ * ccs_read - read() for /proc/ccs/ interface.
6133+ *
6134+ * @file: Pointer to "struct file".
6135+ * @buf: Pointer to buffer.
6136+ * @count: Size of @buf.
6137+ * @ppos: Unused.
6138+ *
6139+ * Returns bytes read on success, negative value otherwise.
6140+ */
6141+static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
6142+ loff_t *ppos)
6143+{
6144+ struct ccs_io_buffer *head = file->private_data;
6145+ int len;
6146+ int idx;
6147+ if (mutex_lock_interruptible(&head->io_sem))
6148+ return -EINTR;
6149+ head->read_user_buf = buf;
6150+ head->read_user_buf_avail = count;
6151+ idx = ccs_read_lock();
6152+ if (ccs_flush(head))
6153+ /* Call the policy handler. */
6154+ do {
6155+ ccs_set_namespace_cursor(head);
6156+ switch (head->type) {
6157+ case CCS_DOMAIN_POLICY:
6158+ ccs_read_domain(head);
6159+ break;
6160+ case CCS_EXCEPTION_POLICY:
6161+ ccs_read_exception(head);
6162+ break;
6163+ case CCS_AUDIT:
6164+ ccs_read_log(head);
6165+ break;
6166+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
6167+ case CCS_EXECUTE_HANDLER:
6168+#endif
6169+ case CCS_PROCESS_STATUS:
6170+ ccs_read_pid(head);
6171+ break;
6172+ case CCS_VERSION:
6173+ ccs_read_version(head);
6174+ break;
6175+ case CCS_STAT:
6176+ ccs_read_stat(head);
6177+ break;
6178+ case CCS_PROFILE:
6179+ ccs_read_profile(head);
6180+ break;
6181+ case CCS_QUERY:
6182+ ccs_read_query(head);
6183+ break;
6184+ case CCS_MANAGER:
6185+ ccs_read_manager(head);
6186+ break;
6187+ }
6188+ } while (ccs_flush(head) && ccs_has_more_namespace(head));
6189+ ccs_read_unlock(idx);
6190+ len = head->read_user_buf - buf;
6191+ mutex_unlock(&head->io_sem);
6192+ return len;
6193+}
6194+
6195+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
6196+
6197+/**
6198+ * ccs_write_self - write() for /proc/ccs/self_domain interface.
6199+ *
6200+ * @file: Pointer to "struct file".
6201+ * @buf: Domainname to transit to.
6202+ * @count: Size of @buf.
6203+ * @ppos: Unused.
6204+ *
6205+ * Returns @count on success, negative value otherwise.
6206+ *
6207+ * If domain transition was permitted but the domain transition failed, this
6208+ * function returns error rather than terminating current thread with SIGKILL.
6209+ */
6210+static ssize_t ccs_write_self(struct file *file, const char __user *buf,
6211+ size_t count, loff_t *ppos)
6212+{
6213+ char *data;
6214+ int error;
6215+ if (!count || count >= CCS_EXEC_TMPSIZE - 10)
6216+ return -ENOMEM;
6217+ data = kzalloc(count + 1, CCS_GFP_FLAGS);
6218+ if (!data)
6219+ return -ENOMEM;
6220+ if (copy_from_user(data, buf, count)) {
6221+ error = -EFAULT;
6222+ goto out;
6223+ }
6224+ ccs_normalize_line(data);
6225+ if (ccs_correct_domain(data)) {
6226+ const int idx = ccs_read_lock();
6227+ struct ccs_path_info name;
6228+ struct ccs_request_info r;
6229+ name.name = data;
6230+ ccs_fill_path_info(&name);
6231+ /* Check "task manual_domain_transition" permission. */
6232+ ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
6233+ r.param_type = CCS_TYPE_MANUAL_TASK_ACL;
6234+ r.param.task.domainname = &name;
6235+ ccs_check_acl(&r);
6236+ if (!r.granted)
6237+ error = -EPERM;
6238+ else
6239+ error = ccs_assign_domain(data, true) ? 0 : -ENOENT;
6240+ ccs_read_unlock(idx);
6241+ } else
6242+ error = -EINVAL;
6243+out:
6244+ kfree(data);
6245+ return error ? error : count;
6246+}
6247+
6248+#endif
6249+
6250+/**
6251+ * ccs_write - write() for /proc/ccs/ interface.
6252+ *
6253+ * @file: Pointer to "struct file".
6254+ * @buf: Pointer to buffer.
6255+ * @count: Size of @buf.
6256+ * @ppos: Unused.
6257+ *
6258+ * Returns @count on success, negative value otherwise.
6259+ */
6260+static ssize_t ccs_write(struct file *file, const char __user *buf,
6261+ size_t count, loff_t *ppos)
6262+{
6263+ struct ccs_io_buffer *head = file->private_data;
6264+ int error = count;
6265+ char *cp0 = head->write_buf;
6266+ int idx;
6267+ if (mutex_lock_interruptible(&head->io_sem))
6268+ return -EINTR;
6269+ head->read_user_buf_avail = 0;
6270+ idx = ccs_read_lock();
6271+ /* Read a line and dispatch it to the policy handler. */
6272+ while (count) {
6273+ char c;
6274+ if (head->w.avail >= head->writebuf_size - 1) {
6275+ const int len = head->writebuf_size * 2;
6276+ char *cp = kzalloc(len, CCS_GFP_FLAGS);
6277+ if (!cp) {
6278+ error = -ENOMEM;
6279+ break;
6280+ }
6281+ memmove(cp, cp0, head->w.avail);
6282+ kfree(cp0);
6283+ head->write_buf = cp;
6284+ cp0 = cp;
6285+ head->writebuf_size = len;
6286+ }
6287+ if (get_user(c, buf)) {
6288+ error = -EFAULT;
6289+ break;
6290+ }
6291+ buf++;
6292+ count--;
6293+ cp0[head->w.avail++] = c;
6294+ if (c != '\n')
6295+ continue;
6296+ cp0[head->w.avail - 1] = '\0';
6297+ head->w.avail = 0;
6298+ ccs_normalize_line(cp0);
6299+ if (!strcmp(cp0, "reset")) {
6300+ head->w.ns = &ccs_kernel_namespace;
6301+ head->w.domain = NULL;
6302+ memset(&head->r, 0, sizeof(head->r));
6303+ continue;
6304+ }
6305+ /* Don't allow updating policies by non manager programs. */
6306+ switch (head->type) {
6307+ case CCS_PROCESS_STATUS:
6308+ /* This does not write anything. */
6309+ break;
6310+ case CCS_DOMAIN_POLICY:
6311+ if (ccs_select_domain(head, cp0))
6312+ continue;
6313+ /* fall through */
6314+ case CCS_EXCEPTION_POLICY:
6315+ if (!strcmp(cp0, "select transition_only")) {
6316+ head->r.print_transition_related_only = true;
6317+ continue;
6318+ }
6319+ /* fall through */
6320+ default:
6321+ if (!ccs_manager()) {
6322+ error = -EPERM;
6323+ goto out;
6324+ }
6325+ }
6326+ switch (ccs_parse_policy(head, cp0)) {
6327+ case -EPERM:
6328+ error = -EPERM;
6329+ goto out;
6330+ case 0:
6331+ /* Update statistics. */
6332+ switch (head->type) {
6333+ case CCS_DOMAIN_POLICY:
6334+ case CCS_EXCEPTION_POLICY:
6335+ case CCS_STAT:
6336+ case CCS_PROFILE:
6337+ case CCS_MANAGER:
6338+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
6339+ break;
6340+ default:
6341+ break;
6342+ }
6343+ break;
6344+ }
6345+ }
6346+out:
6347+ ccs_read_unlock(idx);
6348+ mutex_unlock(&head->io_sem);
6349+ return error;
6350+}
6351+
6352+/**
6353+ * ccs_create_entry - Create interface files under /proc/ccs/ directory.
6354+ *
6355+ * @name: The name of the interface file.
6356+ * @mode: The permission of the interface file.
6357+ * @parent: The parent directory.
6358+ * @key: Type of interface.
6359+ *
6360+ * Returns nothing.
6361+ */
6362+static void __init ccs_create_entry(const char *name, const umode_t mode,
6363+ struct proc_dir_entry *parent,
6364+ const u8 key)
6365+{
6366+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
6367+ proc_create_data(name, mode, parent, &ccs_operations,
6368+ ((u8 *) NULL) + key);
6369+#else
6370+ struct proc_dir_entry *entry = create_proc_entry(name, mode, parent);
6371+ if (entry) {
6372+ entry->proc_fops = &ccs_operations;
6373+ entry->data = ((u8 *) NULL) + key;
6374+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
6375+ if (entry->proc_iops)
6376+ ccs_file_inode_operations = *entry->proc_iops;
6377+ if (!ccs_file_inode_operations.setattr)
6378+ ccs_file_inode_operations.setattr = proc_notify_change;
6379+ entry->proc_iops = &ccs_file_inode_operations;
6380+#endif
6381+ }
6382+#endif
6383+}
6384+
6385+/**
6386+ * ccs_proc_init - Initialize /proc/ccs/ interface.
6387+ *
6388+ * Returns nothing.
6389+ */
6390+static void __init ccs_proc_init(void)
6391+{
6392+ struct proc_dir_entry *ccs_dir = proc_mkdir("ccs", NULL);
6393+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
6394+ if (ccs_dir->proc_iops)
6395+ ccs_dir_inode_operations = *ccs_dir->proc_iops;
6396+ if (!ccs_dir_inode_operations.setattr)
6397+ ccs_dir_inode_operations.setattr = proc_notify_change;
6398+ ccs_dir->proc_iops = &ccs_dir_inode_operations;
6399+#endif
6400+ ccs_create_entry("query", 0600, ccs_dir, CCS_QUERY);
6401+ ccs_create_entry("domain_policy", 0600, ccs_dir, CCS_DOMAIN_POLICY);
6402+ ccs_create_entry("exception_policy", 0600, ccs_dir,
6403+ CCS_EXCEPTION_POLICY);
6404+ ccs_create_entry("audit", 0400, ccs_dir, CCS_AUDIT);
6405+ ccs_create_entry(".process_status", 0600, ccs_dir,
6406+ CCS_PROCESS_STATUS);
6407+ ccs_create_entry("stat", 0644, ccs_dir, CCS_STAT);
6408+ ccs_create_entry("profile", 0600, ccs_dir, CCS_PROFILE);
6409+ ccs_create_entry("manager", 0600, ccs_dir, CCS_MANAGER);
6410+ ccs_create_entry("version", 0400, ccs_dir, CCS_VERSION);
6411+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
6412+ ccs_create_entry(".execute_handler", 0666, ccs_dir,
6413+ CCS_EXECUTE_HANDLER);
6414+#endif
6415+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
6416+ proc_create("self_domain", 0666, ccs_dir, &ccs_self_operations);
6417+#else
6418+ {
6419+ struct proc_dir_entry *e = create_proc_entry("self_domain",
6420+ 0666, ccs_dir);
6421+ if (e)
6422+ e->proc_fops = &ccs_self_operations;
6423+ }
6424+#endif
6425+}
6426+
6427+/**
6428+ * ccs_init_module - Initialize this module.
6429+ *
6430+ * Returns 0 on success, negative value otherwise.
6431+ */
6432+static int __init ccs_init_module(void)
6433+{
6434+ if (ccsecurity_ops.disabled)
6435+ return -EINVAL;
6436+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
6437+ MOD_INC_USE_COUNT;
6438+#endif
6439+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
6440+ if (init_srcu_struct(&ccs_ss))
6441+ panic("Out of memory.");
6442+#endif
6443+ ccs_kernel_namespace.name = "<kernel>";
6444+ ccs_init_policy_namespace(&ccs_kernel_namespace);
6445+ ccs_kernel_domain.ns = &ccs_kernel_namespace;
6446+ INIT_LIST_HEAD(&ccs_kernel_domain.acl_info_list);
6447+ ccs_mm_init();
6448+ ccs_policy_io_init();
6449+ ccs_permission_init();
6450+ ccs_proc_init();
6451+ ccs_load_builtin_policy();
6452+ return 0;
6453+}
6454+
6455+/**
6456+ * ccs_main_init - Initialize this module.
6457+ *
6458+ * Returns nothing.
6459+ */
6460+void __init ccs_main_init(void)
6461+{
6462+ ccs_init_module();
6463+}
--- tags/patches/1.0.33/permission.c (nonexistent)
+++ tags/patches/1.0.33/permission.c (revision 502)
@@ -0,0 +1,5028 @@
1+/*
2+ * security/ccsecurity/permission.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
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+/* Mapping table from "enum ccs_path_acl_index" to "enum ccs_mac_index". */
46+static const u8 ccs_p2mac[CCS_MAX_PATH_OPERATION] = {
47+ [CCS_TYPE_EXECUTE] = CCS_MAC_FILE_EXECUTE,
48+ [CCS_TYPE_READ] = CCS_MAC_FILE_OPEN,
49+ [CCS_TYPE_WRITE] = CCS_MAC_FILE_OPEN,
50+ [CCS_TYPE_APPEND] = CCS_MAC_FILE_OPEN,
51+ [CCS_TYPE_UNLINK] = CCS_MAC_FILE_UNLINK,
52+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
53+ [CCS_TYPE_GETATTR] = CCS_MAC_FILE_GETATTR,
54+#endif
55+ [CCS_TYPE_RMDIR] = CCS_MAC_FILE_RMDIR,
56+ [CCS_TYPE_TRUNCATE] = CCS_MAC_FILE_TRUNCATE,
57+ [CCS_TYPE_SYMLINK] = CCS_MAC_FILE_SYMLINK,
58+ [CCS_TYPE_CHROOT] = CCS_MAC_FILE_CHROOT,
59+ [CCS_TYPE_UMOUNT] = CCS_MAC_FILE_UMOUNT,
60+};
61+
62+/* Mapping table from "enum ccs_mkdev_acl_index" to "enum ccs_mac_index". */
63+const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION] = {
64+ [CCS_TYPE_MKBLOCK] = CCS_MAC_FILE_MKBLOCK,
65+ [CCS_TYPE_MKCHAR] = CCS_MAC_FILE_MKCHAR,
66+};
67+
68+/* Mapping table from "enum ccs_path2_acl_index" to "enum ccs_mac_index". */
69+const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION] = {
70+ [CCS_TYPE_LINK] = CCS_MAC_FILE_LINK,
71+ [CCS_TYPE_RENAME] = CCS_MAC_FILE_RENAME,
72+ [CCS_TYPE_PIVOT_ROOT] = CCS_MAC_FILE_PIVOT_ROOT,
73+};
74+
75+/*
76+ * Mapping table from "enum ccs_path_number_acl_index" to "enum ccs_mac_index".
77+ */
78+const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION] = {
79+ [CCS_TYPE_CREATE] = CCS_MAC_FILE_CREATE,
80+ [CCS_TYPE_MKDIR] = CCS_MAC_FILE_MKDIR,
81+ [CCS_TYPE_MKFIFO] = CCS_MAC_FILE_MKFIFO,
82+ [CCS_TYPE_MKSOCK] = CCS_MAC_FILE_MKSOCK,
83+ [CCS_TYPE_IOCTL] = CCS_MAC_FILE_IOCTL,
84+ [CCS_TYPE_CHMOD] = CCS_MAC_FILE_CHMOD,
85+ [CCS_TYPE_CHOWN] = CCS_MAC_FILE_CHOWN,
86+ [CCS_TYPE_CHGRP] = CCS_MAC_FILE_CHGRP,
87+};
88+
89+#ifdef CONFIG_CCSECURITY_NETWORK
90+
91+/*
92+ * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
93+ * inet domain socket.
94+ */
95+static const u8 ccs_inet2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
96+ [SOCK_STREAM] = {
97+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_STREAM_BIND,
98+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_INET_STREAM_LISTEN,
99+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_INET_STREAM_CONNECT,
100+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
101+ },
102+ [SOCK_DGRAM] = {
103+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_DGRAM_BIND,
104+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_INET_DGRAM_SEND,
105+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
106+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_INET_DGRAM_RECV,
107+#endif
108+ },
109+ [SOCK_RAW] = {
110+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_RAW_BIND,
111+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_INET_RAW_SEND,
112+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
113+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_INET_RAW_RECV,
114+#endif
115+ },
116+};
117+
118+/*
119+ * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
120+ * unix domain socket.
121+ */
122+static const u8 ccs_unix2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
123+ [SOCK_STREAM] = {
124+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_STREAM_BIND,
125+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
126+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
127+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
128+ },
129+ [SOCK_DGRAM] = {
130+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
131+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
132+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
133+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
134+#endif
135+ },
136+ [SOCK_SEQPACKET] = {
137+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
138+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
139+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
140+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
141+ },
142+};
143+
144+#endif
145+
146+#ifdef CONFIG_CCSECURITY_CAPABILITY
147+
148+/*
149+ * Mapping table from "enum ccs_capability_acl_index" to "enum ccs_mac_index".
150+ */
151+const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX] = {
152+ [CCS_USE_ROUTE_SOCKET] = CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
153+ [CCS_USE_PACKET_SOCKET] = CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
154+ [CCS_SYS_REBOOT] = CCS_MAC_CAPABILITY_SYS_REBOOT,
155+ [CCS_SYS_VHANGUP] = CCS_MAC_CAPABILITY_SYS_VHANGUP,
156+ [CCS_SYS_SETTIME] = CCS_MAC_CAPABILITY_SYS_SETTIME,
157+ [CCS_SYS_NICE] = CCS_MAC_CAPABILITY_SYS_NICE,
158+ [CCS_SYS_SETHOSTNAME] = CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
159+ [CCS_USE_KERNEL_MODULE] = CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
160+ [CCS_SYS_KEXEC_LOAD] = CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
161+ [CCS_SYS_PTRACE] = CCS_MAC_CAPABILITY_SYS_PTRACE,
162+};
163+
164+#endif
165+
166+/***** SECTION2: Structure definition *****/
167+
168+/* Structure for holding inet domain socket's address. */
169+struct ccs_inet_addr_info {
170+ u16 port; /* In network byte order. */
171+ const u32 *address; /* In network byte order. */
172+ bool is_ipv6;
173+};
174+
175+/* Structure for holding unix domain socket's address. */
176+struct ccs_unix_addr_info {
177+ u8 *addr; /* This may not be '\0' terminated string. */
178+ unsigned int addr_len;
179+};
180+
181+/* Structure for holding socket address. */
182+struct ccs_addr_info {
183+ u8 protocol;
184+ u8 operation;
185+ struct ccs_inet_addr_info inet;
186+ struct ccs_unix_addr_info unix0;
187+};
188+
189+/***** SECTION3: Prototype definition section *****/
190+
191+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
192+ struct ccs_page_dump *dump);
193+void ccs_get_attributes(struct ccs_obj_info *obj);
194+
195+static bool ccs_alphabet_char(const char c);
196+static bool ccs_argv(const unsigned int index, const char *arg_ptr,
197+ const int argc, const struct ccs_argv *argv, u8 *checked);
198+static bool ccs_byte_range(const char *str);
199+static bool ccs_check_entry(struct ccs_request_info *r,
200+ struct ccs_acl_info *ptr);
201+static bool ccs_check_mkdev_acl(struct ccs_request_info *r,
202+ const struct ccs_acl_info *ptr);
203+static bool ccs_check_mount_acl(struct ccs_request_info *r,
204+ const struct ccs_acl_info *ptr);
205+static bool ccs_check_path2_acl(struct ccs_request_info *r,
206+ const struct ccs_acl_info *ptr);
207+static bool ccs_check_path_acl(struct ccs_request_info *r,
208+ const struct ccs_acl_info *ptr);
209+static bool ccs_check_path_number_acl(struct ccs_request_info *r,
210+ const struct ccs_acl_info *ptr);
211+static bool ccs_compare_number_union(const unsigned long value,
212+ const struct ccs_number_union *ptr);
213+static bool ccs_condition(struct ccs_request_info *r,
214+ const struct ccs_condition *cond);
215+static bool ccs_decimal(const char c);
216+static bool ccs_envp(const char *env_name, const char *env_value,
217+ const int envc, const struct ccs_envp *envp, u8 *checked);
218+static bool ccs_file_matches_pattern(const char *filename,
219+ const char *filename_end,
220+ const char *pattern,
221+ const char *pattern_end);
222+static bool ccs_file_matches_pattern2(const char *filename,
223+ const char *filename_end,
224+ const char *pattern,
225+ const char *pattern_end);
226+static bool ccs_get_realpath(struct ccs_path_info *buf, struct path *path);
227+static bool ccs_hexadecimal(const char c);
228+static bool ccs_number_matches_group(const unsigned long min,
229+ const unsigned long max,
230+ const struct ccs_group *group);
231+static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
232+ const struct ccs_path_info *pattern);
233+static bool ccs_path_matches_pattern2(const char *f, const char *p);
234+static bool ccs_scan_bprm(struct ccs_execve *ee, const u16 argc,
235+ const struct ccs_argv *argv, const u16 envc,
236+ const struct ccs_envp *envp);
237+static bool ccs_scan_exec_realpath(struct file *file,
238+ const struct ccs_name_union *ptr,
239+ const bool match);
240+static bool ccs_scan_transition(const struct list_head *list,
241+ const struct ccs_path_info *domainname,
242+ const struct ccs_path_info *program,
243+ const char *last_name,
244+ const enum ccs_transition_type type);
245+static const char *ccs_last_word(const char *name);
246+static const struct ccs_path_info *ccs_compare_name_union
247+(const struct ccs_path_info *name, const struct ccs_name_union *ptr);
248+static const struct ccs_path_info *ccs_path_matches_group
249+(const struct ccs_path_info *pathname, const struct ccs_group *group);
250+static enum ccs_transition_type ccs_transition_type
251+(const struct ccs_policy_namespace *ns, const struct ccs_path_info *domainname,
252+ const struct ccs_path_info *program);
253+static int __ccs_chmod_permission(struct dentry *dentry,
254+ struct vfsmount *vfsmnt, mode_t mode);
255+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
256+static int __ccs_chown_permission(struct dentry *dentry,
257+ struct vfsmount *vfsmnt, kuid_t user,
258+ kgid_t group);
259+#else
260+static int __ccs_chown_permission(struct dentry *dentry,
261+ struct vfsmount *vfsmnt, uid_t user,
262+ gid_t group);
263+#endif
264+static int __ccs_chroot_permission(struct path *path);
265+static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
266+ unsigned long arg);
267+static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
268+ unsigned long arg);
269+static int __ccs_link_permission(struct dentry *old_dentry,
270+ struct dentry *new_dentry,
271+ struct vfsmount *mnt);
272+static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
273+ unsigned int mode);
274+static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
275+ const unsigned int mode, unsigned int dev);
276+static int __ccs_mount_permission(const char *dev_name, struct path *path,
277+ const char *type, unsigned long flags,
278+ void *data_page);
279+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
280+static int __ccs_open_exec_permission(struct dentry *dentry,
281+ struct vfsmount *mnt);
282+#endif
283+static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
284+ const int flag);
285+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
286+static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
287+ void __user *newval, struct ctl_table *table);
288+#endif
289+static int __ccs_pivot_root_permission(struct path *old_path,
290+ struct path *new_path);
291+static int __ccs_rename_permission(struct dentry *old_dentry,
292+ struct dentry *new_dentry,
293+ struct vfsmount *mnt);
294+static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt);
295+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
296+static int __ccs_search_binary_handler(struct linux_binprm *bprm);
297+#else
298+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
299+ struct pt_regs *regs);
300+#endif
301+static int __ccs_symlink_permission(struct dentry *dentry,
302+ struct vfsmount *mnt, const char *from);
303+static int __ccs_truncate_permission(struct dentry *dentry,
304+ struct vfsmount *mnt);
305+static int __ccs_umount_permission(struct vfsmount *mnt, int flags);
306+static int __ccs_unlink_permission(struct dentry *dentry,
307+ struct vfsmount *mnt);
308+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
309+static int __ccs_uselib_permission(struct dentry *dentry,
310+ struct vfsmount *mnt);
311+#endif
312+static int ccs_execute_permission(struct ccs_request_info *r,
313+ const struct ccs_path_info *filename);
314+static int ccs_find_next_domain(struct ccs_execve *ee);
315+static int ccs_get_path(const char *pathname, struct path *path);
316+static int ccs_kern_path(const char *pathname, int flags, struct path *path);
317+static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
318+ struct vfsmount *mnt, const unsigned int mode,
319+ unsigned int dev);
320+static int ccs_mount_acl(struct ccs_request_info *r, const char *dev_name,
321+ struct path *dir, const char *type,
322+ unsigned long flags);
323+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
324+static int ccs_new_open_permission(struct file *filp);
325+#endif
326+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
327+static int ccs_old_chroot_permission(struct nameidata *nd);
328+static int ccs_old_mount_permission(const char *dev_name, struct nameidata *nd,
329+ const char *type, unsigned long flags,
330+ void *data_page);
331+static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
332+ struct nameidata *new_nd);
333+#endif
334+static int ccs_path2_perm(const u8 operation, struct dentry *dentry1,
335+ struct vfsmount *mnt1, struct dentry *dentry2,
336+ struct vfsmount *mnt2);
337+static int ccs_path_number_perm(const u8 type, struct dentry *dentry,
338+ struct vfsmount *vfsmnt, unsigned long number);
339+static int ccs_path_perm(const u8 operation, struct dentry *dentry,
340+ struct vfsmount *mnt, const char *target);
341+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) || !defined(CONFIG_SYSCTL_SYSCALL)
342+static
343+#endif
344+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
345+ const struct ccs_path_info *filename);
346+static int ccs_symlink_path(const char *pathname, struct ccs_path_info *name);
347+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
348+static void __ccs_clear_open_mode(void);
349+static void __ccs_save_open_mode(int mode);
350+#endif
351+static void ccs_add_slash(struct ccs_path_info *buf);
352+
353+#ifdef CONFIG_CCSECURITY_MISC
354+static bool ccs_check_env_acl(struct ccs_request_info *r,
355+ const struct ccs_acl_info *ptr);
356+static int ccs_env_perm(struct ccs_request_info *r, const char *env);
357+static int ccs_environ(struct ccs_execve *ee);
358+#endif
359+
360+#ifdef CONFIG_CCSECURITY_CAPABILITY
361+static bool __ccs_capable(const u8 operation);
362+static bool ccs_check_capability_acl(struct ccs_request_info *r,
363+ const struct ccs_acl_info *ptr);
364+static bool ccs_kernel_service(void);
365+static int __ccs_ptrace_permission(long request, long pid);
366+static int __ccs_socket_create_permission(int family, int type, int protocol);
367+#endif
368+
369+#ifdef CONFIG_CCSECURITY_NETWORK
370+static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
371+ const struct ccs_group *group);
372+static bool ccs_check_inet_acl(struct ccs_request_info *r,
373+ const struct ccs_acl_info *ptr);
374+static bool ccs_check_unix_acl(struct ccs_request_info *r,
375+ const struct ccs_acl_info *ptr);
376+static bool ccs_kernel_service(void);
377+static int __ccs_socket_bind_permission(struct socket *sock,
378+ struct sockaddr *addr, int addr_len);
379+static int __ccs_socket_connect_permission(struct socket *sock,
380+ struct sockaddr *addr,
381+ int addr_len);
382+static int __ccs_socket_listen_permission(struct socket *sock);
383+static int __ccs_socket_post_accept_permission(struct socket *sock,
384+ struct socket *newsock);
385+static int __ccs_socket_sendmsg_permission(struct socket *sock,
386+ struct msghdr *msg, int size);
387+static int ccs_check_inet_address(const struct sockaddr *addr,
388+ const unsigned int addr_len, const u16 port,
389+ struct ccs_addr_info *address);
390+static int ccs_check_unix_address(struct sockaddr *addr,
391+ const unsigned int addr_len,
392+ struct ccs_addr_info *address);
393+static int ccs_inet_entry(const struct ccs_addr_info *address);
394+static int ccs_unix_entry(const struct ccs_addr_info *address);
395+static u8 ccs_sock_family(struct sock *sk);
396+#endif
397+
398+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
399+static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
400+ struct sk_buff *skb,
401+ int flags);
402+#endif
403+
404+#ifdef CONFIG_CCSECURITY_IPC
405+static bool ccs_check_signal_acl(struct ccs_request_info *r,
406+ const struct ccs_acl_info *ptr);
407+static int ccs_signal_acl(const int pid, const int sig);
408+static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig);
409+static int ccs_signal_acl2(const int sig, const int pid);
410+#endif
411+
412+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
413+static int __ccs_getattr_permission(struct vfsmount *mnt,
414+ struct dentry *dentry);
415+#endif
416+
417+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
418+static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type);
419+static int ccs_try_alt_exec(struct ccs_execve *ee);
420+static void ccs_unescape(unsigned char *dest);
421+#endif
422+
423+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
424+static bool ccs_check_task_acl(struct ccs_request_info *r,
425+ const struct ccs_acl_info *ptr);
426+#endif
427+
428+/***** SECTION4: Standalone functions section *****/
429+
430+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
431+
432+/**
433+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
434+ *
435+ * @arg: String to copy.
436+ * @bprm: Pointer to "struct linux_binprm".
437+ *
438+ * Returns return value of copy_strings_kernel().
439+ */
440+static inline int ccs_copy_argv(const char *arg, struct linux_binprm *bprm)
441+{
442+ const int ret = copy_strings_kernel(1, &arg, bprm);
443+ if (ret >= 0)
444+ bprm->argc++;
445+ return ret;
446+}
447+
448+#else
449+
450+/**
451+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
452+ *
453+ * @arg: String to copy.
454+ * @bprm: Pointer to "struct linux_binprm".
455+ *
456+ * Returns return value of copy_strings_kernel().
457+ */
458+static inline int ccs_copy_argv(char *arg, struct linux_binprm *bprm)
459+{
460+ const int ret = copy_strings_kernel(1, &arg, bprm);
461+ if (ret >= 0)
462+ bprm->argc++;
463+ return ret;
464+}
465+
466+#endif
467+
468+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
469+
470+/**
471+ * get_fs_root - Get reference on root directory.
472+ *
473+ * @fs: Pointer to "struct fs_struct".
474+ * @root: Pointer to "struct path".
475+ *
476+ * Returns nothing.
477+ *
478+ * This is for compatibility with older kernels.
479+ */
480+static inline void get_fs_root(struct fs_struct *fs, struct path *root)
481+{
482+ read_lock(&fs->lock);
483+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
484+ *root = fs->root;
485+ path_get(root);
486+#else
487+ root->dentry = dget(fs->root);
488+ root->mnt = mntget(fs->rootmnt);
489+#endif
490+ read_unlock(&fs->lock);
491+}
492+
493+#endif
494+
495+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
496+
497+/**
498+ * module_put - Put a reference on module.
499+ *
500+ * @module: Pointer to "struct module". Maybe NULL.
501+ *
502+ * Returns nothing.
503+ *
504+ * This is for compatibility with older kernels.
505+ */
506+static inline void module_put(struct module *module)
507+{
508+ if (module)
509+ __MOD_DEC_USE_COUNT(module);
510+}
511+
512+#endif
513+
514+/**
515+ * ccs_put_filesystem - Wrapper for put_filesystem().
516+ *
517+ * @fstype: Pointer to "struct file_system_type".
518+ *
519+ * Returns nothing.
520+ *
521+ * Since put_filesystem() is not exported, I embed put_filesystem() here.
522+ */
523+static inline void ccs_put_filesystem(struct file_system_type *fstype)
524+{
525+ module_put(fstype->owner);
526+}
527+
528+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
529+
530+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
531+#if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
532+#if !defined(AX_MAJOR) || AX_MAJOR != 3
533+
534+/**
535+ * ip_hdr - Get "struct iphdr".
536+ *
537+ * @skb: Pointer to "struct sk_buff".
538+ *
539+ * Returns pointer to "struct iphdr".
540+ *
541+ * This is for compatibility with older kernels.
542+ */
543+static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
544+{
545+ return skb->nh.iph;
546+}
547+
548+/**
549+ * udp_hdr - Get "struct udphdr".
550+ *
551+ * @skb: Pointer to "struct sk_buff".
552+ *
553+ * Returns pointer to "struct udphdr".
554+ *
555+ * This is for compatibility with older kernels.
556+ */
557+static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
558+{
559+ return skb->h.uh;
560+}
561+
562+/**
563+ * ipv6_hdr - Get "struct ipv6hdr".
564+ *
565+ * @skb: Pointer to "struct sk_buff".
566+ *
567+ * Returns pointer to "struct ipv6hdr".
568+ *
569+ * This is for compatibility with older kernels.
570+ */
571+static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
572+{
573+ return skb->nh.ipv6h;
574+}
575+
576+#endif
577+#endif
578+#endif
579+
580+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
581+
582+/**
583+ * skb_kill_datagram - Kill a datagram forcibly.
584+ *
585+ * @sk: Pointer to "struct sock".
586+ * @skb: Pointer to "struct sk_buff".
587+ * @flags: Flags passed to skb_recv_datagram().
588+ *
589+ * Returns nothing.
590+ */
591+static inline void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
592+ int flags)
593+{
594+ /* Clear queue. */
595+ if (flags & MSG_PEEK) {
596+ int clear = 0;
597+ spin_lock_irq(&sk->receive_queue.lock);
598+ if (skb == skb_peek(&sk->receive_queue)) {
599+ __skb_unlink(skb, &sk->receive_queue);
600+ clear = 1;
601+ }
602+ spin_unlock_irq(&sk->receive_queue.lock);
603+ if (clear)
604+ kfree_skb(skb);
605+ }
606+ skb_free_datagram(sk, skb);
607+}
608+
609+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
610+
611+/**
612+ * skb_kill_datagram - Kill a datagram forcibly.
613+ *
614+ * @sk: Pointer to "struct sock".
615+ * @skb: Pointer to "struct sk_buff".
616+ * @flags: Flags passed to skb_recv_datagram().
617+ *
618+ * Returns nothing.
619+ */
620+static inline void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
621+ int flags)
622+{
623+ /* Clear queue. */
624+ if (flags & MSG_PEEK) {
625+ int clear = 0;
626+ spin_lock_bh(&sk->sk_receive_queue.lock);
627+ if (skb == skb_peek(&sk->sk_receive_queue)) {
628+ __skb_unlink(skb, &sk->sk_receive_queue);
629+ clear = 1;
630+ }
631+ spin_unlock_bh(&sk->sk_receive_queue.lock);
632+ if (clear)
633+ kfree_skb(skb);
634+ }
635+ skb_free_datagram(sk, skb);
636+}
637+
638+#endif
639+
640+#endif
641+
642+/***** SECTION5: Variables definition section *****/
643+
644+/* The initial domain. */
645+struct ccs_domain_info ccs_kernel_domain;
646+
647+/* The list for "struct ccs_domain_info". */
648+LIST_HEAD(ccs_domain_list);
649+
650+/***** SECTION6: Dependent functions section *****/
651+
652+/**
653+ * ccs_path_matches_group - Check whether the given pathname matches members of the given pathname group.
654+ *
655+ * @pathname: The name of pathname.
656+ * @group: Pointer to "struct ccs_path_group".
657+ *
658+ * Returns matched member's pathname if @pathname matches pathnames in @group,
659+ * NULL otherwise.
660+ *
661+ * Caller holds ccs_read_lock().
662+ */
663+static const struct ccs_path_info *ccs_path_matches_group
664+(const struct ccs_path_info *pathname, const struct ccs_group *group)
665+{
666+ struct ccs_path_group *member;
667+ list_for_each_entry_srcu(member, &group->member_list, head.list,
668+ &ccs_ss) {
669+ if (member->head.is_deleted)
670+ continue;
671+ if (!ccs_path_matches_pattern(pathname, member->member_name))
672+ continue;
673+ return member->member_name;
674+ }
675+ return NULL;
676+}
677+
678+/**
679+ * ccs_number_matches_group - Check whether the given number matches members of the given number group.
680+ *
681+ * @min: Min number.
682+ * @max: Max number.
683+ * @group: Pointer to "struct ccs_number_group".
684+ *
685+ * Returns true if @min and @max partially overlaps @group, false otherwise.
686+ *
687+ * Caller holds ccs_read_lock().
688+ */
689+static bool ccs_number_matches_group(const unsigned long min,
690+ const unsigned long max,
691+ const struct ccs_group *group)
692+{
693+ struct ccs_number_group *member;
694+ bool matched = false;
695+ list_for_each_entry_srcu(member, &group->member_list, head.list,
696+ &ccs_ss) {
697+ if (member->head.is_deleted)
698+ continue;
699+ if (min > member->number.values[1] ||
700+ max < member->number.values[0])
701+ continue;
702+ matched = true;
703+ break;
704+ }
705+ return matched;
706+}
707+
708+/**
709+ * ccs_check_entry - Do permission check.
710+ *
711+ * @r: Pointer to "struct ccs_request_info".
712+ * @ptr: Pointer to "struct ccs_acl_info".
713+ *
714+ * Returns true on match, false otherwise.
715+ *
716+ * Caller holds ccs_read_lock().
717+ */
718+static bool ccs_check_entry(struct ccs_request_info *r,
719+ struct ccs_acl_info *ptr)
720+{
721+ if (ptr->is_deleted || ptr->type != r->param_type)
722+ return false;
723+ switch (r->param_type) {
724+ case CCS_TYPE_PATH_ACL:
725+ return ccs_check_path_acl(r, ptr);
726+ case CCS_TYPE_PATH2_ACL:
727+ return ccs_check_path2_acl(r, ptr);
728+ case CCS_TYPE_PATH_NUMBER_ACL:
729+ return ccs_check_path_number_acl(r, ptr);
730+ case CCS_TYPE_MKDEV_ACL:
731+ return ccs_check_mkdev_acl(r, ptr);
732+ case CCS_TYPE_MOUNT_ACL:
733+ return ccs_check_mount_acl(r, ptr);
734+#ifdef CONFIG_CCSECURITY_MISC
735+ case CCS_TYPE_ENV_ACL:
736+ return ccs_check_env_acl(r, ptr);
737+#endif
738+#ifdef CONFIG_CCSECURITY_CAPABILITY
739+ case CCS_TYPE_CAPABILITY_ACL:
740+ return ccs_check_capability_acl(r, ptr);
741+#endif
742+#ifdef CONFIG_CCSECURITY_NETWORK
743+ case CCS_TYPE_INET_ACL:
744+ return ccs_check_inet_acl(r, ptr);
745+ case CCS_TYPE_UNIX_ACL:
746+ return ccs_check_unix_acl(r, ptr);
747+#endif
748+#ifdef CONFIG_CCSECURITY_IPC
749+ case CCS_TYPE_SIGNAL_ACL:
750+ return ccs_check_signal_acl(r, ptr);
751+#endif
752+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
753+ case CCS_TYPE_MANUAL_TASK_ACL:
754+ return ccs_check_task_acl(r, ptr);
755+#endif
756+ }
757+ return true;
758+}
759+
760+/**
761+ * ccs_check_acl - Do permission check.
762+ *
763+ * @r: Pointer to "struct ccs_request_info".
764+ *
765+ * Returns 0 on success, negative value otherwise.
766+ *
767+ * Caller holds ccs_read_lock().
768+ */
769+int ccs_check_acl(struct ccs_request_info *r)
770+{
771+ const struct ccs_domain_info *domain = ccs_current_domain();
772+ int error;
773+ do {
774+ struct ccs_acl_info *ptr;
775+ const struct list_head *list = &domain->acl_info_list;
776+ bool retried = false;
777+retry:
778+ list_for_each_entry_srcu(ptr, list, list, &ccs_ss) {
779+ if (!ccs_check_entry(r, ptr))
780+ continue;
781+ if (!ccs_condition(r, ptr->cond))
782+ continue;
783+ r->matched_acl = ptr;
784+ r->granted = true;
785+ ccs_audit_log(r);
786+ return 0;
787+ }
788+ if (!retried) {
789+ retried = true;
790+ list = &domain->ns->acl_group[domain->group];
791+ goto retry;
792+ }
793+ r->granted = false;
794+ error = ccs_audit_log(r);
795+ } while (error == CCS_RETRY_REQUEST &&
796+ r->type != CCS_MAC_FILE_EXECUTE);
797+ return error;
798+}
799+
800+/**
801+ * ccs_last_word - Get last component of a domainname.
802+ *
803+ * @name: Domainname to check.
804+ *
805+ * Returns the last word of @name.
806+ */
807+static const char *ccs_last_word(const char *name)
808+{
809+ const char *cp = strrchr(name, ' ');
810+ if (cp)
811+ return cp + 1;
812+ return name;
813+}
814+
815+/**
816+ * ccs_scan_transition - Try to find specific domain transition type.
817+ *
818+ * @list: Pointer to "struct list_head".
819+ * @domainname: The name of current domain.
820+ * @program: The name of requested program.
821+ * @last_name: The last component of @domainname.
822+ * @type: One of values in "enum ccs_transition_type".
823+ *
824+ * Returns true if found one, false otherwise.
825+ *
826+ * Caller holds ccs_read_lock().
827+ */
828+static bool ccs_scan_transition(const struct list_head *list,
829+ const struct ccs_path_info *domainname,
830+ const struct ccs_path_info *program,
831+ const char *last_name,
832+ const enum ccs_transition_type type)
833+{
834+ const struct ccs_transition_control *ptr;
835+ list_for_each_entry_srcu(ptr, list, head.list, &ccs_ss) {
836+ if (ptr->head.is_deleted || ptr->type != type)
837+ continue;
838+ if (ptr->domainname) {
839+ if (!ptr->is_last_name) {
840+ if (ptr->domainname != domainname)
841+ continue;
842+ } else {
843+ /*
844+ * Use direct strcmp() since this is
845+ * unlikely used.
846+ */
847+ if (strcmp(ptr->domainname->name, last_name))
848+ continue;
849+ }
850+ }
851+ if (ptr->program && ccs_pathcmp(ptr->program, program))
852+ continue;
853+ return true;
854+ }
855+ return false;
856+}
857+
858+/**
859+ * ccs_transition_type - Get domain transition type.
860+ *
861+ * @ns: Pointer to "struct ccs_policy_namespace".
862+ * @domainname: The name of current domain.
863+ * @program: The name of requested program.
864+ *
865+ * Returns CCS_TRANSITION_CONTROL_TRANSIT if executing @program causes domain
866+ * transition across namespaces, CCS_TRANSITION_CONTROL_INITIALIZE if executing
867+ * @program reinitializes domain transition within that namespace,
868+ * CCS_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
869+ * others otherwise.
870+ *
871+ * Caller holds ccs_read_lock().
872+ */
873+static enum ccs_transition_type ccs_transition_type
874+(const struct ccs_policy_namespace *ns, const struct ccs_path_info *domainname,
875+ const struct ccs_path_info *program)
876+{
877+ const char *last_name = ccs_last_word(domainname->name);
878+ enum ccs_transition_type type = CCS_TRANSITION_CONTROL_NO_RESET;
879+ while (type < CCS_MAX_TRANSITION_TYPE) {
880+ const struct list_head * const list =
881+ &ns->policy_list[CCS_ID_TRANSITION_CONTROL];
882+ if (!ccs_scan_transition(list, domainname, program, last_name,
883+ type)) {
884+ type++;
885+ continue;
886+ }
887+ if (type != CCS_TRANSITION_CONTROL_NO_RESET &&
888+ type != CCS_TRANSITION_CONTROL_NO_INITIALIZE)
889+ break;
890+ /*
891+ * Do not check for reset_domain if no_reset_domain matched.
892+ * Do not check for initialize_domain if no_initialize_domain
893+ * matched.
894+ */
895+ type++;
896+ type++;
897+ }
898+ return type;
899+}
900+
901+/**
902+ * ccs_find_next_domain - Find a domain.
903+ *
904+ * @ee: Pointer to "struct ccs_execve".
905+ *
906+ * Returns 0 on success, negative value otherwise.
907+ *
908+ * Caller holds ccs_read_lock().
909+ */
910+static int ccs_find_next_domain(struct ccs_execve *ee)
911+{
912+ struct ccs_request_info *r = &ee->r;
913+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
914+ const struct ccs_path_info *handler = ee->handler;
915+#endif
916+ struct ccs_domain_info *domain = NULL;
917+ struct ccs_domain_info * const old_domain = ccs_current_domain();
918+ struct linux_binprm *bprm = ee->bprm;
919+ struct ccs_security *task = ccs_current_security();
920+ const struct ccs_path_info *candidate;
921+ struct ccs_path_info exename;
922+ int retval;
923+ bool reject_on_transition_failure = false;
924+
925+ /* Get symlink's pathname of program. */
926+ retval = ccs_symlink_path(bprm->filename, &exename);
927+ if (retval < 0)
928+ return retval;
929+
930+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
931+ if (handler) {
932+ /* No permission check for execute handler. */
933+ candidate = &exename;
934+ if (ccs_pathcmp(candidate, handler)) {
935+ /* Failed to verify execute handler. */
936+ static u8 counter = 20;
937+ if (counter) {
938+ counter--;
939+ printk(KERN_WARNING "Failed to verify: %s\n",
940+ handler->name);
941+ }
942+ goto out;
943+ }
944+ } else
945+#endif
946+ {
947+ struct ccs_aggregator *ptr;
948+ struct list_head *list;
949+retry:
950+ /* Check 'aggregator' directive. */
951+ candidate = &exename;
952+ list = &old_domain->ns->policy_list[CCS_ID_AGGREGATOR];
953+ list_for_each_entry_srcu(ptr, list, head.list, &ccs_ss) {
954+ if (ptr->head.is_deleted ||
955+ !ccs_path_matches_pattern(candidate,
956+ ptr->original_name))
957+ continue;
958+ candidate = ptr->aggregated_name;
959+ break;
960+ }
961+
962+ /* Check execute permission. */
963+ retval = ccs_execute_permission(r, candidate);
964+ if (retval == CCS_RETRY_REQUEST)
965+ goto retry;
966+ if (retval < 0)
967+ goto out;
968+ /*
969+ * To be able to specify domainnames with wildcards, use the
970+ * pathname specified in the policy (which may contain
971+ * wildcard) rather than the pathname passed to execve()
972+ * (which never contains wildcard).
973+ */
974+ if (r->param.path.matched_path)
975+ candidate = r->param.path.matched_path;
976+ }
977+ /*
978+ * Check for domain transition preference if "file execute" matched.
979+ * If preference is given, make do_execve() fail if domain transition
980+ * has failed, for domain transition preference should be used with
981+ * destination domain defined.
982+ */
983+ if (r->ee->transition) {
984+ const char *domainname = r->ee->transition->name;
985+ reject_on_transition_failure = true;
986+ if (!strcmp(domainname, "keep"))
987+ goto force_keep_domain;
988+ if (!strcmp(domainname, "child"))
989+ goto force_child_domain;
990+ if (!strcmp(domainname, "reset"))
991+ goto force_reset_domain;
992+ if (!strcmp(domainname, "initialize"))
993+ goto force_initialize_domain;
994+ if (!strcmp(domainname, "parent")) {
995+ char *cp;
996+ strncpy(ee->tmp, old_domain->domainname->name,
997+ CCS_EXEC_TMPSIZE - 1);
998+ cp = strrchr(ee->tmp, ' ');
999+ if (cp)
1000+ *cp = '\0';
1001+ } else if (*domainname == '<')
1002+ strncpy(ee->tmp, domainname, CCS_EXEC_TMPSIZE - 1);
1003+ else
1004+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
1005+ old_domain->domainname->name, domainname);
1006+ goto force_jump_domain;
1007+ }
1008+ /*
1009+ * No domain transition preference specified.
1010+ * Calculate domain to transit to.
1011+ */
1012+ switch (ccs_transition_type(old_domain->ns, old_domain->domainname,
1013+ candidate)) {
1014+ case CCS_TRANSITION_CONTROL_RESET:
1015+force_reset_domain:
1016+ /* Transit to the root of specified namespace. */
1017+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<%s>",
1018+ candidate->name);
1019+ /*
1020+ * Make do_execve() fail if domain transition across namespaces
1021+ * has failed.
1022+ */
1023+ reject_on_transition_failure = true;
1024+ break;
1025+ case CCS_TRANSITION_CONTROL_INITIALIZE:
1026+force_initialize_domain:
1027+ /* Transit to the child of current namespace's root. */
1028+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
1029+ old_domain->ns->name, candidate->name);
1030+ break;
1031+ case CCS_TRANSITION_CONTROL_KEEP:
1032+force_keep_domain:
1033+ /* Keep current domain. */
1034+ domain = old_domain;
1035+ break;
1036+ default:
1037+ if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
1038+ /*
1039+ * Needn't to transit from kernel domain before
1040+ * starting /sbin/init. But transit from kernel domain
1041+ * if executing initializers because they might start
1042+ * before /sbin/init.
1043+ */
1044+ domain = old_domain;
1045+ break;
1046+ }
1047+force_child_domain:
1048+ /* Normal domain transition. */
1049+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
1050+ old_domain->domainname->name, candidate->name);
1051+ break;
1052+ }
1053+force_jump_domain:
1054+ /*
1055+ * Tell GC that I started execve().
1056+ * Also, tell open_exec() to check read permission.
1057+ */
1058+ task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
1059+ /*
1060+ * Make task->ccs_flags visible to GC before changing
1061+ * task->ccs_domain_info.
1062+ */
1063+ smp_wmb();
1064+ /*
1065+ * Proceed to the next domain in order to allow reaching via PID.
1066+ * It will be reverted if execve() failed. Reverting is not good.
1067+ * But it is better than being unable to reach via PID in interactive
1068+ * enforcing mode.
1069+ */
1070+ if (!domain)
1071+ domain = ccs_assign_domain(ee->tmp, true);
1072+ if (domain)
1073+ retval = 0;
1074+ else if (reject_on_transition_failure) {
1075+ printk(KERN_WARNING
1076+ "ERROR: Domain '%s' not ready.\n", ee->tmp);
1077+ retval = -ENOMEM;
1078+ } else if (r->mode == CCS_CONFIG_ENFORCING)
1079+ retval = -ENOMEM;
1080+ else {
1081+ retval = 0;
1082+ if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) {
1083+ old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true;
1084+ r->granted = false;
1085+ ccs_write_log(r, "%s",
1086+ ccs_dif[CCS_DIF_TRANSITION_FAILED]);
1087+ printk(KERN_WARNING
1088+ "ERROR: Domain '%s' not defined.\n", ee->tmp);
1089+ }
1090+ }
1091+out:
1092+ kfree(exename.name);
1093+ return retval;
1094+}
1095+
1096+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1097+
1098+/**
1099+ * ccs_unescape - Unescape escaped string.
1100+ *
1101+ * @dest: String to unescape.
1102+ *
1103+ * Returns nothing.
1104+ */
1105+static void ccs_unescape(unsigned char *dest)
1106+{
1107+ unsigned char *src = dest;
1108+ unsigned char c;
1109+ unsigned char d;
1110+ unsigned char e;
1111+ while (1) {
1112+ c = *src++;
1113+ if (!c)
1114+ break;
1115+ if (c != '\\') {
1116+ *dest++ = c;
1117+ continue;
1118+ }
1119+ c = *src++;
1120+ if (c == '\\') {
1121+ *dest++ = c;
1122+ continue;
1123+ }
1124+ if (c < '0' || c > '3')
1125+ break;
1126+ d = *src++;
1127+ if (d < '0' || d > '7')
1128+ break;
1129+ e = *src++;
1130+ if (e < '0' || e > '7')
1131+ break;
1132+ *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1133+ }
1134+ *dest = '\0';
1135+}
1136+
1137+/**
1138+ * ccs_try_alt_exec - Try to start execute handler.
1139+ *
1140+ * @ee: Pointer to "struct ccs_execve".
1141+ *
1142+ * Returns 0 on success, negative value otherwise.
1143+ */
1144+static int ccs_try_alt_exec(struct ccs_execve *ee)
1145+{
1146+ /*
1147+ * Contents of modified bprm.
1148+ * The envp[] in original bprm is moved to argv[] so that
1149+ * the alternatively executed program won't be affected by
1150+ * some dangerous environment variables like LD_PRELOAD.
1151+ *
1152+ * modified bprm->argc
1153+ * = original bprm->argc + original bprm->envc + 7
1154+ * modified bprm->envc
1155+ * = 0
1156+ *
1157+ * modified bprm->argv[0]
1158+ * = the program's name specified by *_execute_handler
1159+ * modified bprm->argv[1]
1160+ * = ccs_current_domain()->domainname->name
1161+ * modified bprm->argv[2]
1162+ * = the current process's name
1163+ * modified bprm->argv[3]
1164+ * = the current process's information (e.g. uid/gid).
1165+ * modified bprm->argv[4]
1166+ * = original bprm->filename
1167+ * modified bprm->argv[5]
1168+ * = original bprm->argc in string expression
1169+ * modified bprm->argv[6]
1170+ * = original bprm->envc in string expression
1171+ * modified bprm->argv[7]
1172+ * = original bprm->argv[0]
1173+ * ...
1174+ * modified bprm->argv[bprm->argc + 6]
1175+ * = original bprm->argv[bprm->argc - 1]
1176+ * modified bprm->argv[bprm->argc + 7]
1177+ * = original bprm->envp[0]
1178+ * ...
1179+ * modified bprm->argv[bprm->envc + bprm->argc + 6]
1180+ * = original bprm->envp[bprm->envc - 1]
1181+ */
1182+ struct linux_binprm *bprm = ee->bprm;
1183+ struct file *filp;
1184+ int retval;
1185+ const int original_argc = bprm->argc;
1186+ const int original_envc = bprm->envc;
1187+
1188+ /* Close the requested program's dentry. */
1189+ ee->obj.path1.dentry = NULL;
1190+ ee->obj.path1.mnt = NULL;
1191+ ee->obj.stat_valid[CCS_PATH1] = false;
1192+ ee->obj.stat_valid[CCS_PATH1_PARENT] = false;
1193+ ee->obj.validate_done = false;
1194+ allow_write_access(bprm->file);
1195+ fput(bprm->file);
1196+ bprm->file = NULL;
1197+
1198+ /* Invalidate page dump cache. */
1199+ ee->dump.page = NULL;
1200+
1201+ /* Move envp[] to argv[] */
1202+ bprm->argc += bprm->envc;
1203+ bprm->envc = 0;
1204+
1205+ /* Set argv[6] */
1206+ {
1207+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1208+ retval = ccs_copy_argv(ee->tmp, bprm);
1209+ if (retval < 0)
1210+ goto out;
1211+ }
1212+
1213+ /* Set argv[5] */
1214+ {
1215+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1216+ retval = ccs_copy_argv(ee->tmp, bprm);
1217+ if (retval < 0)
1218+ goto out;
1219+ }
1220+
1221+ /* Set argv[4] */
1222+ {
1223+ retval = ccs_copy_argv(bprm->filename, bprm);
1224+ if (retval < 0)
1225+ goto out;
1226+ }
1227+
1228+ /* Set argv[3] */
1229+ {
1230+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
1231+ /*
1232+ * Pass uid/gid seen from current user namespace, for these
1233+ * values are used by programs in current user namespace in
1234+ * order to decide whether to execve() or not (rather than by
1235+ * auditing daemon in init's user namespace).
1236+ */
1237+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1238+ "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1239+ "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
1240+ __kuid_val(current_uid()), __kgid_val(current_gid()),
1241+ __kuid_val(current_euid()),
1242+ __kgid_val(current_egid()),
1243+ __kuid_val(current_suid()),
1244+ __kgid_val(current_sgid()),
1245+ __kuid_val(current_fsuid()),
1246+ __kgid_val(current_fsgid()));
1247+#else
1248+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1249+ "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1250+ "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
1251+ current_uid(), current_gid(), current_euid(),
1252+ current_egid(), current_suid(), current_sgid(),
1253+ current_fsuid(), current_fsgid());
1254+#endif
1255+ retval = ccs_copy_argv(ee->tmp, bprm);
1256+ if (retval < 0)
1257+ goto out;
1258+ }
1259+
1260+ /* Set argv[2] */
1261+ {
1262+ char *exe = (char *) ccs_get_exe();
1263+ if (exe) {
1264+ retval = ccs_copy_argv(exe, bprm);
1265+ kfree(exe);
1266+ } else {
1267+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
1268+ retval = ccs_copy_argv("<unknown>", bprm);
1269+#else
1270+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
1271+ retval = ccs_copy_argv(ee->tmp, bprm);
1272+#endif
1273+ }
1274+ if (retval < 0)
1275+ goto out;
1276+ }
1277+
1278+ /* Set argv[1] */
1279+ {
1280+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
1281+ retval = ccs_copy_argv(ccs_current_domain()->domainname->name,
1282+ bprm);
1283+#else
1284+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1285+ ccs_current_domain()->domainname->name);
1286+ retval = ccs_copy_argv(ee->tmp, bprm);
1287+#endif
1288+ if (retval < 0)
1289+ goto out;
1290+ }
1291+
1292+ /* Set argv[0] */
1293+ {
1294+ struct path root;
1295+ char *cp;
1296+ int root_len;
1297+ int handler_len;
1298+ get_fs_root(current->fs, &root);
1299+ cp = ccs_realpath(&root);
1300+ path_put(&root);
1301+ if (!cp) {
1302+ retval = -ENOMEM;
1303+ goto out;
1304+ }
1305+ root_len = strlen(cp);
1306+ retval = strncmp(ee->handler->name, cp, root_len);
1307+ root_len--;
1308+ kfree(cp);
1309+ if (retval) {
1310+ retval = -ENOENT;
1311+ goto out;
1312+ }
1313+ handler_len = ee->handler->total_len + 1;
1314+ cp = kmalloc(handler_len, CCS_GFP_FLAGS);
1315+ if (!cp) {
1316+ retval = -ENOMEM;
1317+ goto out;
1318+ }
1319+ /* ee->handler_path is released by ccs_finish_execve(). */
1320+ ee->handler_path = cp;
1321+ /* Adjust root directory for open_exec(). */
1322+ memmove(cp, ee->handler->name + root_len,
1323+ handler_len - root_len);
1324+ ccs_unescape(cp);
1325+ retval = -ENOENT;
1326+ if (*cp != '/')
1327+ goto out;
1328+ retval = ccs_copy_argv(cp, bprm);
1329+ if (retval < 0)
1330+ goto out;
1331+ }
1332+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1333+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1334+ bprm->argv_len = bprm->exec - bprm->p;
1335+#endif
1336+#endif
1337+
1338+ /*
1339+ * OK, now restart the process with execute handler program's dentry.
1340+ */
1341+ filp = open_exec(ee->handler_path);
1342+ if (IS_ERR(filp)) {
1343+ retval = PTR_ERR(filp);
1344+ goto out;
1345+ }
1346+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1347+ ee->obj.path1 = filp->f_path;
1348+#else
1349+ ee->obj.path1.dentry = filp->f_dentry;
1350+ ee->obj.path1.mnt = filp->f_vfsmnt;
1351+#endif
1352+ bprm->file = filp;
1353+ bprm->filename = ee->handler_path;
1354+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1355+ bprm->interp = bprm->filename;
1356+#endif
1357+ retval = prepare_binprm(bprm);
1358+ if (retval < 0)
1359+ goto out;
1360+ ee->r.dont_sleep_on_enforce_error = true;
1361+ retval = ccs_find_next_domain(ee);
1362+ ee->r.dont_sleep_on_enforce_error = false;
1363+out:
1364+ return retval;
1365+}
1366+
1367+/**
1368+ * ccs_find_execute_handler - Find an execute handler.
1369+ *
1370+ * @ee: Pointer to "struct ccs_execve".
1371+ * @type: Type of execute handler.
1372+ *
1373+ * Returns true if found, false otherwise.
1374+ *
1375+ * Caller holds ccs_read_lock().
1376+ */
1377+static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type)
1378+{
1379+ struct ccs_request_info *r = &ee->r;
1380+ /*
1381+ * To avoid infinite execute handler loop, don't use execute handler
1382+ * if the current process is marked as execute handler.
1383+ */
1384+ if (ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)
1385+ return false;
1386+ r->param_type = type;
1387+ ccs_check_acl(r);
1388+ if (!r->granted)
1389+ return false;
1390+ ee->handler = container_of(r->matched_acl, struct ccs_handler_acl,
1391+ head)->handler;
1392+ ee->transition = r->matched_acl && r->matched_acl->cond &&
1393+ r->matched_acl->cond->exec_transit ?
1394+ r->matched_acl->cond->transit : NULL;
1395+ return true;
1396+}
1397+
1398+#endif
1399+
1400+#ifdef CONFIG_MMU
1401+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1402+#define CCS_BPRM_MMU
1403+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3
1404+#define CCS_BPRM_MMU
1405+#elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2
1406+#define CCS_BPRM_MMU
1407+#endif
1408+#endif
1409+
1410+/**
1411+ * ccs_dump_page - Dump a page to buffer.
1412+ *
1413+ * @bprm: Pointer to "struct linux_binprm".
1414+ * @pos: Location to dump.
1415+ * @dump: Poiner to "struct ccs_page_dump".
1416+ *
1417+ * Returns true on success, false otherwise.
1418+ */
1419+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1420+ struct ccs_page_dump *dump)
1421+{
1422+ struct page *page;
1423+ /* dump->data is released by ccs_start_execve(). */
1424+ if (!dump->data) {
1425+ dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1426+ if (!dump->data)
1427+ return false;
1428+ }
1429+ /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1430+#ifdef CCS_BPRM_MMU
1431+ if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1432+ return false;
1433+#else
1434+ page = bprm->page[pos / PAGE_SIZE];
1435+#endif
1436+ if (page != dump->page) {
1437+ const unsigned int offset = pos % PAGE_SIZE;
1438+ /*
1439+ * Maybe kmap()/kunmap() should be used here.
1440+ * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1441+ * So do I.
1442+ */
1443+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
1444+ char *kaddr = kmap_atomic(page);
1445+#else
1446+ char *kaddr = kmap_atomic(page, KM_USER0);
1447+#endif
1448+ dump->page = page;
1449+ memcpy(dump->data + offset, kaddr + offset,
1450+ PAGE_SIZE - offset);
1451+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
1452+ kunmap_atomic(kaddr);
1453+#else
1454+ kunmap_atomic(kaddr, KM_USER0);
1455+#endif
1456+ }
1457+ /* Same with put_arg_page(page) in fs/exec.c */
1458+#ifdef CCS_BPRM_MMU
1459+ put_page(page);
1460+#endif
1461+ return true;
1462+}
1463+
1464+/**
1465+ * ccs_start_execve - Prepare for execve() operation.
1466+ *
1467+ * @bprm: Pointer to "struct linux_binprm".
1468+ * @eep: Pointer to "struct ccs_execve *".
1469+ *
1470+ * Returns 0 on success, negative value otherwise.
1471+ */
1472+int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve **eep)
1473+{
1474+ int retval;
1475+ struct ccs_security *task = ccs_current_security();
1476+ struct ccs_execve *ee;
1477+ int idx;
1478+ *eep = NULL;
1479+ ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1480+ if (!ee)
1481+ return -ENOMEM;
1482+ ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1483+ if (!ee->tmp) {
1484+ kfree(ee);
1485+ return -ENOMEM;
1486+ }
1487+ ccs_audit_alloc_execve(ee);
1488+ idx = ccs_read_lock();
1489+ /* ee->dump->data is allocated by ccs_dump_page(). */
1490+ ee->previous_domain = task->ccs_domain_info;
1491+ /* Clear manager flag. */
1492+ task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1493+ *eep = ee;
1494+ ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1495+ ee->r.ee = ee;
1496+ ee->bprm = bprm;
1497+ ee->r.obj = &ee->obj;
1498+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1499+ ee->obj.path1 = bprm->file->f_path;
1500+#else
1501+ ee->obj.path1.dentry = bprm->file->f_dentry;
1502+ ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1503+#endif
1504+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1505+ /*
1506+ * No need to call ccs_environ() for execute handler because envp[] is
1507+ * moved to argv[].
1508+ */
1509+ if (ccs_find_execute_handler(ee, CCS_TYPE_AUTO_EXECUTE_HANDLER)) {
1510+ retval = ccs_try_alt_exec(ee);
1511+ goto done;
1512+ }
1513+#endif
1514+ retval = ccs_find_next_domain(ee);
1515+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1516+ if (retval == -EPERM &&
1517+ ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1518+ retval = ccs_try_alt_exec(ee);
1519+ goto done;
1520+ }
1521+#endif
1522+#ifdef CONFIG_CCSECURITY_MISC
1523+ if (!retval)
1524+ retval = ccs_environ(ee);
1525+#endif
1526+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1527+done:
1528+#endif
1529+ ccs_read_unlock(idx);
1530+ kfree(ee->tmp);
1531+ ee->tmp = NULL;
1532+ kfree(ee->dump.data);
1533+ ee->dump.data = NULL;
1534+ return retval;
1535+}
1536+
1537+/**
1538+ * ccs_finish_execve - Clean up execve() operation.
1539+ *
1540+ * @retval: Return code of an execve() operation.
1541+ * @ee: Pointer to "struct ccs_execve".
1542+ *
1543+ * Returns nothing.
1544+ */
1545+void ccs_finish_execve(int retval, struct ccs_execve *ee)
1546+{
1547+ struct ccs_security *task = ccs_current_security();
1548+ if (!ee)
1549+ return;
1550+ if (retval < 0) {
1551+ task->ccs_domain_info = ee->previous_domain;
1552+ /*
1553+ * Make task->ccs_domain_info visible to GC before changing
1554+ * task->ccs_flags.
1555+ */
1556+ smp_wmb();
1557+ } else {
1558+ /* Mark the current process as execute handler. */
1559+ if (ee->handler)
1560+ task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1561+ /* Mark the current process as normal process. */
1562+ else
1563+ task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1564+ }
1565+ /* Tell GC that I finished execve(). */
1566+ task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1567+ ccs_audit_free_execve(ee, true);
1568+ kfree(ee->handler_path);
1569+ kfree(ee);
1570+}
1571+
1572+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
1573+
1574+/**
1575+ * __ccs_search_binary_handler - Main routine for do_execve().
1576+ *
1577+ * @bprm: Pointer to "struct linux_binprm".
1578+ *
1579+ * Returns 0 on success, negative value otherwise.
1580+ *
1581+ * Performs permission checks for do_execve() and domain transition.
1582+ * Domain transition by "struct ccs_domain_transition_control" and
1583+ * "auto_domain_transition=" parameter of "struct ccs_condition" are reverted
1584+ * if do_execve() failed.
1585+ * Garbage collector does not remove "struct ccs_domain_info" from
1586+ * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
1587+ * marked as CCS_TASK_IS_IN_EXECVE.
1588+ */
1589+static int __ccs_search_binary_handler(struct linux_binprm *bprm)
1590+{
1591+ struct ccs_execve *ee;
1592+ int retval;
1593+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1594+ if (!ccs_policy_loaded)
1595+ ccsecurity_exports.load_policy(bprm->filename);
1596+#endif
1597+ retval = ccs_start_execve(bprm, &ee);
1598+ if (!retval)
1599+ retval = search_binary_handler(bprm);
1600+ ccs_finish_execve(retval, ee);
1601+ return retval;
1602+}
1603+
1604+#else
1605+
1606+/**
1607+ * __ccs_search_binary_handler - Main routine for do_execve().
1608+ *
1609+ * @bprm: Pointer to "struct linux_binprm".
1610+ * @regs: Pointer to "struct pt_regs".
1611+ *
1612+ * Returns 0 on success, negative value otherwise.
1613+ *
1614+ * Performs permission checks for do_execve() and domain transition.
1615+ * Domain transition by "struct ccs_domain_transition_control" and
1616+ * "auto_domain_transition=" parameter of "struct ccs_condition" are reverted
1617+ * if do_execve() failed.
1618+ * Garbage collector does not remove "struct ccs_domain_info" from
1619+ * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
1620+ * marked as CCS_TASK_IS_IN_EXECVE.
1621+ */
1622+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1623+ struct pt_regs *regs)
1624+{
1625+ struct ccs_execve *ee;
1626+ int retval;
1627+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1628+ if (!ccs_policy_loaded)
1629+ ccsecurity_exports.load_policy(bprm->filename);
1630+#endif
1631+ retval = ccs_start_execve(bprm, &ee);
1632+ if (!retval)
1633+ retval = search_binary_handler(bprm, regs);
1634+ ccs_finish_execve(retval, ee);
1635+ return retval;
1636+}
1637+
1638+#endif
1639+
1640+/**
1641+ * ccs_permission_init - Register permission check hooks.
1642+ *
1643+ * Returns nothing.
1644+ */
1645+void __init ccs_permission_init(void)
1646+{
1647+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1648+ ccsecurity_ops.save_open_mode = __ccs_save_open_mode;
1649+ ccsecurity_ops.clear_open_mode = __ccs_clear_open_mode;
1650+ ccsecurity_ops.open_permission = __ccs_open_permission;
1651+#else
1652+ ccsecurity_ops.open_permission = ccs_new_open_permission;
1653+#endif
1654+ ccsecurity_ops.fcntl_permission = __ccs_fcntl_permission;
1655+ ccsecurity_ops.ioctl_permission = __ccs_ioctl_permission;
1656+ ccsecurity_ops.chmod_permission = __ccs_chmod_permission;
1657+ ccsecurity_ops.chown_permission = __ccs_chown_permission;
1658+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
1659+ ccsecurity_ops.getattr_permission = __ccs_getattr_permission;
1660+#endif
1661+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1662+ ccsecurity_ops.pivot_root_permission = __ccs_pivot_root_permission;
1663+ ccsecurity_ops.chroot_permission = __ccs_chroot_permission;
1664+#else
1665+ ccsecurity_ops.pivot_root_permission = ccs_old_pivot_root_permission;
1666+ ccsecurity_ops.chroot_permission = ccs_old_chroot_permission;
1667+#endif
1668+ ccsecurity_ops.umount_permission = __ccs_umount_permission;
1669+ ccsecurity_ops.mknod_permission = __ccs_mknod_permission;
1670+ ccsecurity_ops.mkdir_permission = __ccs_mkdir_permission;
1671+ ccsecurity_ops.rmdir_permission = __ccs_rmdir_permission;
1672+ ccsecurity_ops.unlink_permission = __ccs_unlink_permission;
1673+ ccsecurity_ops.symlink_permission = __ccs_symlink_permission;
1674+ ccsecurity_ops.truncate_permission = __ccs_truncate_permission;
1675+ ccsecurity_ops.rename_permission = __ccs_rename_permission;
1676+ ccsecurity_ops.link_permission = __ccs_link_permission;
1677+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1678+ ccsecurity_ops.open_exec_permission = __ccs_open_exec_permission;
1679+ ccsecurity_ops.uselib_permission = __ccs_uselib_permission;
1680+#endif
1681+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
1682+ ccsecurity_ops.parse_table = __ccs_parse_table;
1683+#endif
1684+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1685+ ccsecurity_ops.mount_permission = __ccs_mount_permission;
1686+#else
1687+ ccsecurity_ops.mount_permission = ccs_old_mount_permission;
1688+#endif
1689+#ifdef CONFIG_CCSECURITY_CAPABILITY
1690+ ccsecurity_ops.socket_create_permission =
1691+ __ccs_socket_create_permission;
1692+#endif
1693+#ifdef CONFIG_CCSECURITY_NETWORK
1694+ ccsecurity_ops.socket_listen_permission =
1695+ __ccs_socket_listen_permission;
1696+ ccsecurity_ops.socket_connect_permission =
1697+ __ccs_socket_connect_permission;
1698+ ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission;
1699+ ccsecurity_ops.socket_post_accept_permission =
1700+ __ccs_socket_post_accept_permission;
1701+ ccsecurity_ops.socket_sendmsg_permission =
1702+ __ccs_socket_sendmsg_permission;
1703+#endif
1704+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
1705+ ccsecurity_ops.socket_post_recvmsg_permission =
1706+ __ccs_socket_post_recvmsg_permission;
1707+#endif
1708+#ifdef CONFIG_CCSECURITY_IPC
1709+ ccsecurity_ops.kill_permission = ccs_signal_acl;
1710+ ccsecurity_ops.tgkill_permission = ccs_signal_acl0;
1711+ ccsecurity_ops.tkill_permission = ccs_signal_acl;
1712+ ccsecurity_ops.sigqueue_permission = ccs_signal_acl;
1713+ ccsecurity_ops.tgsigqueue_permission = ccs_signal_acl0;
1714+#endif
1715+#ifdef CONFIG_CCSECURITY_CAPABILITY
1716+ ccsecurity_ops.capable = __ccs_capable;
1717+ ccsecurity_ops.ptrace_permission = __ccs_ptrace_permission;
1718+#endif
1719+ ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1720+}
1721+
1722+/**
1723+ * ccs_kern_path - Wrapper for kern_path().
1724+ *
1725+ * @pathname: Pathname to resolve. Maybe NULL.
1726+ * @flags: Lookup flags.
1727+ * @path: Pointer to "struct path".
1728+ *
1729+ * Returns 0 on success, negative value otherwise.
1730+ */
1731+static int ccs_kern_path(const char *pathname, int flags, struct path *path)
1732+{
1733+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
1734+ if (!pathname || kern_path(pathname, flags, path))
1735+ return -ENOENT;
1736+#else
1737+ struct nameidata nd;
1738+ if (!pathname || path_lookup(pathname, flags, &nd))
1739+ return -ENOENT;
1740+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1741+ *path = nd.path;
1742+#else
1743+ path->dentry = nd.dentry;
1744+ path->mnt = nd.mnt;
1745+#endif
1746+#endif
1747+ return 0;
1748+}
1749+
1750+/**
1751+ * ccs_get_path - Get dentry/vfsmmount of a pathname.
1752+ *
1753+ * @pathname: The pathname to solve. Maybe NULL.
1754+ * @path: Pointer to "struct path".
1755+ *
1756+ * Returns 0 on success, negative value otherwise.
1757+ */
1758+static int ccs_get_path(const char *pathname, struct path *path)
1759+{
1760+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1761+ return ccs_kern_path(pathname, LOOKUP_FOLLOW, path);
1762+#else
1763+ return ccs_kern_path(pathname, LOOKUP_FOLLOW | LOOKUP_POSITIVE, path);
1764+#endif
1765+}
1766+
1767+/**
1768+ * ccs_symlink_path - Get symlink's pathname.
1769+ *
1770+ * @pathname: The pathname to solve. Maybe NULL.
1771+ * @name: Pointer to "struct ccs_path_info".
1772+ *
1773+ * Returns 0 on success, negative value otherwise.
1774+ *
1775+ * This function uses kzalloc(), so caller must kfree() if this function
1776+ * didn't return NULL.
1777+ */
1778+static int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
1779+{
1780+ char *buf;
1781+ struct path path;
1782+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1783+ if (ccs_kern_path(pathname, 0, &path))
1784+ return -ENOENT;
1785+#else
1786+ if (ccs_kern_path(pathname, LOOKUP_POSITIVE, &path))
1787+ return -ENOENT;
1788+#endif
1789+ buf = ccs_realpath(&path);
1790+ path_put(&path);
1791+ if (buf) {
1792+ name->name = buf;
1793+ ccs_fill_path_info(name);
1794+ return 0;
1795+ }
1796+ return -ENOMEM;
1797+}
1798+
1799+/**
1800+ * ccs_check_mount_acl - Check permission for path path path number operation.
1801+ *
1802+ * @r: Pointer to "struct ccs_request_info".
1803+ * @ptr: Pointer to "struct ccs_acl_info".
1804+ *
1805+ * Returns true if granted, false otherwise.
1806+ */
1807+static bool ccs_check_mount_acl(struct ccs_request_info *r,
1808+ const struct ccs_acl_info *ptr)
1809+{
1810+ const struct ccs_mount_acl *acl =
1811+ container_of(ptr, typeof(*acl), head);
1812+ return ccs_compare_number_union(r->param.mount.flags, &acl->flags) &&
1813+ ccs_compare_name_union(r->param.mount.type, &acl->fs_type) &&
1814+ ccs_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
1815+ (!r->param.mount.need_dev ||
1816+ ccs_compare_name_union(r->param.mount.dev, &acl->dev_name));
1817+}
1818+
1819+/**
1820+ * ccs_mount_acl - Check permission for mount() operation.
1821+ *
1822+ * @r: Pointer to "struct ccs_request_info".
1823+ * @dev_name: Name of device file. Maybe NULL.
1824+ * @dir: Pointer to "struct path".
1825+ * @type: Name of filesystem type.
1826+ * @flags: Mount options.
1827+ *
1828+ * Returns 0 on success, negative value otherwise.
1829+ *
1830+ * Caller holds ccs_read_lock().
1831+ */
1832+static int ccs_mount_acl(struct ccs_request_info *r, const char *dev_name,
1833+ struct path *dir, const char *type,
1834+ unsigned long flags)
1835+{
1836+ struct ccs_obj_info obj = { };
1837+ struct file_system_type *fstype = NULL;
1838+ const char *requested_type = NULL;
1839+ const char *requested_dir_name = NULL;
1840+ const char *requested_dev_name = NULL;
1841+ struct ccs_path_info rtype;
1842+ struct ccs_path_info rdev;
1843+ struct ccs_path_info rdir;
1844+ int need_dev = 0;
1845+ int error = -ENOMEM;
1846+ r->obj = &obj;
1847+
1848+ /* Get fstype. */
1849+ requested_type = ccs_encode(type);
1850+ if (!requested_type)
1851+ goto out;
1852+ rtype.name = requested_type;
1853+ ccs_fill_path_info(&rtype);
1854+
1855+ /* Get mount point. */
1856+ obj.path2 = *dir;
1857+ requested_dir_name = ccs_realpath(dir);
1858+ if (!requested_dir_name) {
1859+ error = -ENOMEM;
1860+ goto out;
1861+ }
1862+ rdir.name = requested_dir_name;
1863+ ccs_fill_path_info(&rdir);
1864+
1865+ /* Compare fs name. */
1866+ if (type == ccs_mounts[CCS_MOUNT_REMOUNT]) {
1867+ /* dev_name is ignored. */
1868+ } else if (type == ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE] ||
1869+ type == ccs_mounts[CCS_MOUNT_MAKE_PRIVATE] ||
1870+ type == ccs_mounts[CCS_MOUNT_MAKE_SLAVE] ||
1871+ type == ccs_mounts[CCS_MOUNT_MAKE_SHARED]) {
1872+ /* dev_name is ignored. */
1873+ } else if (type == ccs_mounts[CCS_MOUNT_BIND] ||
1874+ type == ccs_mounts[CCS_MOUNT_MOVE]) {
1875+ need_dev = -1; /* dev_name is a directory */
1876+ } else {
1877+ fstype = get_fs_type(type);
1878+ if (!fstype) {
1879+ error = -ENODEV;
1880+ goto out;
1881+ }
1882+ if (fstype->fs_flags & FS_REQUIRES_DEV)
1883+ /* dev_name is a block device file. */
1884+ need_dev = 1;
1885+ }
1886+ if (need_dev) {
1887+ /* Get mount point or device file. */
1888+ if (ccs_get_path(dev_name, &obj.path1)) {
1889+ error = -ENOENT;
1890+ goto out;
1891+ }
1892+ requested_dev_name = ccs_realpath(&obj.path1);
1893+ if (!requested_dev_name) {
1894+ error = -ENOENT;
1895+ goto out;
1896+ }
1897+ } else {
1898+ /* Map dev_name to "<NULL>" if no dev_name given. */
1899+ if (!dev_name)
1900+ dev_name = "<NULL>";
1901+ requested_dev_name = ccs_encode(dev_name);
1902+ if (!requested_dev_name) {
1903+ error = -ENOMEM;
1904+ goto out;
1905+ }
1906+ }
1907+ rdev.name = requested_dev_name;
1908+ ccs_fill_path_info(&rdev);
1909+ r->param_type = CCS_TYPE_MOUNT_ACL;
1910+ r->param.mount.need_dev = need_dev;
1911+ r->param.mount.dev = &rdev;
1912+ r->param.mount.dir = &rdir;
1913+ r->param.mount.type = &rtype;
1914+ r->param.mount.flags = flags;
1915+ error = ccs_check_acl(r);
1916+out:
1917+ kfree(requested_dev_name);
1918+ kfree(requested_dir_name);
1919+ if (fstype)
1920+ ccs_put_filesystem(fstype);
1921+ kfree(requested_type);
1922+ /* Drop refcount obtained by ccs_get_path(). */
1923+ if (obj.path1.dentry)
1924+ path_put(&obj.path1);
1925+ return error;
1926+}
1927+
1928+/**
1929+ * __ccs_mount_permission - Check permission for mount() operation.
1930+ *
1931+ * @dev_name: Name of device file. Maybe NULL.
1932+ * @path: Pointer to "struct path".
1933+ * @type: Name of filesystem type. Maybe NULL.
1934+ * @flags: Mount options.
1935+ * @data_page: Optional data. Maybe NULL.
1936+ *
1937+ * Returns 0 on success, negative value otherwise.
1938+ */
1939+static int __ccs_mount_permission(const char *dev_name, struct path *path,
1940+ const char *type, unsigned long flags,
1941+ void *data_page)
1942+{
1943+ struct ccs_request_info r;
1944+ int error = 0;
1945+ int idx;
1946+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1947+ flags &= ~MS_MGC_MSK;
1948+ if (flags & MS_REMOUNT) {
1949+ type = ccs_mounts[CCS_MOUNT_REMOUNT];
1950+ flags &= ~MS_REMOUNT;
1951+ } else if (flags & MS_BIND) {
1952+ type = ccs_mounts[CCS_MOUNT_BIND];
1953+ flags &= ~MS_BIND;
1954+ } else if (flags & MS_SHARED) {
1955+ if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1956+ return -EINVAL;
1957+ type = ccs_mounts[CCS_MOUNT_MAKE_SHARED];
1958+ flags &= ~MS_SHARED;
1959+ } else if (flags & MS_PRIVATE) {
1960+ if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
1961+ return -EINVAL;
1962+ type = ccs_mounts[CCS_MOUNT_MAKE_PRIVATE];
1963+ flags &= ~MS_PRIVATE;
1964+ } else if (flags & MS_SLAVE) {
1965+ if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
1966+ return -EINVAL;
1967+ type = ccs_mounts[CCS_MOUNT_MAKE_SLAVE];
1968+ flags &= ~MS_SLAVE;
1969+ } else if (flags & MS_UNBINDABLE) {
1970+ if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
1971+ return -EINVAL;
1972+ type = ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE];
1973+ flags &= ~MS_UNBINDABLE;
1974+ } else if (flags & MS_MOVE) {
1975+ type = ccs_mounts[CCS_MOUNT_MOVE];
1976+ flags &= ~MS_MOVE;
1977+ }
1978+ if (!type)
1979+ type = "<NULL>";
1980+ idx = ccs_read_lock();
1981+ if (ccs_init_request_info(&r, CCS_MAC_FILE_MOUNT)
1982+ != CCS_CONFIG_DISABLED)
1983+ error = ccs_mount_acl(&r, dev_name, path, type, flags);
1984+ ccs_read_unlock(idx);
1985+ return error;
1986+}
1987+
1988+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1989+
1990+/**
1991+ * ccs_old_mount_permission - Check permission for mount() operation.
1992+ *
1993+ * @dev_name: Name of device file.
1994+ * @nd: Pointer to "struct nameidata".
1995+ * @type: Name of filesystem type. Maybe NULL.
1996+ * @flags: Mount options.
1997+ * @data_page: Optional data. Maybe NULL.
1998+ *
1999+ * Returns 0 on success, negative value otherwise.
2000+ */
2001+static int ccs_old_mount_permission(const char *dev_name, struct nameidata *nd,
2002+ const char *type, unsigned long flags,
2003+ void *data_page)
2004+{
2005+ struct path path = { nd->mnt, nd->dentry };
2006+ return __ccs_mount_permission(dev_name, &path, type, flags, data_page);
2007+}
2008+
2009+#endif
2010+
2011+/**
2012+ * ccs_compare_number_union - Check whether a value matches "struct ccs_number_union" or not.
2013+ *
2014+ * @value: Number to check.
2015+ * @ptr: Pointer to "struct ccs_number_union".
2016+ *
2017+ * Returns true if @value matches @ptr, false otherwise.
2018+ */
2019+static bool ccs_compare_number_union(const unsigned long value,
2020+ const struct ccs_number_union *ptr)
2021+{
2022+ if (ptr->group)
2023+ return ccs_number_matches_group(value, value, ptr->group);
2024+ return value >= ptr->values[0] && value <= ptr->values[1];
2025+}
2026+
2027+/**
2028+ * ccs_compare_name_union - Check whether a name matches "struct ccs_name_union" or not.
2029+ *
2030+ * @name: Pointer to "struct ccs_path_info".
2031+ * @ptr: Pointer to "struct ccs_name_union".
2032+ *
2033+ * Returns "struct ccs_path_info" if @name matches @ptr, NULL otherwise.
2034+ */
2035+static const struct ccs_path_info *ccs_compare_name_union
2036+(const struct ccs_path_info *name, const struct ccs_name_union *ptr)
2037+{
2038+ if (ptr->group)
2039+ return ccs_path_matches_group(name, ptr->group);
2040+ if (ccs_path_matches_pattern(name, ptr->filename))
2041+ return ptr->filename;
2042+ return NULL;
2043+}
2044+
2045+/**
2046+ * ccs_add_slash - Add trailing '/' if needed.
2047+ *
2048+ * @buf: Pointer to "struct ccs_path_info".
2049+ *
2050+ * Returns nothing.
2051+ *
2052+ * @buf must be generated by ccs_encode() because this function does not
2053+ * allocate memory for adding '/'.
2054+ */
2055+static void ccs_add_slash(struct ccs_path_info *buf)
2056+{
2057+ if (buf->is_dir)
2058+ return;
2059+ /* This is OK because ccs_encode() reserves space for appending "/". */
2060+ strcat((char *) buf->name, "/");
2061+ ccs_fill_path_info(buf);
2062+}
2063+
2064+/**
2065+ * ccs_get_realpath - Get realpath.
2066+ *
2067+ * @buf: Pointer to "struct ccs_path_info".
2068+ * @path: Pointer to "struct path". @path->mnt may be NULL.
2069+ *
2070+ * Returns true on success, false otherwise.
2071+ */
2072+static bool ccs_get_realpath(struct ccs_path_info *buf, struct path *path)
2073+{
2074+ buf->name = ccs_realpath(path);
2075+ if (buf->name) {
2076+ ccs_fill_path_info(buf);
2077+ return true;
2078+ }
2079+ return false;
2080+}
2081+
2082+/**
2083+ * ccs_check_path_acl - Check permission for path operation.
2084+ *
2085+ * @r: Pointer to "struct ccs_request_info".
2086+ * @ptr: Pointer to "struct ccs_acl_info".
2087+ *
2088+ * Returns true if granted, false otherwise.
2089+ *
2090+ * To be able to use wildcard for domain transition, this function sets
2091+ * matching entry on success. Since the caller holds ccs_read_lock(),
2092+ * it is safe to set matching entry.
2093+ */
2094+static bool ccs_check_path_acl(struct ccs_request_info *r,
2095+ const struct ccs_acl_info *ptr)
2096+{
2097+ const struct ccs_path_acl *acl = container_of(ptr, typeof(*acl), head);
2098+ if (ptr->perm & (1 << r->param.path.operation)) {
2099+ r->param.path.matched_path =
2100+ ccs_compare_name_union(r->param.path.filename,
2101+ &acl->name);
2102+ return r->param.path.matched_path != NULL;
2103+ }
2104+ return false;
2105+}
2106+
2107+/**
2108+ * ccs_check_path_number_acl - Check permission for path number operation.
2109+ *
2110+ * @r: Pointer to "struct ccs_request_info".
2111+ * @ptr: Pointer to "struct ccs_acl_info".
2112+ *
2113+ * Returns true if granted, false otherwise.
2114+ */
2115+static bool ccs_check_path_number_acl(struct ccs_request_info *r,
2116+ const struct ccs_acl_info *ptr)
2117+{
2118+ const struct ccs_path_number_acl *acl =
2119+ container_of(ptr, typeof(*acl), head);
2120+ return (ptr->perm & (1 << r->param.path_number.operation)) &&
2121+ ccs_compare_number_union(r->param.path_number.number,
2122+ &acl->number) &&
2123+ ccs_compare_name_union(r->param.path_number.filename,
2124+ &acl->name);
2125+}
2126+
2127+/**
2128+ * ccs_check_path2_acl - Check permission for path path operation.
2129+ *
2130+ * @r: Pointer to "struct ccs_request_info".
2131+ * @ptr: Pointer to "struct ccs_acl_info".
2132+ *
2133+ * Returns true if granted, false otherwise.
2134+ */
2135+static bool ccs_check_path2_acl(struct ccs_request_info *r,
2136+ const struct ccs_acl_info *ptr)
2137+{
2138+ const struct ccs_path2_acl *acl =
2139+ container_of(ptr, typeof(*acl), head);
2140+ return (ptr->perm & (1 << r->param.path2.operation)) &&
2141+ ccs_compare_name_union(r->param.path2.filename1, &acl->name1)
2142+ && ccs_compare_name_union(r->param.path2.filename2,
2143+ &acl->name2);
2144+}
2145+
2146+/**
2147+ * ccs_check_mkdev_acl - Check permission for path number number number operation.
2148+ *
2149+ * @r: Pointer to "struct ccs_request_info".
2150+ * @ptr: Pointer to "struct ccs_acl_info".
2151+ *
2152+ * Returns true if granted, false otherwise.
2153+ */
2154+static bool ccs_check_mkdev_acl(struct ccs_request_info *r,
2155+ const struct ccs_acl_info *ptr)
2156+{
2157+ const struct ccs_mkdev_acl *acl =
2158+ container_of(ptr, typeof(*acl), head);
2159+ return (ptr->perm & (1 << r->param.mkdev.operation)) &&
2160+ ccs_compare_number_union(r->param.mkdev.mode, &acl->mode) &&
2161+ ccs_compare_number_union(r->param.mkdev.major, &acl->major) &&
2162+ ccs_compare_number_union(r->param.mkdev.minor, &acl->minor) &&
2163+ ccs_compare_name_union(r->param.mkdev.filename, &acl->name);
2164+}
2165+
2166+/**
2167+ * ccs_path_permission - Check permission for path operation.
2168+ *
2169+ * @r: Pointer to "struct ccs_request_info".
2170+ * @operation: Type of operation.
2171+ * @filename: Filename to check.
2172+ *
2173+ * Returns 0 on success, negative value otherwise.
2174+ *
2175+ * Caller holds ccs_read_lock().
2176+ */
2177+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) || !defined(CONFIG_SYSCTL_SYSCALL)
2178+static
2179+#endif
2180+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
2181+ const struct ccs_path_info *filename)
2182+{
2183+ r->type = ccs_p2mac[operation];
2184+ r->mode = ccs_get_mode(r->profile, r->type);
2185+ if (r->mode == CCS_CONFIG_DISABLED)
2186+ return 0;
2187+ r->param_type = CCS_TYPE_PATH_ACL;
2188+ r->param.path.filename = filename;
2189+ r->param.path.operation = operation;
2190+ return ccs_check_acl(r);
2191+}
2192+
2193+/**
2194+ * ccs_execute_permission - Check permission for execute operation.
2195+ *
2196+ * @r: Pointer to "struct ccs_request_info".
2197+ * @filename: Filename to check.
2198+ *
2199+ * Returns 0 on success, CCS_RETRY_REQUEST on retry, negative value otherwise.
2200+ *
2201+ * Caller holds ccs_read_lock().
2202+ */
2203+static int ccs_execute_permission(struct ccs_request_info *r,
2204+ const struct ccs_path_info *filename)
2205+{
2206+ int error;
2207+ /*
2208+ * Unlike other permission checks, this check is done regardless of
2209+ * profile mode settings in order to check for domain transition
2210+ * preference.
2211+ */
2212+ r->type = CCS_MAC_FILE_EXECUTE;
2213+ r->mode = ccs_get_mode(r->profile, r->type);
2214+ r->param_type = CCS_TYPE_PATH_ACL;
2215+ r->param.path.filename = filename;
2216+ r->param.path.operation = CCS_TYPE_EXECUTE;
2217+ error = ccs_check_acl(r);
2218+ r->ee->transition = r->matched_acl && r->matched_acl->cond &&
2219+ r->matched_acl->cond->exec_transit ?
2220+ r->matched_acl->cond->transit : NULL;
2221+ return error;
2222+}
2223+
2224+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
2225+
2226+/**
2227+ * __ccs_save_open_mode - Remember original flags passed to sys_open().
2228+ *
2229+ * @mode: Flags passed to sys_open().
2230+ *
2231+ * Returns nothing.
2232+ *
2233+ * TOMOYO does not check "file write" if open(path, O_TRUNC | O_RDONLY) was
2234+ * requested because write() is not permitted. Instead, TOMOYO checks
2235+ * "file truncate" if O_TRUNC is passed.
2236+ *
2237+ * TOMOYO does not check "file read" and "file write" if open(path, 3) was
2238+ * requested because read()/write() are not permitted. Instead, TOMOYO checks
2239+ * "file ioctl" when ioctl() is requested.
2240+ */
2241+static void __ccs_save_open_mode(int mode)
2242+{
2243+ if ((mode & 3) == 3)
2244+ ccs_current_security()->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
2245+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
2246+ /* O_TRUNC passes MAY_WRITE to ccs_open_permission(). */
2247+ else if (!(mode & 3) && (mode & O_TRUNC))
2248+ ccs_current_security()->ccs_flags |=
2249+ CCS_OPEN_FOR_READ_TRUNCATE;
2250+#endif
2251+}
2252+
2253+/**
2254+ * __ccs_clear_open_mode - Forget original flags passed to sys_open().
2255+ *
2256+ * Returns nothing.
2257+ */
2258+static void __ccs_clear_open_mode(void)
2259+{
2260+ ccs_current_security()->ccs_flags &= ~(CCS_OPEN_FOR_IOCTL_ONLY |
2261+ CCS_OPEN_FOR_READ_TRUNCATE);
2262+}
2263+
2264+#endif
2265+
2266+/**
2267+ * __ccs_open_permission - Check permission for "read" and "write".
2268+ *
2269+ * @dentry: Pointer to "struct dentry".
2270+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2271+ * @flag: Flags for open().
2272+ *
2273+ * Returns 0 on success, negative value otherwise.
2274+ */
2275+static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
2276+ const int flag)
2277+{
2278+ struct ccs_request_info r;
2279+ struct ccs_obj_info obj = {
2280+ .path1.dentry = dentry,
2281+ .path1.mnt = mnt,
2282+ };
2283+ const u32 ccs_flags = ccs_current_flags();
2284+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2285+ const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
2286+#else
2287+ const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
2288+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
2289+ (ccs_flags & CCS_OPEN_FOR_READ_TRUNCATE) ? 4 :
2290+#endif
2291+ ACC_MODE(flag);
2292+#endif
2293+ int error = 0;
2294+ struct ccs_path_info buf;
2295+ int idx;
2296+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
2297+ if (current->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
2298+ return 0;
2299+#endif
2300+#ifndef CONFIG_CCSECURITY_FILE_READDIR
2301+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2302+ if (d_is_dir(dentry))
2303+ return 0;
2304+#else
2305+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
2306+ return 0;
2307+#endif
2308+#endif
2309+ buf.name = NULL;
2310+ r.mode = CCS_CONFIG_DISABLED;
2311+ idx = ccs_read_lock();
2312+ if (acc_mode && ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2313+ != CCS_CONFIG_DISABLED) {
2314+ if (!ccs_get_realpath(&buf, &obj.path1)) {
2315+ error = -ENOMEM;
2316+ goto out;
2317+ }
2318+ r.obj = &obj;
2319+ if (acc_mode & MAY_READ)
2320+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
2321+ if (!error && (acc_mode & MAY_WRITE))
2322+ error = ccs_path_permission(&r, (flag & O_APPEND) ?
2323+ CCS_TYPE_APPEND :
2324+ CCS_TYPE_WRITE, &buf);
2325+ }
2326+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
2327+ if (!error && (flag & O_TRUNC) &&
2328+ ccs_init_request_info(&r, CCS_MAC_FILE_TRUNCATE)
2329+ != CCS_CONFIG_DISABLED) {
2330+ if (!buf.name && !ccs_get_realpath(&buf, &obj.path1)) {
2331+ error = -ENOMEM;
2332+ goto out;
2333+ }
2334+ r.obj = &obj;
2335+ error = ccs_path_permission(&r, CCS_TYPE_TRUNCATE, &buf);
2336+ }
2337+#endif
2338+out:
2339+ kfree(buf.name);
2340+ ccs_read_unlock(idx);
2341+ if (r.mode != CCS_CONFIG_ENFORCING)
2342+ error = 0;
2343+ return error;
2344+}
2345+
2346+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2347+
2348+/**
2349+ * ccs_new_open_permission - Check permission for "read" and "write".
2350+ *
2351+ * @filp: Pointer to "struct file".
2352+ *
2353+ * Returns 0 on success, negative value otherwise.
2354+ */
2355+static int ccs_new_open_permission(struct file *filp)
2356+{
2357+ return __ccs_open_permission(filp->f_path.dentry, filp->f_path.mnt,
2358+ filp->f_flags);
2359+}
2360+
2361+#endif
2362+
2363+/**
2364+ * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "getattr", "chroot" and "unmount".
2365+ *
2366+ * @operation: Type of operation.
2367+ * @dentry: Pointer to "struct dentry".
2368+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2369+ * @target: Symlink's target if @operation is CCS_TYPE_SYMLINK,
2370+ * NULL otherwise.
2371+ *
2372+ * Returns 0 on success, negative value otherwise.
2373+ */
2374+static int ccs_path_perm(const u8 operation, struct dentry *dentry,
2375+ struct vfsmount *mnt, const char *target)
2376+{
2377+ struct ccs_request_info r;
2378+ struct ccs_obj_info obj = {
2379+ .path1.dentry = dentry,
2380+ .path1.mnt = mnt,
2381+ };
2382+ int error = 0;
2383+ struct ccs_path_info buf;
2384+ bool is_enforce = false;
2385+ struct ccs_path_info symlink_target;
2386+ int idx;
2387+ buf.name = NULL;
2388+ symlink_target.name = NULL;
2389+ idx = ccs_read_lock();
2390+ if (ccs_init_request_info(&r, ccs_p2mac[operation])
2391+ == CCS_CONFIG_DISABLED)
2392+ goto out;
2393+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2394+ error = -ENOMEM;
2395+ if (!ccs_get_realpath(&buf, &obj.path1))
2396+ goto out;
2397+ r.obj = &obj;
2398+ switch (operation) {
2399+ case CCS_TYPE_RMDIR:
2400+ case CCS_TYPE_CHROOT:
2401+ ccs_add_slash(&buf);
2402+ break;
2403+ case CCS_TYPE_SYMLINK:
2404+ symlink_target.name = ccs_encode(target);
2405+ if (!symlink_target.name)
2406+ goto out;
2407+ ccs_fill_path_info(&symlink_target);
2408+ obj.symlink_target = &symlink_target;
2409+ break;
2410+ }
2411+ error = ccs_path_permission(&r, operation, &buf);
2412+ if (operation == CCS_TYPE_SYMLINK)
2413+ kfree(symlink_target.name);
2414+out:
2415+ kfree(buf.name);
2416+ ccs_read_unlock(idx);
2417+ if (!is_enforce)
2418+ error = 0;
2419+ return error;
2420+}
2421+
2422+/**
2423+ * ccs_mkdev_perm - Check permission for "mkblock" and "mkchar".
2424+ *
2425+ * @operation: Type of operation. (CCS_TYPE_MKCHAR or CCS_TYPE_MKBLOCK)
2426+ * @dentry: Pointer to "struct dentry".
2427+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2428+ * @mode: Create mode.
2429+ * @dev: Device number.
2430+ *
2431+ * Returns 0 on success, negative value otherwise.
2432+ */
2433+static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
2434+ struct vfsmount *mnt, const unsigned int mode,
2435+ unsigned int dev)
2436+{
2437+ struct ccs_request_info r;
2438+ struct ccs_obj_info obj = {
2439+ .path1.dentry = dentry,
2440+ .path1.mnt = mnt,
2441+ };
2442+ int error = 0;
2443+ struct ccs_path_info buf;
2444+ bool is_enforce = false;
2445+ int idx;
2446+ idx = ccs_read_lock();
2447+ if (ccs_init_request_info(&r, ccs_pnnn2mac[operation])
2448+ == CCS_CONFIG_DISABLED)
2449+ goto out;
2450+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2451+ error = -EPERM;
2452+ if (!capable(CAP_MKNOD))
2453+ goto out;
2454+ error = -ENOMEM;
2455+ if (!ccs_get_realpath(&buf, &obj.path1))
2456+ goto out;
2457+ r.obj = &obj;
2458+#ifdef CONFIG_SECURITY_PATH
2459+ dev = new_decode_dev(dev);
2460+#endif
2461+ r.param_type = CCS_TYPE_MKDEV_ACL;
2462+ r.param.mkdev.filename = &buf;
2463+ r.param.mkdev.operation = operation;
2464+ r.param.mkdev.mode = mode;
2465+ r.param.mkdev.major = MAJOR(dev);
2466+ r.param.mkdev.minor = MINOR(dev);
2467+ error = ccs_check_acl(&r);
2468+ kfree(buf.name);
2469+out:
2470+ ccs_read_unlock(idx);
2471+ if (!is_enforce)
2472+ error = 0;
2473+ return error;
2474+}
2475+
2476+/**
2477+ * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
2478+ *
2479+ * @operation: Type of operation.
2480+ * @dentry1: Pointer to "struct dentry".
2481+ * @mnt1: Pointer to "struct vfsmount". Maybe NULL.
2482+ * @dentry2: Pointer to "struct dentry".
2483+ * @mnt2: Pointer to "struct vfsmount". Maybe NULL.
2484+ *
2485+ * Returns 0 on success, negative value otherwise.
2486+ */
2487+static int ccs_path2_perm(const u8 operation, struct dentry *dentry1,
2488+ struct vfsmount *mnt1, struct dentry *dentry2,
2489+ struct vfsmount *mnt2)
2490+{
2491+ struct ccs_request_info r;
2492+ int error = 0;
2493+ struct ccs_path_info buf1;
2494+ struct ccs_path_info buf2;
2495+ bool is_enforce = false;
2496+ struct ccs_obj_info obj = {
2497+ .path1.dentry = dentry1,
2498+ .path1.mnt = mnt1,
2499+ .path2.dentry = dentry2,
2500+ .path2.mnt = mnt2,
2501+ };
2502+ int idx;
2503+ buf1.name = NULL;
2504+ buf2.name = NULL;
2505+ idx = ccs_read_lock();
2506+ if (ccs_init_request_info(&r, ccs_pp2mac[operation])
2507+ == CCS_CONFIG_DISABLED)
2508+ goto out;
2509+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2510+ error = -ENOMEM;
2511+ if (!ccs_get_realpath(&buf1, &obj.path1) ||
2512+ !ccs_get_realpath(&buf2, &obj.path2))
2513+ goto out;
2514+ switch (operation) {
2515+ case CCS_TYPE_RENAME:
2516+ case CCS_TYPE_LINK:
2517+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2518+ if (!d_is_dir(dentry1))
2519+ break;
2520+#else
2521+ if (!dentry1->d_inode || !S_ISDIR(dentry1->d_inode->i_mode))
2522+ break;
2523+#endif
2524+ /* fall through */
2525+ case CCS_TYPE_PIVOT_ROOT:
2526+ ccs_add_slash(&buf1);
2527+ ccs_add_slash(&buf2);
2528+ break;
2529+ }
2530+ r.obj = &obj;
2531+ r.param_type = CCS_TYPE_PATH2_ACL;
2532+ r.param.path2.operation = operation;
2533+ r.param.path2.filename1 = &buf1;
2534+ r.param.path2.filename2 = &buf2;
2535+ error = ccs_check_acl(&r);
2536+out:
2537+ kfree(buf1.name);
2538+ kfree(buf2.name);
2539+ ccs_read_unlock(idx);
2540+ if (!is_enforce)
2541+ error = 0;
2542+ return error;
2543+}
2544+
2545+/**
2546+ * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
2547+ *
2548+ * @type: Type of operation.
2549+ * @dentry: Pointer to "struct dentry".
2550+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2551+ * @number: Number.
2552+ *
2553+ * Returns 0 on success, negative value otherwise.
2554+ */
2555+static int ccs_path_number_perm(const u8 type, struct dentry *dentry,
2556+ struct vfsmount *vfsmnt, unsigned long number)
2557+{
2558+ struct ccs_request_info r;
2559+ struct ccs_obj_info obj = {
2560+ .path1.dentry = dentry,
2561+ .path1.mnt = vfsmnt,
2562+ };
2563+ int error = 0;
2564+ struct ccs_path_info buf;
2565+ int idx;
2566+ if (!dentry)
2567+ return 0;
2568+ idx = ccs_read_lock();
2569+ if (ccs_init_request_info(&r, ccs_pn2mac[type]) == CCS_CONFIG_DISABLED)
2570+ goto out;
2571+ error = -ENOMEM;
2572+ if (!ccs_get_realpath(&buf, &obj.path1))
2573+ goto out;
2574+ r.obj = &obj;
2575+ if (type == CCS_TYPE_MKDIR)
2576+ ccs_add_slash(&buf);
2577+ r.param_type = CCS_TYPE_PATH_NUMBER_ACL;
2578+ r.param.path_number.operation = type;
2579+ r.param.path_number.filename = &buf;
2580+ r.param.path_number.number = number;
2581+ error = ccs_check_acl(&r);
2582+ kfree(buf.name);
2583+out:
2584+ ccs_read_unlock(idx);
2585+ if (r.mode != CCS_CONFIG_ENFORCING)
2586+ error = 0;
2587+ return error;
2588+}
2589+
2590+/**
2591+ * __ccs_ioctl_permission - Check permission for "ioctl".
2592+ *
2593+ * @filp: Pointer to "struct file".
2594+ * @cmd: Ioctl command number.
2595+ * @arg: Param for @cmd.
2596+ *
2597+ * Returns 0 on success, negative value otherwise.
2598+ */
2599+static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
2600+ unsigned long arg)
2601+{
2602+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
2603+ return ccs_path_number_perm(CCS_TYPE_IOCTL, filp->f_path.dentry,
2604+ filp->f_path.mnt, cmd);
2605+#else
2606+ return ccs_path_number_perm(CCS_TYPE_IOCTL, filp->f_dentry,
2607+ filp->f_vfsmnt, cmd);
2608+#endif
2609+}
2610+
2611+/**
2612+ * __ccs_chmod_permission - Check permission for "chmod".
2613+ *
2614+ * @dentry: Pointer to "struct dentry".
2615+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2616+ * @mode: Mode.
2617+ *
2618+ * Returns 0 on success, negative value otherwise.
2619+ */
2620+static int __ccs_chmod_permission(struct dentry *dentry,
2621+ struct vfsmount *vfsmnt, mode_t mode)
2622+{
2623+ return ccs_path_number_perm(CCS_TYPE_CHMOD, dentry, vfsmnt,
2624+ mode & S_IALLUGO);
2625+}
2626+
2627+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
2628+
2629+/**
2630+ * __ccs_chown_permission - Check permission for "chown/chgrp".
2631+ *
2632+ * @dentry: Pointer to "struct dentry".
2633+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2634+ * @user: User ID.
2635+ * @group: Group ID.
2636+ *
2637+ * Returns 0 on success, negative value otherwise.
2638+ */
2639+static int __ccs_chown_permission(struct dentry *dentry,
2640+ struct vfsmount *vfsmnt, kuid_t user,
2641+ kgid_t group)
2642+{
2643+ int error = 0;
2644+ if (uid_valid(user))
2645+ error = ccs_path_number_perm(CCS_TYPE_CHOWN, dentry, vfsmnt,
2646+ from_kuid(&init_user_ns, user));
2647+ if (!error && gid_valid(group))
2648+ error = ccs_path_number_perm(CCS_TYPE_CHGRP, dentry, vfsmnt,
2649+ from_kgid(&init_user_ns, group));
2650+ return error;
2651+}
2652+
2653+#else
2654+
2655+/**
2656+ * __ccs_chown_permission - Check permission for "chown/chgrp".
2657+ *
2658+ * @dentry: Pointer to "struct dentry".
2659+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2660+ * @user: User ID.
2661+ * @group: Group ID.
2662+ *
2663+ * Returns 0 on success, negative value otherwise.
2664+ */
2665+static int __ccs_chown_permission(struct dentry *dentry,
2666+ struct vfsmount *vfsmnt, uid_t user,
2667+ gid_t group)
2668+{
2669+ int error = 0;
2670+ if (user == (uid_t) -1 && group == (gid_t) -1)
2671+ return 0;
2672+ if (user != (uid_t) -1)
2673+ error = ccs_path_number_perm(CCS_TYPE_CHOWN, dentry, vfsmnt,
2674+ user);
2675+ if (!error && group != (gid_t) -1)
2676+ error = ccs_path_number_perm(CCS_TYPE_CHGRP, dentry, vfsmnt,
2677+ group);
2678+ return error;
2679+}
2680+
2681+#endif
2682+
2683+/**
2684+ * __ccs_fcntl_permission - Check permission for changing O_APPEND flag.
2685+ *
2686+ * @file: Pointer to "struct file".
2687+ * @cmd: Command number.
2688+ * @arg: Value for @cmd.
2689+ *
2690+ * Returns 0 on success, negative value otherwise.
2691+ */
2692+static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
2693+ unsigned long arg)
2694+{
2695+ if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
2696+ return 0;
2697+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2698+ return __ccs_open_permission(file->f_path.dentry, file->f_path.mnt,
2699+ O_WRONLY | (arg & O_APPEND));
2700+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
2701+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2702+ O_WRONLY | (arg & O_APPEND));
2703+#else
2704+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2705+ (O_WRONLY + 1) | (arg & O_APPEND));
2706+#endif
2707+}
2708+
2709+/**
2710+ * __ccs_pivot_root_permission - Check permission for pivot_root().
2711+ *
2712+ * @old_path: Pointer to "struct path".
2713+ * @new_path: Pointer to "struct path".
2714+ *
2715+ * Returns 0 on success, negative value otherwise.
2716+ */
2717+static int __ccs_pivot_root_permission(struct path *old_path,
2718+ struct path *new_path)
2719+{
2720+ return ccs_path2_perm(CCS_TYPE_PIVOT_ROOT, new_path->dentry,
2721+ new_path->mnt, old_path->dentry, old_path->mnt);
2722+}
2723+
2724+/**
2725+ * __ccs_chroot_permission - Check permission for chroot().
2726+ *
2727+ * @path: Pointer to "struct path".
2728+ *
2729+ * Returns 0 on success, negative value otherwise.
2730+ */
2731+static int __ccs_chroot_permission(struct path *path)
2732+{
2733+ return ccs_path_perm(CCS_TYPE_CHROOT, path->dentry, path->mnt, NULL);
2734+}
2735+
2736+/**
2737+ * __ccs_umount_permission - Check permission for unmount.
2738+ *
2739+ * @mnt: Pointer to "struct vfsmount".
2740+ * @flags: Unused.
2741+ *
2742+ * Returns 0 on success, negative value otherwise.
2743+ */
2744+static int __ccs_umount_permission(struct vfsmount *mnt, int flags)
2745+{
2746+ return ccs_path_perm(CCS_TYPE_UMOUNT, mnt->mnt_root, mnt, NULL);
2747+}
2748+
2749+/**
2750+ * __ccs_mknod_permission - Check permission for vfs_mknod().
2751+ *
2752+ * @dentry: Pointer to "struct dentry".
2753+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2754+ * @mode: Device type and permission.
2755+ * @dev: Device number for block or character device.
2756+ *
2757+ * Returns 0 on success, negative value otherwise.
2758+ */
2759+static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
2760+ const unsigned int mode, unsigned int dev)
2761+{
2762+ int error = 0;
2763+ const unsigned int perm = mode & S_IALLUGO;
2764+ switch (mode & S_IFMT) {
2765+ case S_IFCHR:
2766+ error = ccs_mkdev_perm(CCS_TYPE_MKCHAR, dentry, mnt, perm,
2767+ dev);
2768+ break;
2769+ case S_IFBLK:
2770+ error = ccs_mkdev_perm(CCS_TYPE_MKBLOCK, dentry, mnt, perm,
2771+ dev);
2772+ break;
2773+ case S_IFIFO:
2774+ error = ccs_path_number_perm(CCS_TYPE_MKFIFO, dentry, mnt,
2775+ perm);
2776+ break;
2777+ case S_IFSOCK:
2778+ error = ccs_path_number_perm(CCS_TYPE_MKSOCK, dentry, mnt,
2779+ perm);
2780+ break;
2781+ case 0:
2782+ case S_IFREG:
2783+ error = ccs_path_number_perm(CCS_TYPE_CREATE, dentry, mnt,
2784+ perm);
2785+ break;
2786+ }
2787+ return error;
2788+}
2789+
2790+/**
2791+ * __ccs_mkdir_permission - Check permission for vfs_mkdir().
2792+ *
2793+ * @dentry: Pointer to "struct dentry".
2794+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2795+ * @mode: Create mode.
2796+ *
2797+ * Returns 0 on success, negative value otherwise.
2798+ */
2799+static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
2800+ unsigned int mode)
2801+{
2802+ return ccs_path_number_perm(CCS_TYPE_MKDIR, dentry, mnt, mode);
2803+}
2804+
2805+/**
2806+ * __ccs_rmdir_permission - Check permission for vfs_rmdir().
2807+ *
2808+ * @dentry: Pointer to "struct dentry".
2809+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2810+ *
2811+ * Returns 0 on success, negative value otherwise.
2812+ */
2813+static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt)
2814+{
2815+ return ccs_path_perm(CCS_TYPE_RMDIR, dentry, mnt, NULL);
2816+}
2817+
2818+/**
2819+ * __ccs_unlink_permission - Check permission for vfs_unlink().
2820+ *
2821+ * @dentry: Pointer to "struct dentry".
2822+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2823+ *
2824+ * Returns 0 on success, negative value otherwise.
2825+ */
2826+static int __ccs_unlink_permission(struct dentry *dentry, struct vfsmount *mnt)
2827+{
2828+ return ccs_path_perm(CCS_TYPE_UNLINK, dentry, mnt, NULL);
2829+}
2830+
2831+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
2832+
2833+/**
2834+ * __ccs_getattr_permission - Check permission for vfs_getattr().
2835+ *
2836+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2837+ * @dentry: Pointer to "struct dentry".
2838+ *
2839+ * Returns 0 on success, negative value otherwise.
2840+ */
2841+static int __ccs_getattr_permission(struct vfsmount *mnt,
2842+ struct dentry *dentry)
2843+{
2844+ return ccs_path_perm(CCS_TYPE_GETATTR, dentry, mnt, NULL);
2845+}
2846+
2847+#endif
2848+
2849+/**
2850+ * __ccs_symlink_permission - Check permission for vfs_symlink().
2851+ *
2852+ * @dentry: Pointer to "struct dentry".
2853+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2854+ * @from: Content of symlink.
2855+ *
2856+ * Returns 0 on success, negative value otherwise.
2857+ */
2858+static int __ccs_symlink_permission(struct dentry *dentry,
2859+ struct vfsmount *mnt, const char *from)
2860+{
2861+ return ccs_path_perm(CCS_TYPE_SYMLINK, dentry, mnt, from);
2862+}
2863+
2864+/**
2865+ * __ccs_truncate_permission - Check permission for notify_change().
2866+ *
2867+ * @dentry: Pointer to "struct dentry".
2868+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2869+ *
2870+ * Returns 0 on success, negative value otherwise.
2871+ */
2872+static int __ccs_truncate_permission(struct dentry *dentry,
2873+ struct vfsmount *mnt)
2874+{
2875+ return ccs_path_perm(CCS_TYPE_TRUNCATE, dentry, mnt, NULL);
2876+}
2877+
2878+/**
2879+ * __ccs_rename_permission - Check permission for vfs_rename().
2880+ *
2881+ * @old_dentry: Pointer to "struct dentry".
2882+ * @new_dentry: Pointer to "struct dentry".
2883+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2884+ *
2885+ * Returns 0 on success, negative value otherwise.
2886+ */
2887+static int __ccs_rename_permission(struct dentry *old_dentry,
2888+ struct dentry *new_dentry,
2889+ struct vfsmount *mnt)
2890+{
2891+ return ccs_path2_perm(CCS_TYPE_RENAME, old_dentry, mnt, new_dentry,
2892+ mnt);
2893+}
2894+
2895+/**
2896+ * __ccs_link_permission - Check permission for vfs_link().
2897+ *
2898+ * @old_dentry: Pointer to "struct dentry".
2899+ * @new_dentry: Pointer to "struct dentry".
2900+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2901+ *
2902+ * Returns 0 on success, negative value otherwise.
2903+ */
2904+static int __ccs_link_permission(struct dentry *old_dentry,
2905+ struct dentry *new_dentry,
2906+ struct vfsmount *mnt)
2907+{
2908+ return ccs_path2_perm(CCS_TYPE_LINK, old_dentry, mnt, new_dentry, mnt);
2909+}
2910+
2911+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
2912+
2913+/**
2914+ * __ccs_open_exec_permission - Check permission for open_exec().
2915+ *
2916+ * @dentry: Pointer to "struct dentry".
2917+ * @mnt: Pointer to "struct vfsmount".
2918+ *
2919+ * Returns 0 on success, negative value otherwise.
2920+ */
2921+static int __ccs_open_exec_permission(struct dentry *dentry,
2922+ struct vfsmount *mnt)
2923+{
2924+ return (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE) ?
2925+ __ccs_open_permission(dentry, mnt, O_RDONLY + 1) : 0;
2926+}
2927+
2928+/**
2929+ * __ccs_uselib_permission - Check permission for sys_uselib().
2930+ *
2931+ * @dentry: Pointer to "struct dentry".
2932+ * @mnt: Pointer to "struct vfsmount".
2933+ *
2934+ * Returns 0 on success, negative value otherwise.
2935+ */
2936+static int __ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
2937+{
2938+ return __ccs_open_permission(dentry, mnt, O_RDONLY + 1);
2939+}
2940+
2941+#endif
2942+
2943+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
2944+
2945+/**
2946+ * __ccs_parse_table - Check permission for parse_table().
2947+ *
2948+ * @name: Pointer to "int __user".
2949+ * @nlen: Number of elements in @name.
2950+ * @oldval: Pointer to "void __user".
2951+ * @newval: Pointer to "void __user".
2952+ * @table: Pointer to "struct ctl_table".
2953+ *
2954+ * Returns 0 on success, negative value otherwise.
2955+ *
2956+ * Note that this function is racy because this function checks values in
2957+ * userspace memory which could be changed after permission check.
2958+ */
2959+static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
2960+ void __user *newval, struct ctl_table *table)
2961+{
2962+ int n;
2963+ int error = -ENOMEM;
2964+ int op = 0;
2965+ struct ccs_path_info buf;
2966+ char *buffer = NULL;
2967+ struct ccs_request_info r;
2968+ int idx;
2969+ if (oldval)
2970+ op |= 004;
2971+ if (newval)
2972+ op |= 002;
2973+ if (!op) /* Neither read nor write */
2974+ return 0;
2975+ idx = ccs_read_lock();
2976+ if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2977+ == CCS_CONFIG_DISABLED) {
2978+ error = 0;
2979+ goto out;
2980+ }
2981+ buffer = kmalloc(PAGE_SIZE, CCS_GFP_FLAGS);
2982+ if (!buffer)
2983+ goto out;
2984+ snprintf(buffer, PAGE_SIZE - 1, "proc:/sys");
2985+repeat:
2986+ if (!nlen) {
2987+ error = -ENOTDIR;
2988+ goto out;
2989+ }
2990+ if (get_user(n, name)) {
2991+ error = -EFAULT;
2992+ goto out;
2993+ }
2994+ for ( ; table->ctl_name
2995+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
2996+ || table->procname
2997+#endif
2998+ ; table++) {
2999+ int pos;
3000+ const char *cp;
3001+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
3002+ if (n != table->ctl_name && table->ctl_name != CTL_ANY)
3003+ continue;
3004+#else
3005+ if (!n || n != table->ctl_name)
3006+ continue;
3007+#endif
3008+ pos = strlen(buffer);
3009+ cp = table->procname;
3010+ error = -ENOMEM;
3011+ if (cp) {
3012+ int len = strlen(cp);
3013+ if (len + 2 > PAGE_SIZE - 1)
3014+ goto out;
3015+ buffer[pos++] = '/';
3016+ memmove(buffer + pos, cp, len + 1);
3017+ } else {
3018+ /* Assume nobody assigns "=\$=" for procname. */
3019+ snprintf(buffer + pos, PAGE_SIZE - pos - 1,
3020+ "/=%d=", table->ctl_name);
3021+ if (!memchr(buffer, '\0', PAGE_SIZE - 2))
3022+ goto out;
3023+ }
3024+ if (!table->child)
3025+ goto no_child;
3026+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
3027+ if (!table->strategy)
3028+ goto no_strategy;
3029+ /* printk("sysctl='%s'\n", buffer); */
3030+ buf.name = ccs_encode(buffer);
3031+ if (!buf.name)
3032+ goto out;
3033+ ccs_fill_path_info(&buf);
3034+ if (op & MAY_READ)
3035+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
3036+ else
3037+ error = 0;
3038+ if (!error && (op & MAY_WRITE))
3039+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
3040+ kfree(buf.name);
3041+ if (error)
3042+ goto out;
3043+no_strategy:
3044+#endif
3045+ name++;
3046+ nlen--;
3047+ table = table->child;
3048+ goto repeat;
3049+no_child:
3050+ /* printk("sysctl='%s'\n", buffer); */
3051+ buf.name = ccs_encode(buffer);
3052+ if (!buf.name)
3053+ goto out;
3054+ ccs_fill_path_info(&buf);
3055+ if (op & MAY_READ)
3056+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
3057+ else
3058+ error = 0;
3059+ if (!error && (op & MAY_WRITE))
3060+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
3061+ kfree(buf.name);
3062+ goto out;
3063+ }
3064+ error = -ENOTDIR;
3065+out:
3066+ ccs_read_unlock(idx);
3067+ kfree(buffer);
3068+ return error;
3069+}
3070+
3071+#endif
3072+
3073+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
3074+
3075+/**
3076+ * ccs_old_pivot_root_permission - Check permission for pivot_root().
3077+ *
3078+ * @old_nd: Pointer to "struct nameidata".
3079+ * @new_nd: Pointer to "struct nameidata".
3080+ *
3081+ * Returns 0 on success, negative value otherwise.
3082+ */
3083+static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
3084+ struct nameidata *new_nd)
3085+{
3086+ struct path old_path = { old_nd->mnt, old_nd->dentry };
3087+ struct path new_path = { new_nd->mnt, new_nd->dentry };
3088+ return __ccs_pivot_root_permission(&old_path, &new_path);
3089+}
3090+
3091+/**
3092+ * ccs_old_chroot_permission - Check permission for chroot().
3093+ *
3094+ * @nd: Pointer to "struct nameidata".
3095+ *
3096+ * Returns 0 on success, negative value otherwise.
3097+ */
3098+static int ccs_old_chroot_permission(struct nameidata *nd)
3099+{
3100+ struct path path = { nd->mnt, nd->dentry };
3101+ return __ccs_chroot_permission(&path);
3102+}
3103+
3104+#endif
3105+
3106+#ifdef CONFIG_CCSECURITY_NETWORK
3107+
3108+/**
3109+ * ccs_address_matches_group - Check whether the given address matches members of the given address group.
3110+ *
3111+ * @is_ipv6: True if @address is an IPv6 address.
3112+ * @address: An IPv4 or IPv6 address.
3113+ * @group: Pointer to "struct ccs_address_group".
3114+ *
3115+ * Returns true if @address matches addresses in @group group, false otherwise.
3116+ *
3117+ * Caller holds ccs_read_lock().
3118+ */
3119+static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
3120+ const struct ccs_group *group)
3121+{
3122+ struct ccs_address_group *member;
3123+ bool matched = false;
3124+ const u8 size = is_ipv6 ? 16 : 4;
3125+ list_for_each_entry_srcu(member, &group->member_list, head.list,
3126+ &ccs_ss) {
3127+ if (member->head.is_deleted)
3128+ continue;
3129+ if (member->address.is_ipv6 != is_ipv6)
3130+ continue;
3131+ if (memcmp(&member->address.ip[0], address, size) > 0 ||
3132+ memcmp(address, &member->address.ip[1], size) > 0)
3133+ continue;
3134+ matched = true;
3135+ break;
3136+ }
3137+ return matched;
3138+}
3139+
3140+/**
3141+ * ccs_check_inet_acl - Check permission for inet domain socket operation.
3142+ *
3143+ * @r: Pointer to "struct ccs_request_info".
3144+ * @ptr: Pointer to "struct ccs_acl_info".
3145+ *
3146+ * Returns true if granted, false otherwise.
3147+ */
3148+static bool ccs_check_inet_acl(struct ccs_request_info *r,
3149+ const struct ccs_acl_info *ptr)
3150+{
3151+ const struct ccs_inet_acl *acl = container_of(ptr, typeof(*acl), head);
3152+ const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4;
3153+ if (!(ptr->perm & (1 << r->param.inet_network.operation)) ||
3154+ !ccs_compare_number_union(r->param.inet_network.port, &acl->port))
3155+ return false;
3156+ if (acl->address.group)
3157+ return ccs_address_matches_group(r->param.inet_network.is_ipv6,
3158+ r->param.inet_network.address,
3159+ acl->address.group);
3160+ return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 &&
3161+ memcmp(&acl->address.ip[0],
3162+ r->param.inet_network.address, size) <= 0 &&
3163+ memcmp(r->param.inet_network.address,
3164+ &acl->address.ip[1], size) <= 0;
3165+}
3166+
3167+/**
3168+ * ccs_check_unix_acl - Check permission for unix domain socket operation.
3169+ *
3170+ * @r: Pointer to "struct ccs_request_info".
3171+ * @ptr: Pointer to "struct ccs_acl_info".
3172+ *
3173+ * Returns true if granted, false otherwise.
3174+ */
3175+static bool ccs_check_unix_acl(struct ccs_request_info *r,
3176+ const struct ccs_acl_info *ptr)
3177+{
3178+ const struct ccs_unix_acl *acl = container_of(ptr, typeof(*acl), head);
3179+ return (ptr->perm & (1 << r->param.unix_network.operation)) &&
3180+ ccs_compare_name_union(r->param.unix_network.address,
3181+ &acl->name);
3182+}
3183+
3184+/**
3185+ * ccs_inet_entry - Check permission for INET network operation.
3186+ *
3187+ * @address: Pointer to "struct ccs_addr_info".
3188+ *
3189+ * Returns 0 on success, negative value otherwise.
3190+ */
3191+static int ccs_inet_entry(const struct ccs_addr_info *address)
3192+{
3193+ const int idx = ccs_read_lock();
3194+ struct ccs_request_info r;
3195+ int error = 0;
3196+ const u8 type = ccs_inet2mac[address->protocol][address->operation];
3197+ if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
3198+ r.param_type = CCS_TYPE_INET_ACL;
3199+ r.param.inet_network.protocol = address->protocol;
3200+ r.param.inet_network.operation = address->operation;
3201+ r.param.inet_network.is_ipv6 = address->inet.is_ipv6;
3202+ r.param.inet_network.address = address->inet.address;
3203+ r.param.inet_network.port = ntohs(address->inet.port);
3204+ r.dont_sleep_on_enforce_error =
3205+ address->operation == CCS_NETWORK_ACCEPT
3206+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3207+ || address->operation == CCS_NETWORK_RECV
3208+#endif
3209+ ;
3210+ error = ccs_check_acl(&r);
3211+ }
3212+ ccs_read_unlock(idx);
3213+ return error;
3214+}
3215+
3216+/**
3217+ * ccs_check_inet_address - Check permission for inet domain socket's operation.
3218+ *
3219+ * @addr: Pointer to "struct sockaddr".
3220+ * @addr_len: Size of @addr.
3221+ * @port: Port number.
3222+ * @address: Pointer to "struct ccs_addr_info".
3223+ *
3224+ * Returns 0 on success, negative value otherwise.
3225+ */
3226+static int ccs_check_inet_address(const struct sockaddr *addr,
3227+ const unsigned int addr_len, const u16 port,
3228+ struct ccs_addr_info *address)
3229+{
3230+ struct ccs_inet_addr_info *i = &address->inet;
3231+ switch (addr->sa_family) {
3232+ case AF_INET6:
3233+ if (addr_len < SIN6_LEN_RFC2133)
3234+ goto skip;
3235+ i->is_ipv6 = true;
3236+ i->address = (u32 *)
3237+ ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
3238+ i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
3239+ break;
3240+ case AF_INET:
3241+ if (addr_len < sizeof(struct sockaddr_in))
3242+ goto skip;
3243+ i->is_ipv6 = false;
3244+ i->address = (u32 *) &((struct sockaddr_in *) addr)->sin_addr;
3245+ i->port = ((struct sockaddr_in *) addr)->sin_port;
3246+ break;
3247+ default:
3248+ goto skip;
3249+ }
3250+ if (address->protocol == SOCK_RAW)
3251+ i->port = htons(port);
3252+ return ccs_inet_entry(address);
3253+skip:
3254+ return 0;
3255+}
3256+
3257+/**
3258+ * ccs_unix_entry - Check permission for UNIX network operation.
3259+ *
3260+ * @address: Pointer to "struct ccs_addr_info".
3261+ *
3262+ * Returns 0 on success, negative value otherwise.
3263+ */
3264+static int ccs_unix_entry(const struct ccs_addr_info *address)
3265+{
3266+ const int idx = ccs_read_lock();
3267+ struct ccs_request_info r;
3268+ int error = 0;
3269+ const u8 type = ccs_unix2mac[address->protocol][address->operation];
3270+ if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
3271+ char *buf = address->unix0.addr;
3272+ int len = address->unix0.addr_len - sizeof(sa_family_t);
3273+ if (len <= 0) {
3274+ buf = "anonymous";
3275+ len = 9;
3276+ } else if (buf[0]) {
3277+ len = strnlen(buf, len);
3278+ }
3279+ buf = ccs_encode2(buf, len);
3280+ if (buf) {
3281+ struct ccs_path_info addr;
3282+ addr.name = buf;
3283+ ccs_fill_path_info(&addr);
3284+ r.param_type = CCS_TYPE_UNIX_ACL;
3285+ r.param.unix_network.protocol = address->protocol;
3286+ r.param.unix_network.operation = address->operation;
3287+ r.param.unix_network.address = &addr;
3288+ r.dont_sleep_on_enforce_error =
3289+ address->operation == CCS_NETWORK_ACCEPT
3290+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3291+ || address->operation == CCS_NETWORK_RECV
3292+#endif
3293+ ;
3294+ error = ccs_check_acl(&r);
3295+ kfree(buf);
3296+ } else
3297+ error = -ENOMEM;
3298+ }
3299+ ccs_read_unlock(idx);
3300+ return error;
3301+}
3302+
3303+/**
3304+ * ccs_check_unix_address - Check permission for unix domain socket's operation.
3305+ *
3306+ * @addr: Pointer to "struct sockaddr".
3307+ * @addr_len: Size of @addr.
3308+ * @address: Pointer to "struct ccs_addr_info".
3309+ *
3310+ * Returns 0 on success, negative value otherwise.
3311+ */
3312+static int ccs_check_unix_address(struct sockaddr *addr,
3313+ const unsigned int addr_len,
3314+ struct ccs_addr_info *address)
3315+{
3316+ struct ccs_unix_addr_info *u = &address->unix0;
3317+ if (addr->sa_family != AF_UNIX)
3318+ return 0;
3319+ u->addr = ((struct sockaddr_un *) addr)->sun_path;
3320+ u->addr_len = addr_len;
3321+ return ccs_unix_entry(address);
3322+}
3323+
3324+/**
3325+ * ccs_sock_family - Get socket's family.
3326+ *
3327+ * @sk: Pointer to "struct sock".
3328+ *
3329+ * Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
3330+ */
3331+static u8 ccs_sock_family(struct sock *sk)
3332+{
3333+ u8 family;
3334+ if (ccs_kernel_service())
3335+ return 0;
3336+ family = sk->sk_family;
3337+ switch (family) {
3338+ case PF_INET:
3339+ case PF_INET6:
3340+ case PF_UNIX:
3341+ return family;
3342+ default:
3343+ return 0;
3344+ }
3345+}
3346+
3347+/**
3348+ * __ccs_socket_listen_permission - Check permission for listening a socket.
3349+ *
3350+ * @sock: Pointer to "struct socket".
3351+ *
3352+ * Returns 0 on success, negative value otherwise.
3353+ */
3354+static int __ccs_socket_listen_permission(struct socket *sock)
3355+{
3356+ struct ccs_addr_info address;
3357+ const u8 family = ccs_sock_family(sock->sk);
3358+ const unsigned int type = sock->type;
3359+ struct sockaddr_storage addr;
3360+ int addr_len;
3361+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
3362+ return 0;
3363+ {
3364+ const int error = sock->ops->getname(sock, (struct sockaddr *)
3365+ &addr, &addr_len, 0);
3366+ if (error)
3367+ return error;
3368+ }
3369+ address.protocol = type;
3370+ address.operation = CCS_NETWORK_LISTEN;
3371+ if (family == PF_UNIX)
3372+ return ccs_check_unix_address((struct sockaddr *) &addr,
3373+ addr_len, &address);
3374+ return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
3375+ &address);
3376+}
3377+
3378+/**
3379+ * __ccs_socket_connect_permission - Check permission for setting the remote address of a socket.
3380+ *
3381+ * @sock: Pointer to "struct socket".
3382+ * @addr: Pointer to "struct sockaddr".
3383+ * @addr_len: Size of @addr.
3384+ *
3385+ * Returns 0 on success, negative value otherwise.
3386+ */
3387+static int __ccs_socket_connect_permission(struct socket *sock,
3388+ struct sockaddr *addr, int addr_len)
3389+{
3390+ struct ccs_addr_info address;
3391+ const u8 family = ccs_sock_family(sock->sk);
3392+ const unsigned int type = sock->type;
3393+ if (!family)
3394+ return 0;
3395+ address.protocol = type;
3396+ switch (type) {
3397+ case SOCK_DGRAM:
3398+ case SOCK_RAW:
3399+ address.operation = CCS_NETWORK_SEND;
3400+ break;
3401+ case SOCK_STREAM:
3402+ case SOCK_SEQPACKET:
3403+ address.operation = CCS_NETWORK_CONNECT;
3404+ break;
3405+ default:
3406+ return 0;
3407+ }
3408+ if (family == PF_UNIX)
3409+ return ccs_check_unix_address(addr, addr_len, &address);
3410+ return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
3411+ &address);
3412+}
3413+
3414+/**
3415+ * __ccs_socket_bind_permission - Check permission for setting the local address of a socket.
3416+ *
3417+ * @sock: Pointer to "struct socket".
3418+ * @addr: Pointer to "struct sockaddr".
3419+ * @addr_len: Size of @addr.
3420+ *
3421+ * Returns 0 on success, negative value otherwise.
3422+ */
3423+static int __ccs_socket_bind_permission(struct socket *sock,
3424+ struct sockaddr *addr, int addr_len)
3425+{
3426+ struct ccs_addr_info address;
3427+ const u8 family = ccs_sock_family(sock->sk);
3428+ const unsigned int type = sock->type;
3429+ if (!family)
3430+ return 0;
3431+ switch (type) {
3432+ case SOCK_STREAM:
3433+ case SOCK_DGRAM:
3434+ case SOCK_RAW:
3435+ case SOCK_SEQPACKET:
3436+ address.protocol = type;
3437+ address.operation = CCS_NETWORK_BIND;
3438+ break;
3439+ default:
3440+ return 0;
3441+ }
3442+ if (family == PF_UNIX)
3443+ return ccs_check_unix_address(addr, addr_len, &address);
3444+ return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
3445+ &address);
3446+}
3447+
3448+/**
3449+ * __ccs_socket_sendmsg_permission - Check permission for sending a datagram.
3450+ *
3451+ * @sock: Pointer to "struct socket".
3452+ * @msg: Pointer to "struct msghdr".
3453+ * @size: Unused.
3454+ *
3455+ * Returns 0 on success, negative value otherwise.
3456+ */
3457+static int __ccs_socket_sendmsg_permission(struct socket *sock,
3458+ struct msghdr *msg, int size)
3459+{
3460+ struct ccs_addr_info address;
3461+ const u8 family = ccs_sock_family(sock->sk);
3462+ const unsigned int type = sock->type;
3463+ if (!msg->msg_name || !family ||
3464+ (type != SOCK_DGRAM && type != SOCK_RAW))
3465+ return 0;
3466+ address.protocol = type;
3467+ address.operation = CCS_NETWORK_SEND;
3468+ if (family == PF_UNIX)
3469+ return ccs_check_unix_address((struct sockaddr *)
3470+ msg->msg_name, msg->msg_namelen,
3471+ &address);
3472+ return ccs_check_inet_address((struct sockaddr *) msg->msg_name,
3473+ msg->msg_namelen, sock->sk->sk_protocol,
3474+ &address);
3475+}
3476+
3477+/**
3478+ * __ccs_socket_post_accept_permission - Check permission for accepting a socket.
3479+ *
3480+ * @sock: Pointer to "struct socket".
3481+ * @newsock: Pointer to "struct socket".
3482+ *
3483+ * Returns 0 on success, negative value otherwise.
3484+ */
3485+static int __ccs_socket_post_accept_permission(struct socket *sock,
3486+ struct socket *newsock)
3487+{
3488+ struct ccs_addr_info address;
3489+ const u8 family = ccs_sock_family(sock->sk);
3490+ const unsigned int type = sock->type;
3491+ struct sockaddr_storage addr;
3492+ int addr_len;
3493+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
3494+ return 0;
3495+ {
3496+ const int error = newsock->ops->getname(newsock,
3497+ (struct sockaddr *)
3498+ &addr, &addr_len, 2);
3499+ if (error)
3500+ return error;
3501+ }
3502+ address.protocol = type;
3503+ address.operation = CCS_NETWORK_ACCEPT;
3504+ if (family == PF_UNIX)
3505+ return ccs_check_unix_address((struct sockaddr *) &addr,
3506+ addr_len, &address);
3507+ return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
3508+ &address);
3509+}
3510+
3511+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3512+
3513+/**
3514+ * __ccs_socket_post_recvmsg_permission - Check permission for receiving a datagram.
3515+ *
3516+ * @sk: Pointer to "struct sock".
3517+ * @skb: Pointer to "struct sk_buff".
3518+ * @flags: Flags passed to skb_recv_datagram().
3519+ *
3520+ * Returns 0 on success, negative value otherwise.
3521+ */
3522+static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
3523+ struct sk_buff *skb, int flags)
3524+{
3525+ struct ccs_addr_info address;
3526+ const u8 family = ccs_sock_family(sk);
3527+ const unsigned int type = sk->sk_type;
3528+ struct sockaddr_storage addr;
3529+ if (!family)
3530+ return 0;
3531+ switch (type) {
3532+ case SOCK_DGRAM:
3533+ case SOCK_RAW:
3534+ address.protocol = type;
3535+ break;
3536+ default:
3537+ return 0;
3538+ }
3539+ address.operation = CCS_NETWORK_RECV;
3540+ switch (family) {
3541+ case PF_INET6:
3542+ {
3543+ struct in6_addr *sin6 = (struct in6_addr *) &addr;
3544+ address.inet.is_ipv6 = true;
3545+ if (type == SOCK_DGRAM &&
3546+ skb->protocol == htons(ETH_P_IP))
3547+ ipv6_addr_set(sin6, 0, 0, htonl(0xffff),
3548+ ip_hdr(skb)->saddr);
3549+ else
3550+ *sin6 = ipv6_hdr(skb)->saddr;
3551+ break;
3552+ }
3553+ case PF_INET:
3554+ {
3555+ struct in_addr *sin4 = (struct in_addr *) &addr;
3556+ address.inet.is_ipv6 = false;
3557+ sin4->s_addr = ip_hdr(skb)->saddr;
3558+ break;
3559+ }
3560+ default: /* == PF_UNIX */
3561+ {
3562+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
3563+ struct unix_address *u = unix_sk(skb->sk)->addr;
3564+#else
3565+ struct unix_address *u =
3566+ skb->sk->protinfo.af_unix.addr;
3567+#endif
3568+ unsigned int addr_len;
3569+ if (u && u->len <= sizeof(addr)) {
3570+ addr_len = u->len;
3571+ memcpy(&addr, u->name, addr_len);
3572+ } else {
3573+ addr_len = 0;
3574+ addr.ss_family = AF_UNIX;
3575+ }
3576+ if (ccs_check_unix_address((struct sockaddr *) &addr,
3577+ addr_len, &address))
3578+ goto out;
3579+ return 0;
3580+ }
3581+ }
3582+ address.inet.address = (u32 *) &addr;
3583+ if (type == SOCK_DGRAM)
3584+ address.inet.port = udp_hdr(skb)->source;
3585+ else
3586+ address.inet.port = htons(sk->sk_protocol);
3587+ if (ccs_inet_entry(&address))
3588+ goto out;
3589+ return 0;
3590+out:
3591+ /*
3592+ * Remove from queue if MSG_PEEK is used so that
3593+ * the head message from unwanted source in receive queue will not
3594+ * prevent the caller from picking up next message from wanted source
3595+ * when the caller is using MSG_PEEK flag for picking up.
3596+ */
3597+ {
3598+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
3599+ bool slow = false;
3600+ if (type == SOCK_DGRAM && family != PF_UNIX)
3601+ slow = lock_sock_fast(sk);
3602+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
3603+ if (type == SOCK_DGRAM && family != PF_UNIX)
3604+ lock_sock(sk);
3605+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 2
3606+ if (type == SOCK_DGRAM && family != PF_UNIX)
3607+ lock_sock(sk);
3608+#endif
3609+ skb_kill_datagram(sk, skb, flags);
3610+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
3611+ if (type == SOCK_DGRAM && family != PF_UNIX)
3612+ unlock_sock_fast(sk, slow);
3613+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
3614+ if (type == SOCK_DGRAM && family != PF_UNIX)
3615+ release_sock(sk);
3616+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 2
3617+ if (type == SOCK_DGRAM && family != PF_UNIX)
3618+ release_sock(sk);
3619+#endif
3620+ }
3621+ return -EPERM;
3622+}
3623+
3624+#endif
3625+
3626+#endif
3627+
3628+#if defined(CONFIG_CCSECURITY_CAPABILITY) || defined(CONFIG_CCSECURITY_NETWORK)
3629+
3630+/**
3631+ * ccs_kernel_service - Check whether I'm kernel service or not.
3632+ *
3633+ * Returns true if I'm kernel service, false otherwise.
3634+ */
3635+static bool ccs_kernel_service(void)
3636+{
3637+ /* Nothing to do if I am a kernel service. */
3638+ return segment_eq(get_fs(), KERNEL_DS);
3639+}
3640+
3641+#endif
3642+
3643+#ifdef CONFIG_CCSECURITY_CAPABILITY
3644+
3645+/**
3646+ * ccs_check_capability_acl - Check permission for capability operation.
3647+ *
3648+ * @r: Pointer to "struct ccs_request_info".
3649+ * @ptr: Pointer to "struct ccs_acl_info".
3650+ *
3651+ * Returns true if granted, false otherwise.
3652+ */
3653+static bool ccs_check_capability_acl(struct ccs_request_info *r,
3654+ const struct ccs_acl_info *ptr)
3655+{
3656+ const struct ccs_capability_acl *acl =
3657+ container_of(ptr, typeof(*acl), head);
3658+ return acl->operation == r->param.capability.operation;
3659+}
3660+
3661+/**
3662+ * ccs_capable - Check permission for capability.
3663+ *
3664+ * @operation: Type of operation.
3665+ *
3666+ * Returns true on success, false otherwise.
3667+ */
3668+static bool __ccs_capable(const u8 operation)
3669+{
3670+ struct ccs_request_info r;
3671+ int error = 0;
3672+ const int idx = ccs_read_lock();
3673+ if (ccs_init_request_info(&r, ccs_c2mac[operation])
3674+ != CCS_CONFIG_DISABLED) {
3675+ r.param_type = CCS_TYPE_CAPABILITY_ACL;
3676+ r.param.capability.operation = operation;
3677+ error = ccs_check_acl(&r);
3678+ }
3679+ ccs_read_unlock(idx);
3680+ return !error;
3681+}
3682+
3683+/**
3684+ * __ccs_socket_create_permission - Check permission for creating a socket.
3685+ *
3686+ * @family: Protocol family.
3687+ * @type: Unused.
3688+ * @protocol: Unused.
3689+ *
3690+ * Returns 0 on success, negative value otherwise.
3691+ */
3692+static int __ccs_socket_create_permission(int family, int type, int protocol)
3693+{
3694+ if (ccs_kernel_service())
3695+ return 0;
3696+ if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
3697+ return -EPERM;
3698+ if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
3699+ return -EPERM;
3700+ return 0;
3701+}
3702+
3703+/**
3704+ * __ccs_ptrace_permission - Check permission for ptrace().
3705+ *
3706+ * @request: Unused.
3707+ * @pid: Unused.
3708+ *
3709+ * Returns 0 on success, negative value otherwise.
3710+ *
3711+ * Since this function is called from location where it is permitted to sleep,
3712+ * it is racy to check target process's domainname anyway. Therefore, we don't
3713+ * use target process's domainname.
3714+ */
3715+static int __ccs_ptrace_permission(long request, long pid)
3716+{
3717+ return __ccs_capable(CCS_SYS_PTRACE) ? 0 : -EPERM;
3718+}
3719+
3720+#endif
3721+
3722+#ifdef CONFIG_CCSECURITY_IPC
3723+
3724+/**
3725+ * ccs_check_signal_acl - Check permission for signal operation.
3726+ *
3727+ * @r: Pointer to "struct ccs_request_info".
3728+ * @ptr: Pointer to "struct ccs_acl_info".
3729+ *
3730+ * Returns true if granted, false otherwise.
3731+ */
3732+static bool ccs_check_signal_acl(struct ccs_request_info *r,
3733+ const struct ccs_acl_info *ptr)
3734+{
3735+ const struct ccs_signal_acl *acl =
3736+ container_of(ptr, typeof(*acl), head);
3737+ if (ccs_compare_number_union(r->param.signal.sig, &acl->sig)) {
3738+ const int len = acl->domainname->total_len;
3739+ if (!strncmp(acl->domainname->name,
3740+ r->param.signal.dest_pattern, len)) {
3741+ switch (r->param.signal.dest_pattern[len]) {
3742+ case ' ':
3743+ case '\0':
3744+ return true;
3745+ }
3746+ }
3747+ }
3748+ return false;
3749+}
3750+
3751+/**
3752+ * ccs_signal_acl2 - Check permission for signal.
3753+ *
3754+ * @sig: Signal number.
3755+ * @pid: Target's PID.
3756+ *
3757+ * Returns 0 on success, negative value otherwise.
3758+ *
3759+ * Caller holds ccs_read_lock().
3760+ */
3761+static int ccs_signal_acl2(const int sig, const int pid)
3762+{
3763+ struct ccs_request_info r;
3764+ struct ccs_domain_info *dest = NULL;
3765+ const struct ccs_domain_info * const domain = ccs_current_domain();
3766+ if (ccs_init_request_info(&r, CCS_MAC_SIGNAL) == CCS_CONFIG_DISABLED)
3767+ return 0;
3768+ if (!sig)
3769+ return 0; /* No check for NULL signal. */
3770+ r.param_type = CCS_TYPE_SIGNAL_ACL;
3771+ r.param.signal.sig = sig;
3772+ r.param.signal.dest_pattern = domain->domainname->name;
3773+ r.granted = true;
3774+ if (ccs_sys_getpid() == pid) {
3775+ ccs_audit_log(&r);
3776+ return 0; /* No check for self process. */
3777+ }
3778+ { /* Simplified checking. */
3779+ struct task_struct *p = NULL;
3780+ ccs_tasklist_lock();
3781+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3782+ if (pid > 0)
3783+ p = ccsecurity_exports.find_task_by_vpid((pid_t) pid);
3784+ else if (pid == 0)
3785+ p = current;
3786+ else if (pid == -1)
3787+ dest = &ccs_kernel_domain;
3788+ else
3789+ p = ccsecurity_exports.find_task_by_vpid((pid_t) -pid);
3790+#else
3791+ if (pid > 0)
3792+ p = find_task_by_pid((pid_t) pid);
3793+ else if (pid == 0)
3794+ p = current;
3795+ else if (pid == -1)
3796+ dest = &ccs_kernel_domain;
3797+ else
3798+ p = find_task_by_pid((pid_t) -pid);
3799+#endif
3800+ if (p)
3801+ dest = ccs_task_domain(p);
3802+ ccs_tasklist_unlock();
3803+ }
3804+ if (!dest)
3805+ return 0; /* I can't find destinatioin. */
3806+ if (domain == dest) {
3807+ ccs_audit_log(&r);
3808+ return 0; /* No check for self domain. */
3809+ }
3810+ r.param.signal.dest_pattern = dest->domainname->name;
3811+ return ccs_check_acl(&r);
3812+}
3813+
3814+/**
3815+ * ccs_signal_acl - Check permission for signal.
3816+ *
3817+ * @pid: Target's PID.
3818+ * @sig: Signal number.
3819+ *
3820+ * Returns 0 on success, negative value otherwise.
3821+ */
3822+static int ccs_signal_acl(const int pid, const int sig)
3823+{
3824+ int error;
3825+ if (!sig)
3826+ error = 0;
3827+ else {
3828+ const int idx = ccs_read_lock();
3829+ error = ccs_signal_acl2(sig, pid);
3830+ ccs_read_unlock(idx);
3831+ }
3832+ return error;
3833+}
3834+
3835+/**
3836+ * ccs_signal_acl0 - Permission check for signal().
3837+ *
3838+ * @tgid: Unused.
3839+ * @pid: Target's PID.
3840+ * @sig: Signal number.
3841+ *
3842+ * Returns 0 on success, negative value otherwise.
3843+ */
3844+static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig)
3845+{
3846+ return ccs_signal_acl(pid, sig);
3847+}
3848+
3849+#endif
3850+
3851+#ifdef CONFIG_CCSECURITY_MISC
3852+
3853+/**
3854+ * ccs_check_env_acl - Check permission for environment variable's name.
3855+ *
3856+ * @r: Pointer to "struct ccs_request_info".
3857+ * @ptr: Pointer to "struct ccs_acl_info".
3858+ *
3859+ * Returns true if granted, false otherwise.
3860+ */
3861+static bool ccs_check_env_acl(struct ccs_request_info *r,
3862+ const struct ccs_acl_info *ptr)
3863+{
3864+ const struct ccs_env_acl *acl = container_of(ptr, typeof(*acl), head);
3865+ return ccs_path_matches_pattern(r->param.environ.name, acl->env);
3866+}
3867+
3868+/**
3869+ * ccs_env_perm - Check permission for environment variable's name.
3870+ *
3871+ * @r: Pointer to "struct ccs_request_info".
3872+ * @env: The name of environment variable.
3873+ *
3874+ * Returns 0 on success, negative value otherwise.
3875+ *
3876+ * Caller holds ccs_read_lock().
3877+ */
3878+static int ccs_env_perm(struct ccs_request_info *r, const char *env)
3879+{
3880+ struct ccs_path_info environ;
3881+ if (!env || !*env)
3882+ return 0;
3883+ environ.name = env;
3884+ ccs_fill_path_info(&environ);
3885+ r->param_type = CCS_TYPE_ENV_ACL;
3886+ r->param.environ.name = &environ;
3887+ return ccs_check_acl(r);
3888+}
3889+
3890+/**
3891+ * ccs_environ - Check permission for environment variable names.
3892+ *
3893+ * @ee: Pointer to "struct ccs_execve".
3894+ *
3895+ * Returns 0 on success, negative value otherwise.
3896+ */
3897+static int ccs_environ(struct ccs_execve *ee)
3898+{
3899+ struct ccs_request_info *r = &ee->r;
3900+ struct linux_binprm *bprm = ee->bprm;
3901+ /* env_page.data is allocated by ccs_dump_page(). */
3902+ struct ccs_page_dump env_page = { };
3903+ char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
3904+ int arg_len = 0;
3905+ unsigned long pos = bprm->p;
3906+ int offset = pos % PAGE_SIZE;
3907+ int argv_count = bprm->argc;
3908+ int envp_count = bprm->envc;
3909+ /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
3910+ int error = -ENOMEM;
3911+ ee->r.type = CCS_MAC_ENVIRON;
3912+ ee->r.profile = ccs_current_domain()->profile;
3913+ ee->r.mode = ccs_get_mode(ee->r.profile, CCS_MAC_ENVIRON);
3914+ if (!r->mode || !envp_count)
3915+ return 0;
3916+ arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
3917+ if (!arg_ptr)
3918+ goto out;
3919+ while (error == -ENOMEM) {
3920+ if (!ccs_dump_page(bprm, pos, &env_page))
3921+ goto out;
3922+ pos += PAGE_SIZE - offset;
3923+ /* Read. */
3924+ while (argv_count && offset < PAGE_SIZE) {
3925+ if (!env_page.data[offset++])
3926+ argv_count--;
3927+ }
3928+ if (argv_count) {
3929+ offset = 0;
3930+ continue;
3931+ }
3932+ while (offset < PAGE_SIZE) {
3933+ const unsigned char c = env_page.data[offset++];
3934+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
3935+ if (c == '=') {
3936+ arg_ptr[arg_len++] = '\0';
3937+ } else if (c == '\\') {
3938+ arg_ptr[arg_len++] = '\\';
3939+ arg_ptr[arg_len++] = '\\';
3940+ } else if (c > ' ' && c < 127) {
3941+ arg_ptr[arg_len++] = c;
3942+ } else {
3943+ arg_ptr[arg_len++] = '\\';
3944+ arg_ptr[arg_len++] = (c >> 6) + '0';
3945+ arg_ptr[arg_len++]
3946+ = ((c >> 3) & 7) + '0';
3947+ arg_ptr[arg_len++] = (c & 7) + '0';
3948+ }
3949+ } else {
3950+ arg_ptr[arg_len] = '\0';
3951+ }
3952+ if (c)
3953+ continue;
3954+ if (ccs_env_perm(r, arg_ptr)) {
3955+ error = -EPERM;
3956+ break;
3957+ }
3958+ if (!--envp_count) {
3959+ error = 0;
3960+ break;
3961+ }
3962+ arg_len = 0;
3963+ }
3964+ offset = 0;
3965+ }
3966+out:
3967+ if (r->mode != CCS_CONFIG_ENFORCING)
3968+ error = 0;
3969+ kfree(env_page.data);
3970+ kfree(arg_ptr);
3971+ return error;
3972+}
3973+
3974+#endif
3975+
3976+/**
3977+ * ccs_argv - Check argv[] in "struct linux_binbrm".
3978+ *
3979+ * @index: Index number of @arg_ptr.
3980+ * @arg_ptr: Contents of argv[@index].
3981+ * @argc: Length of @argv.
3982+ * @argv: Pointer to "struct ccs_argv".
3983+ * @checked: Set to true if @argv[@index] was found.
3984+ *
3985+ * Returns true on success, false otherwise.
3986+ */
3987+static bool ccs_argv(const unsigned int index, const char *arg_ptr,
3988+ const int argc, const struct ccs_argv *argv,
3989+ u8 *checked)
3990+{
3991+ int i;
3992+ struct ccs_path_info arg;
3993+ arg.name = arg_ptr;
3994+ for (i = 0; i < argc; argv++, checked++, i++) {
3995+ bool result;
3996+ if (index != argv->index)
3997+ continue;
3998+ *checked = 1;
3999+ ccs_fill_path_info(&arg);
4000+ result = ccs_path_matches_pattern(&arg, argv->value);
4001+ if (argv->is_not)
4002+ result = !result;
4003+ if (!result)
4004+ return false;
4005+ }
4006+ return true;
4007+}
4008+
4009+/**
4010+ * ccs_envp - Check envp[] in "struct linux_binbrm".
4011+ *
4012+ * @env_name: The name of environment variable.
4013+ * @env_value: The value of environment variable.
4014+ * @envc: Length of @envp.
4015+ * @envp: Pointer to "struct ccs_envp".
4016+ * @checked: Set to true if @envp[@env_name] was found.
4017+ *
4018+ * Returns true on success, false otherwise.
4019+ */
4020+static bool ccs_envp(const char *env_name, const char *env_value,
4021+ const int envc, const struct ccs_envp *envp,
4022+ u8 *checked)
4023+{
4024+ int i;
4025+ struct ccs_path_info name;
4026+ struct ccs_path_info value;
4027+ name.name = env_name;
4028+ ccs_fill_path_info(&name);
4029+ value.name = env_value;
4030+ ccs_fill_path_info(&value);
4031+ for (i = 0; i < envc; envp++, checked++, i++) {
4032+ bool result;
4033+ if (!ccs_path_matches_pattern(&name, envp->name))
4034+ continue;
4035+ *checked = 1;
4036+ if (envp->value) {
4037+ result = ccs_path_matches_pattern(&value, envp->value);
4038+ if (envp->is_not)
4039+ result = !result;
4040+ } else {
4041+ result = true;
4042+ if (!envp->is_not)
4043+ result = !result;
4044+ }
4045+ if (!result)
4046+ return false;
4047+ }
4048+ return true;
4049+}
4050+
4051+/**
4052+ * ccs_scan_bprm - Scan "struct linux_binprm".
4053+ *
4054+ * @ee: Pointer to "struct ccs_execve".
4055+ * @argc: Length of @argc.
4056+ * @argv: Pointer to "struct ccs_argv".
4057+ * @envc: Length of @envp.
4058+ * @envp: Poiner to "struct ccs_envp".
4059+ *
4060+ * Returns true on success, false otherwise.
4061+ */
4062+static bool ccs_scan_bprm(struct ccs_execve *ee,
4063+ const u16 argc, const struct ccs_argv *argv,
4064+ const u16 envc, const struct ccs_envp *envp)
4065+{
4066+ struct linux_binprm *bprm = ee->bprm;
4067+ struct ccs_page_dump *dump = &ee->dump;
4068+ char *arg_ptr = ee->tmp;
4069+ int arg_len = 0;
4070+ unsigned long pos = bprm->p;
4071+ int offset = pos % PAGE_SIZE;
4072+ int argv_count = bprm->argc;
4073+ int envp_count = bprm->envc;
4074+ bool result = true;
4075+ u8 local_checked[32];
4076+ u8 *checked;
4077+ if (argc + envc <= sizeof(local_checked)) {
4078+ checked = local_checked;
4079+ memset(local_checked, 0, sizeof(local_checked));
4080+ } else {
4081+ checked = kzalloc(argc + envc, CCS_GFP_FLAGS);
4082+ if (!checked)
4083+ return false;
4084+ }
4085+ while (argv_count || envp_count) {
4086+ if (!ccs_dump_page(bprm, pos, dump)) {
4087+ result = false;
4088+ goto out;
4089+ }
4090+ pos += PAGE_SIZE - offset;
4091+ while (offset < PAGE_SIZE) {
4092+ /* Read. */
4093+ const char *kaddr = dump->data;
4094+ const unsigned char c = kaddr[offset++];
4095+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
4096+ if (c == '\\') {
4097+ arg_ptr[arg_len++] = '\\';
4098+ arg_ptr[arg_len++] = '\\';
4099+ } else if (c > ' ' && c < 127) {
4100+ arg_ptr[arg_len++] = c;
4101+ } else {
4102+ arg_ptr[arg_len++] = '\\';
4103+ arg_ptr[arg_len++] = (c >> 6) + '0';
4104+ arg_ptr[arg_len++] =
4105+ ((c >> 3) & 7) + '0';
4106+ arg_ptr[arg_len++] = (c & 7) + '0';
4107+ }
4108+ } else {
4109+ arg_ptr[arg_len] = '\0';
4110+ }
4111+ if (c)
4112+ continue;
4113+ /* Check. */
4114+ if (argv_count) {
4115+ if (!ccs_argv(bprm->argc - argv_count,
4116+ arg_ptr, argc, argv,
4117+ checked)) {
4118+ result = false;
4119+ break;
4120+ }
4121+ argv_count--;
4122+ } else if (envp_count) {
4123+ char *cp = strchr(arg_ptr, '=');
4124+ if (cp) {
4125+ *cp = '\0';
4126+ if (!ccs_envp(arg_ptr, cp + 1,
4127+ envc, envp,
4128+ checked + argc)) {
4129+ result = false;
4130+ break;
4131+ }
4132+ }
4133+ envp_count--;
4134+ } else {
4135+ break;
4136+ }
4137+ arg_len = 0;
4138+ }
4139+ offset = 0;
4140+ if (!result)
4141+ break;
4142+ }
4143+out:
4144+ if (result) {
4145+ int i;
4146+ /* Check not-yet-checked entries. */
4147+ for (i = 0; i < argc; i++) {
4148+ if (checked[i])
4149+ continue;
4150+ /*
4151+ * Return true only if all unchecked indexes in
4152+ * bprm->argv[] are not matched.
4153+ */
4154+ if (argv[i].is_not)
4155+ continue;
4156+ result = false;
4157+ break;
4158+ }
4159+ for (i = 0; i < envc; envp++, i++) {
4160+ if (checked[argc + i])
4161+ continue;
4162+ /*
4163+ * Return true only if all unchecked environ variables
4164+ * in bprm->envp[] are either undefined or not matched.
4165+ */
4166+ if ((!envp->value && !envp->is_not) ||
4167+ (envp->value && envp->is_not))
4168+ continue;
4169+ result = false;
4170+ break;
4171+ }
4172+ }
4173+ if (checked != local_checked)
4174+ kfree(checked);
4175+ return result;
4176+}
4177+
4178+/**
4179+ * ccs_scan_exec_realpath - Check "exec.realpath" parameter of "struct ccs_condition".
4180+ *
4181+ * @file: Pointer to "struct file".
4182+ * @ptr: Pointer to "struct ccs_name_union".
4183+ * @match: True if "exec.realpath=", false if "exec.realpath!=".
4184+ *
4185+ * Returns true on success, false otherwise.
4186+ */
4187+static bool ccs_scan_exec_realpath(struct file *file,
4188+ const struct ccs_name_union *ptr,
4189+ const bool match)
4190+{
4191+ bool result;
4192+ struct ccs_path_info exe;
4193+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
4194+ struct path path;
4195+#endif
4196+ if (!file)
4197+ return false;
4198+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
4199+ exe.name = ccs_realpath(&file->f_path);
4200+#else
4201+ path.mnt = file->f_vfsmnt;
4202+ path.dentry = file->f_dentry;
4203+ exe.name = ccs_realpath(&path);
4204+#endif
4205+ if (!exe.name)
4206+ return false;
4207+ ccs_fill_path_info(&exe);
4208+ result = ccs_compare_name_union(&exe, ptr);
4209+ kfree(exe.name);
4210+ return result == match;
4211+}
4212+
4213+/**
4214+ * ccs_get_attributes - Revalidate "struct inode".
4215+ *
4216+ * @obj: Pointer to "struct ccs_obj_info".
4217+ *
4218+ * Returns nothing.
4219+ */
4220+void ccs_get_attributes(struct ccs_obj_info *obj)
4221+{
4222+ u8 i;
4223+ struct dentry *dentry = NULL;
4224+
4225+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
4226+ struct inode *inode;
4227+ switch (i) {
4228+ case CCS_PATH1:
4229+ dentry = obj->path1.dentry;
4230+ if (!dentry)
4231+ continue;
4232+ break;
4233+ case CCS_PATH2:
4234+ dentry = obj->path2.dentry;
4235+ if (!dentry)
4236+ continue;
4237+ break;
4238+ default:
4239+ if (!dentry)
4240+ continue;
4241+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
4242+ spin_lock(&dcache_lock);
4243+ dentry = dget(dentry->d_parent);
4244+ spin_unlock(&dcache_lock);
4245+#else
4246+ dentry = dget_parent(dentry);
4247+#endif
4248+ break;
4249+ }
4250+ inode = dentry->d_inode;
4251+ if (inode) {
4252+ struct ccs_mini_stat *stat = &obj->stat[i];
4253+ stat->uid = inode->i_uid;
4254+ stat->gid = inode->i_gid;
4255+ stat->ino = inode->i_ino;
4256+ stat->mode = inode->i_mode;
4257+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
4258+ stat->dev = inode->i_dev;
4259+#else
4260+ stat->dev = inode->i_sb->s_dev;
4261+#endif
4262+ stat->rdev = inode->i_rdev;
4263+ obj->stat_valid[i] = true;
4264+ }
4265+ if (i & 1) /* i == CCS_PATH1_PARENT || i == CCS_PATH2_PARENT */
4266+ dput(dentry);
4267+ }
4268+}
4269+
4270+/**
4271+ * ccs_condition - Check condition part.
4272+ *
4273+ * @r: Pointer to "struct ccs_request_info".
4274+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
4275+ *
4276+ * Returns true on success, false otherwise.
4277+ *
4278+ * Caller holds ccs_read_lock().
4279+ */
4280+static bool ccs_condition(struct ccs_request_info *r,
4281+ const struct ccs_condition *cond)
4282+{
4283+ const u32 ccs_flags = ccs_current_flags();
4284+ u32 i;
4285+ unsigned long min_v[2] = { 0, 0 };
4286+ unsigned long max_v[2] = { 0, 0 };
4287+ const struct ccs_condition_element *condp;
4288+ const struct ccs_number_union *numbers_p;
4289+ const struct ccs_name_union *names_p;
4290+ const struct ccs_argv *argv;
4291+ const struct ccs_envp *envp;
4292+ struct ccs_obj_info *obj;
4293+ u16 condc;
4294+ u16 argc;
4295+ u16 envc;
4296+ struct linux_binprm *bprm = NULL;
4297+ if (!cond)
4298+ return true;
4299+ condc = cond->condc;
4300+ argc = cond->argc;
4301+ envc = cond->envc;
4302+ obj = r->obj;
4303+ if (r->ee)
4304+ bprm = r->ee->bprm;
4305+ if (!bprm && (argc || envc))
4306+ return false;
4307+ condp = (struct ccs_condition_element *) (cond + 1);
4308+ numbers_p = (const struct ccs_number_union *) (condp + condc);
4309+ names_p = (const struct ccs_name_union *)
4310+ (numbers_p + cond->numbers_count);
4311+ argv = (const struct ccs_argv *) (names_p + cond->names_count);
4312+ envp = (const struct ccs_envp *) (argv + argc);
4313+ for (i = 0; i < condc; i++) {
4314+ const bool match = condp->equals;
4315+ const u8 left = condp->left;
4316+ const u8 right = condp->right;
4317+ bool is_bitop[2] = { false, false };
4318+ u8 j;
4319+ condp++;
4320+ /* Check argv[] and envp[] later. */
4321+ if (left == CCS_ARGV_ENTRY || left == CCS_ENVP_ENTRY)
4322+ continue;
4323+ /* Check string expressions. */
4324+ if (right == CCS_NAME_UNION) {
4325+ const struct ccs_name_union *ptr = names_p++;
4326+ switch (left) {
4327+ struct ccs_path_info *symlink;
4328+ struct ccs_execve *ee;
4329+ struct file *file;
4330+ case CCS_SYMLINK_TARGET:
4331+ symlink = obj ? obj->symlink_target : NULL;
4332+ if (!symlink ||
4333+ !ccs_compare_name_union(symlink, ptr)
4334+ == match)
4335+ goto out;
4336+ break;
4337+ case CCS_EXEC_REALPATH:
4338+ ee = r->ee;
4339+ file = ee ? ee->bprm->file : NULL;
4340+ if (!ccs_scan_exec_realpath(file, ptr, match))
4341+ goto out;
4342+ break;
4343+ }
4344+ continue;
4345+ }
4346+ /* Check numeric or bit-op expressions. */
4347+ for (j = 0; j < 2; j++) {
4348+ const u8 index = j ? right : left;
4349+ unsigned long value = 0;
4350+ switch (index) {
4351+ case CCS_TASK_UID:
4352+ value = from_kuid(&init_user_ns,
4353+ current_uid());
4354+ break;
4355+ case CCS_TASK_EUID:
4356+ value = from_kuid(&init_user_ns,
4357+ current_euid());
4358+ break;
4359+ case CCS_TASK_SUID:
4360+ value = from_kuid(&init_user_ns,
4361+ current_suid());
4362+ break;
4363+ case CCS_TASK_FSUID:
4364+ value = from_kuid(&init_user_ns,
4365+ current_fsuid());
4366+ break;
4367+ case CCS_TASK_GID:
4368+ value = from_kgid(&init_user_ns,
4369+ current_gid());
4370+ break;
4371+ case CCS_TASK_EGID:
4372+ value = from_kgid(&init_user_ns,
4373+ current_egid());
4374+ break;
4375+ case CCS_TASK_SGID:
4376+ value = from_kgid(&init_user_ns,
4377+ current_sgid());
4378+ break;
4379+ case CCS_TASK_FSGID:
4380+ value = from_kgid(&init_user_ns,
4381+ current_fsgid());
4382+ break;
4383+ case CCS_TASK_PID:
4384+ value = ccs_sys_getpid();
4385+ break;
4386+ case CCS_TASK_PPID:
4387+ value = ccs_sys_getppid();
4388+ break;
4389+ case CCS_TYPE_IS_SOCKET:
4390+ value = S_IFSOCK;
4391+ break;
4392+ case CCS_TYPE_IS_SYMLINK:
4393+ value = S_IFLNK;
4394+ break;
4395+ case CCS_TYPE_IS_FILE:
4396+ value = S_IFREG;
4397+ break;
4398+ case CCS_TYPE_IS_BLOCK_DEV:
4399+ value = S_IFBLK;
4400+ break;
4401+ case CCS_TYPE_IS_DIRECTORY:
4402+ value = S_IFDIR;
4403+ break;
4404+ case CCS_TYPE_IS_CHAR_DEV:
4405+ value = S_IFCHR;
4406+ break;
4407+ case CCS_TYPE_IS_FIFO:
4408+ value = S_IFIFO;
4409+ break;
4410+ case CCS_MODE_SETUID:
4411+ value = S_ISUID;
4412+ break;
4413+ case CCS_MODE_SETGID:
4414+ value = S_ISGID;
4415+ break;
4416+ case CCS_MODE_STICKY:
4417+ value = S_ISVTX;
4418+ break;
4419+ case CCS_MODE_OWNER_READ:
4420+ value = S_IRUSR;
4421+ break;
4422+ case CCS_MODE_OWNER_WRITE:
4423+ value = S_IWUSR;
4424+ break;
4425+ case CCS_MODE_OWNER_EXECUTE:
4426+ value = S_IXUSR;
4427+ break;
4428+ case CCS_MODE_GROUP_READ:
4429+ value = S_IRGRP;
4430+ break;
4431+ case CCS_MODE_GROUP_WRITE:
4432+ value = S_IWGRP;
4433+ break;
4434+ case CCS_MODE_GROUP_EXECUTE:
4435+ value = S_IXGRP;
4436+ break;
4437+ case CCS_MODE_OTHERS_READ:
4438+ value = S_IROTH;
4439+ break;
4440+ case CCS_MODE_OTHERS_WRITE:
4441+ value = S_IWOTH;
4442+ break;
4443+ case CCS_MODE_OTHERS_EXECUTE:
4444+ value = S_IXOTH;
4445+ break;
4446+ case CCS_EXEC_ARGC:
4447+ if (!bprm)
4448+ goto out;
4449+ value = bprm->argc;
4450+ break;
4451+ case CCS_EXEC_ENVC:
4452+ if (!bprm)
4453+ goto out;
4454+ value = bprm->envc;
4455+ break;
4456+ case CCS_TASK_TYPE:
4457+ value = ((u8) ccs_flags)
4458+ & CCS_TASK_IS_EXECUTE_HANDLER;
4459+ break;
4460+ case CCS_TASK_EXECUTE_HANDLER:
4461+ value = CCS_TASK_IS_EXECUTE_HANDLER;
4462+ break;
4463+ case CCS_NUMBER_UNION:
4464+ /* Fetch values later. */
4465+ break;
4466+ default:
4467+ if (!obj)
4468+ goto out;
4469+ if (!obj->validate_done) {
4470+ ccs_get_attributes(obj);
4471+ obj->validate_done = true;
4472+ }
4473+ {
4474+ u8 stat_index;
4475+ struct ccs_mini_stat *stat;
4476+ switch (index) {
4477+ case CCS_PATH1_UID:
4478+ case CCS_PATH1_GID:
4479+ case CCS_PATH1_INO:
4480+ case CCS_PATH1_MAJOR:
4481+ case CCS_PATH1_MINOR:
4482+ case CCS_PATH1_TYPE:
4483+ case CCS_PATH1_DEV_MAJOR:
4484+ case CCS_PATH1_DEV_MINOR:
4485+ case CCS_PATH1_PERM:
4486+ stat_index = CCS_PATH1;
4487+ break;
4488+ case CCS_PATH2_UID:
4489+ case CCS_PATH2_GID:
4490+ case CCS_PATH2_INO:
4491+ case CCS_PATH2_MAJOR:
4492+ case CCS_PATH2_MINOR:
4493+ case CCS_PATH2_TYPE:
4494+ case CCS_PATH2_DEV_MAJOR:
4495+ case CCS_PATH2_DEV_MINOR:
4496+ case CCS_PATH2_PERM:
4497+ stat_index = CCS_PATH2;
4498+ break;
4499+ case CCS_PATH1_PARENT_UID:
4500+ case CCS_PATH1_PARENT_GID:
4501+ case CCS_PATH1_PARENT_INO:
4502+ case CCS_PATH1_PARENT_PERM:
4503+ stat_index = CCS_PATH1_PARENT;
4504+ break;
4505+ case CCS_PATH2_PARENT_UID:
4506+ case CCS_PATH2_PARENT_GID:
4507+ case CCS_PATH2_PARENT_INO:
4508+ case CCS_PATH2_PARENT_PERM:
4509+ stat_index = CCS_PATH2_PARENT;
4510+ break;
4511+ default:
4512+ goto out;
4513+ }
4514+ if (!obj->stat_valid[stat_index])
4515+ goto out;
4516+ stat = &obj->stat[stat_index];
4517+ switch (index) {
4518+ case CCS_PATH1_UID:
4519+ case CCS_PATH2_UID:
4520+ case CCS_PATH1_PARENT_UID:
4521+ case CCS_PATH2_PARENT_UID:
4522+ value = from_kuid
4523+ (&init_user_ns,
4524+ stat->uid);
4525+ break;
4526+ case CCS_PATH1_GID:
4527+ case CCS_PATH2_GID:
4528+ case CCS_PATH1_PARENT_GID:
4529+ case CCS_PATH2_PARENT_GID:
4530+ value = from_kgid
4531+ (&init_user_ns,
4532+ stat->gid);
4533+ break;
4534+ case CCS_PATH1_INO:
4535+ case CCS_PATH2_INO:
4536+ case CCS_PATH1_PARENT_INO:
4537+ case CCS_PATH2_PARENT_INO:
4538+ value = stat->ino;
4539+ break;
4540+ case CCS_PATH1_MAJOR:
4541+ case CCS_PATH2_MAJOR:
4542+ value = MAJOR(stat->dev);
4543+ break;
4544+ case CCS_PATH1_MINOR:
4545+ case CCS_PATH2_MINOR:
4546+ value = MINOR(stat->dev);
4547+ break;
4548+ case CCS_PATH1_TYPE:
4549+ case CCS_PATH2_TYPE:
4550+ value = stat->mode & S_IFMT;
4551+ break;
4552+ case CCS_PATH1_DEV_MAJOR:
4553+ case CCS_PATH2_DEV_MAJOR:
4554+ value = MAJOR(stat->rdev);
4555+ break;
4556+ case CCS_PATH1_DEV_MINOR:
4557+ case CCS_PATH2_DEV_MINOR:
4558+ value = MINOR(stat->rdev);
4559+ break;
4560+ case CCS_PATH1_PERM:
4561+ case CCS_PATH2_PERM:
4562+ case CCS_PATH1_PARENT_PERM:
4563+ case CCS_PATH2_PARENT_PERM:
4564+ value = stat->mode & S_IALLUGO;
4565+ break;
4566+ }
4567+ }
4568+ break;
4569+ }
4570+ max_v[j] = value;
4571+ min_v[j] = value;
4572+ switch (index) {
4573+ case CCS_MODE_SETUID:
4574+ case CCS_MODE_SETGID:
4575+ case CCS_MODE_STICKY:
4576+ case CCS_MODE_OWNER_READ:
4577+ case CCS_MODE_OWNER_WRITE:
4578+ case CCS_MODE_OWNER_EXECUTE:
4579+ case CCS_MODE_GROUP_READ:
4580+ case CCS_MODE_GROUP_WRITE:
4581+ case CCS_MODE_GROUP_EXECUTE:
4582+ case CCS_MODE_OTHERS_READ:
4583+ case CCS_MODE_OTHERS_WRITE:
4584+ case CCS_MODE_OTHERS_EXECUTE:
4585+ is_bitop[j] = true;
4586+ }
4587+ }
4588+ if (left == CCS_NUMBER_UNION) {
4589+ /* Fetch values now. */
4590+ const struct ccs_number_union *ptr = numbers_p++;
4591+ min_v[0] = ptr->values[0];
4592+ max_v[0] = ptr->values[1];
4593+ }
4594+ if (right == CCS_NUMBER_UNION) {
4595+ /* Fetch values now. */
4596+ const struct ccs_number_union *ptr = numbers_p++;
4597+ if (ptr->group) {
4598+ if (ccs_number_matches_group(min_v[0],
4599+ max_v[0],
4600+ ptr->group)
4601+ == match)
4602+ continue;
4603+ } else {
4604+ if ((min_v[0] <= ptr->values[1] &&
4605+ max_v[0] >= ptr->values[0]) == match)
4606+ continue;
4607+ }
4608+ goto out;
4609+ }
4610+ /*
4611+ * Bit operation is valid only when counterpart value
4612+ * represents permission.
4613+ */
4614+ if (is_bitop[0] && is_bitop[1]) {
4615+ goto out;
4616+ } else if (is_bitop[0]) {
4617+ switch (right) {
4618+ case CCS_PATH1_PERM:
4619+ case CCS_PATH1_PARENT_PERM:
4620+ case CCS_PATH2_PERM:
4621+ case CCS_PATH2_PARENT_PERM:
4622+ if (!(max_v[0] & max_v[1]) == !match)
4623+ continue;
4624+ }
4625+ goto out;
4626+ } else if (is_bitop[1]) {
4627+ switch (left) {
4628+ case CCS_PATH1_PERM:
4629+ case CCS_PATH1_PARENT_PERM:
4630+ case CCS_PATH2_PERM:
4631+ case CCS_PATH2_PARENT_PERM:
4632+ if (!(max_v[0] & max_v[1]) == !match)
4633+ continue;
4634+ }
4635+ goto out;
4636+ }
4637+ /* Normal value range comparison. */
4638+ if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
4639+ continue;
4640+out:
4641+ return false;
4642+ }
4643+ /* Check argv[] and envp[] now. */
4644+ if (r->ee && (argc || envc))
4645+ return ccs_scan_bprm(r->ee, argc, argv, envc, envp);
4646+ return true;
4647+}
4648+
4649+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4650+
4651+/**
4652+ * ccs_check_task_acl - Check permission for task operation.
4653+ *
4654+ * @r: Pointer to "struct ccs_request_info".
4655+ * @ptr: Pointer to "struct ccs_acl_info".
4656+ *
4657+ * Returns true if granted, false otherwise.
4658+ */
4659+static bool ccs_check_task_acl(struct ccs_request_info *r,
4660+ const struct ccs_acl_info *ptr)
4661+{
4662+ const struct ccs_task_acl *acl = container_of(ptr, typeof(*acl), head);
4663+ return !ccs_pathcmp(r->param.task.domainname, acl->domainname);
4664+}
4665+
4666+#endif
4667+
4668+/**
4669+ * ccs_init_request_info - Initialize "struct ccs_request_info" members.
4670+ *
4671+ * @r: Pointer to "struct ccs_request_info" to initialize.
4672+ * @index: Index number of functionality.
4673+ *
4674+ * Returns mode.
4675+ *
4676+ * "task auto_domain_transition" keyword is evaluated before returning mode for
4677+ * @index. If "task auto_domain_transition" keyword was specified and
4678+ * transition to that domain failed, the current thread will be killed by
4679+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
4680+ */
4681+int ccs_init_request_info(struct ccs_request_info *r, const u8 index)
4682+{
4683+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4684+ u8 i;
4685+ const char *buf;
4686+ for (i = 0; i < 255; i++) {
4687+ const u8 profile = ccs_current_domain()->profile;
4688+ memset(r, 0, sizeof(*r));
4689+ r->profile = profile;
4690+ r->type = index;
4691+ r->mode = ccs_get_mode(profile, index);
4692+ r->param_type = CCS_TYPE_AUTO_TASK_ACL;
4693+ ccs_check_acl(r);
4694+ if (!r->granted)
4695+ return r->mode;
4696+ buf = container_of(r->matched_acl, typeof(struct ccs_task_acl),
4697+ head)->domainname->name;
4698+ if (!ccs_assign_domain(buf, true))
4699+ break;
4700+ }
4701+ ccs_transition_failed(buf);
4702+ return CCS_CONFIG_DISABLED;
4703+#else
4704+ const u8 profile = ccs_current_domain()->profile;
4705+ memset(r, 0, sizeof(*r));
4706+ r->profile = profile;
4707+ r->type = index;
4708+ r->mode = ccs_get_mode(profile, index);
4709+ return r->mode;
4710+#endif
4711+}
4712+
4713+/**
4714+ * ccs_byte_range - Check whether the string is a \ooo style octal value.
4715+ *
4716+ * @str: Pointer to the string.
4717+ *
4718+ * Returns true if @str is a \ooo style octal value, false otherwise.
4719+ */
4720+static bool ccs_byte_range(const char *str)
4721+{
4722+ return *str >= '0' && *str++ <= '3' &&
4723+ *str >= '0' && *str++ <= '7' &&
4724+ *str >= '0' && *str <= '7';
4725+}
4726+
4727+/**
4728+ * ccs_decimal - Check whether the character is a decimal character.
4729+ *
4730+ * @c: The character to check.
4731+ *
4732+ * Returns true if @c is a decimal character, false otherwise.
4733+ */
4734+static bool ccs_decimal(const char c)
4735+{
4736+ return c >= '0' && c <= '9';
4737+}
4738+
4739+/**
4740+ * ccs_hexadecimal - Check whether the character is a hexadecimal character.
4741+ *
4742+ * @c: The character to check.
4743+ *
4744+ * Returns true if @c is a hexadecimal character, false otherwise.
4745+ */
4746+static bool ccs_hexadecimal(const char c)
4747+{
4748+ return (c >= '0' && c <= '9') ||
4749+ (c >= 'A' && c <= 'F') ||
4750+ (c >= 'a' && c <= 'f');
4751+}
4752+
4753+/**
4754+ * ccs_alphabet_char - Check whether the character is an alphabet.
4755+ *
4756+ * @c: The character to check.
4757+ *
4758+ * Returns true if @c is an alphabet character, false otherwise.
4759+ */
4760+static bool ccs_alphabet_char(const char c)
4761+{
4762+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
4763+}
4764+
4765+/**
4766+ * ccs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
4767+ *
4768+ * @filename: The start of string to check.
4769+ * @filename_end: The end of string to check.
4770+ * @pattern: The start of pattern to compare.
4771+ * @pattern_end: The end of pattern to compare.
4772+ *
4773+ * Returns true if @filename matches @pattern, false otherwise.
4774+ */
4775+static bool ccs_file_matches_pattern2(const char *filename,
4776+ const char *filename_end,
4777+ const char *pattern,
4778+ const char *pattern_end)
4779+{
4780+ while (filename < filename_end && pattern < pattern_end) {
4781+ char c;
4782+ if (*pattern != '\\') {
4783+ if (*filename++ != *pattern++)
4784+ return false;
4785+ continue;
4786+ }
4787+ c = *filename;
4788+ pattern++;
4789+ switch (*pattern) {
4790+ int i;
4791+ int j;
4792+ case '?':
4793+ if (c == '/') {
4794+ return false;
4795+ } else if (c == '\\') {
4796+ if (filename[1] == '\\')
4797+ filename++;
4798+ else if (ccs_byte_range(filename + 1))
4799+ filename += 3;
4800+ else
4801+ return false;
4802+ }
4803+ break;
4804+ case '\\':
4805+ if (c != '\\')
4806+ return false;
4807+ if (*++filename != '\\')
4808+ return false;
4809+ break;
4810+ case '+':
4811+ if (!ccs_decimal(c))
4812+ return false;
4813+ break;
4814+ case 'x':
4815+ if (!ccs_hexadecimal(c))
4816+ return false;
4817+ break;
4818+ case 'a':
4819+ if (!ccs_alphabet_char(c))
4820+ return false;
4821+ break;
4822+ case '0':
4823+ case '1':
4824+ case '2':
4825+ case '3':
4826+ if (c == '\\' && ccs_byte_range(filename + 1)
4827+ && !strncmp(filename + 1, pattern, 3)) {
4828+ filename += 3;
4829+ pattern += 2;
4830+ break;
4831+ }
4832+ return false; /* Not matched. */
4833+ case '*':
4834+ case '@':
4835+ for (i = 0; i <= filename_end - filename; i++) {
4836+ if (ccs_file_matches_pattern2(filename + i,
4837+ filename_end,
4838+ pattern + 1,
4839+ pattern_end))
4840+ return true;
4841+ c = filename[i];
4842+ if (c == '.' && *pattern == '@')
4843+ break;
4844+ if (c != '\\')
4845+ continue;
4846+ if (filename[i + 1] == '\\')
4847+ i++;
4848+ else if (ccs_byte_range(filename + i + 1))
4849+ i += 3;
4850+ else
4851+ break; /* Bad pattern. */
4852+ }
4853+ return false; /* Not matched. */
4854+ default:
4855+ j = 0;
4856+ c = *pattern;
4857+ if (c == '$') {
4858+ while (ccs_decimal(filename[j]))
4859+ j++;
4860+ } else if (c == 'X') {
4861+ while (ccs_hexadecimal(filename[j]))
4862+ j++;
4863+ } else if (c == 'A') {
4864+ while (ccs_alphabet_char(filename[j]))
4865+ j++;
4866+ }
4867+ for (i = 1; i <= j; i++) {
4868+ if (ccs_file_matches_pattern2(filename + i,
4869+ filename_end,
4870+ pattern + 1,
4871+ pattern_end))
4872+ return true;
4873+ }
4874+ return false; /* Not matched or bad pattern. */
4875+ }
4876+ filename++;
4877+ pattern++;
4878+ }
4879+ while (*pattern == '\\' &&
4880+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
4881+ pattern += 2;
4882+ return filename == filename_end && pattern == pattern_end;
4883+}
4884+
4885+/**
4886+ * ccs_file_matches_pattern - Pattern matching without '/' character.
4887+ *
4888+ * @filename: The start of string to check.
4889+ * @filename_end: The end of string to check.
4890+ * @pattern: The start of pattern to compare.
4891+ * @pattern_end: The end of pattern to compare.
4892+ *
4893+ * Returns true if @filename matches @pattern, false otherwise.
4894+ */
4895+static bool ccs_file_matches_pattern(const char *filename,
4896+ const char *filename_end,
4897+ const char *pattern,
4898+ const char *pattern_end)
4899+{
4900+ const char *pattern_start = pattern;
4901+ bool first = true;
4902+ bool result;
4903+ while (pattern < pattern_end - 1) {
4904+ /* Split at "\-" pattern. */
4905+ if (*pattern++ != '\\' || *pattern++ != '-')
4906+ continue;
4907+ result = ccs_file_matches_pattern2(filename, filename_end,
4908+ pattern_start, pattern - 2);
4909+ if (first)
4910+ result = !result;
4911+ if (result)
4912+ return false;
4913+ first = false;
4914+ pattern_start = pattern;
4915+ }
4916+ result = ccs_file_matches_pattern2(filename, filename_end,
4917+ pattern_start, pattern_end);
4918+ return first ? result : !result;
4919+}
4920+
4921+/**
4922+ * ccs_path_matches_pattern2 - Do pathname pattern matching.
4923+ *
4924+ * @f: The start of string to check.
4925+ * @p: The start of pattern to compare.
4926+ *
4927+ * Returns true if @f matches @p, false otherwise.
4928+ */
4929+static bool ccs_path_matches_pattern2(const char *f, const char *p)
4930+{
4931+ const char *f_delimiter;
4932+ const char *p_delimiter;
4933+ while (*f && *p) {
4934+ f_delimiter = strchr(f, '/');
4935+ if (!f_delimiter)
4936+ f_delimiter = f + strlen(f);
4937+ p_delimiter = strchr(p, '/');
4938+ if (!p_delimiter)
4939+ p_delimiter = p + strlen(p);
4940+ if (*p == '\\' && *(p + 1) == '{')
4941+ goto recursive;
4942+ if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
4943+ return false;
4944+ f = f_delimiter;
4945+ if (*f)
4946+ f++;
4947+ p = p_delimiter;
4948+ if (*p)
4949+ p++;
4950+ }
4951+ /* Ignore trailing "\*" and "\@" in @pattern. */
4952+ while (*p == '\\' &&
4953+ (*(p + 1) == '*' || *(p + 1) == '@'))
4954+ p += 2;
4955+ return !*f && !*p;
4956+recursive:
4957+ /*
4958+ * The "\{" pattern is permitted only after '/' character.
4959+ * This guarantees that below "*(p - 1)" is safe.
4960+ * Also, the "\}" pattern is permitted only before '/' character
4961+ * so that "\{" + "\}" pair will not break the "\-" operator.
4962+ */
4963+ if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
4964+ *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
4965+ return false; /* Bad pattern. */
4966+ do {
4967+ /* Compare current component with pattern. */
4968+ if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
4969+ p_delimiter - 2))
4970+ break;
4971+ /* Proceed to next component. */
4972+ f = f_delimiter;
4973+ if (!*f)
4974+ break;
4975+ f++;
4976+ /* Continue comparison. */
4977+ if (ccs_path_matches_pattern2(f, p_delimiter + 1))
4978+ return true;
4979+ f_delimiter = strchr(f, '/');
4980+ } while (f_delimiter);
4981+ return false; /* Not matched. */
4982+}
4983+
4984+/**
4985+ * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
4986+ *
4987+ * @filename: The filename to check.
4988+ * @pattern: The pattern to compare.
4989+ *
4990+ * Returns true if matches, false otherwise.
4991+ *
4992+ * The following patterns are available.
4993+ * \\ \ itself.
4994+ * \ooo Octal representation of a byte.
4995+ * \* Zero or more repetitions of characters other than '/'.
4996+ * \@ Zero or more repetitions of characters other than '/' or '.'.
4997+ * \? 1 byte character other than '/'.
4998+ * \$ One or more repetitions of decimal digits.
4999+ * \+ 1 decimal digit.
5000+ * \X One or more repetitions of hexadecimal digits.
5001+ * \x 1 hexadecimal digit.
5002+ * \A One or more repetitions of alphabet characters.
5003+ * \a 1 alphabet character.
5004+ *
5005+ * \- Subtraction operator.
5006+ *
5007+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
5008+ * /dir/dir/dir/ ).
5009+ */
5010+static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
5011+ const struct ccs_path_info *pattern)
5012+{
5013+ const char *f = filename->name;
5014+ const char *p = pattern->name;
5015+ const int len = pattern->const_len;
5016+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
5017+ if (!pattern->is_patterned)
5018+ return !ccs_pathcmp(filename, pattern);
5019+ /* Don't compare directory and non-directory. */
5020+ if (filename->is_dir != pattern->is_dir)
5021+ return false;
5022+ /* Compare the initial length without patterns. */
5023+ if (strncmp(f, p, len))
5024+ return false;
5025+ f += len;
5026+ p += len;
5027+ return ccs_path_matches_pattern2(f, p);
5028+}
--- tags/patches/1.0.33/gc.c (nonexistent)
+++ tags/patches/1.0.33/gc.c (revision 502)
@@ -0,0 +1,1037 @@
1+/*
2+ * security/ccsecurity/gc.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2015/04/21
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+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
26+
27+/*
28+ * Lock for syscall users.
29+ *
30+ * This lock is used for protecting single SRCU section for 2.6.18 and
31+ * earlier kernels because they don't have SRCU support.
32+ */
33+struct ccs_lock_struct {
34+ int counter_idx; /* Currently active index (0 or 1). */
35+ int counter[2]; /* Current users. Protected by ccs_counter_lock. */
36+};
37+
38+#endif
39+
40+/***** SECTION3: Prototype definition section *****/
41+
42+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
43+int ccs_lock(void);
44+#endif
45+void ccs_del_acl(struct list_head *element);
46+void ccs_del_condition(struct list_head *element);
47+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
48+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
49+void ccs_unlock(const int idx);
50+#endif
51+
52+static bool ccs_domain_used_by_task(struct ccs_domain_info *domain);
53+static bool ccs_name_used_by_io_buffer(const char *string, const size_t size);
54+static bool ccs_struct_used_by_io_buffer(const struct list_head *element);
55+static int ccs_gc_thread(void *unused);
56+static void ccs_collect_acl(struct list_head *list);
57+static void ccs_collect_entry(void);
58+static void ccs_collect_member(const enum ccs_policy_id id,
59+ struct list_head *member_list);
60+static void ccs_memory_free(const void *ptr, const enum ccs_policy_id type);
61+static void ccs_put_name_union(struct ccs_name_union *ptr);
62+static void ccs_put_number_union(struct ccs_number_union *ptr);
63+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
64+static void ccs_synchronize_counter(void);
65+#endif
66+static void ccs_try_to_gc(const enum ccs_policy_id type,
67+ struct list_head *element);
68+
69+/***** SECTION4: Standalone functions section *****/
70+
71+/***** SECTION5: Variables definition section *****/
72+
73+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
74+
75+/*
76+ * Lock for syscall users.
77+ *
78+ * This lock is held for only protecting single SRCU section.
79+ */
80+struct srcu_struct ccs_ss;
81+
82+#else
83+
84+static struct ccs_lock_struct ccs_counter;
85+/* Lock for protecting ccs_counter. */
86+static DEFINE_SPINLOCK(ccs_counter_lock);
87+
88+#endif
89+
90+/***** SECTION6: Dependent functions section *****/
91+
92+/**
93+ * ccs_memory_free - Free memory for elements.
94+ *
95+ * @ptr: Pointer to allocated memory.
96+ * @type: One of values in "enum ccs_policy_id".
97+ *
98+ * Returns nothing.
99+ *
100+ * Caller holds ccs_policy_lock mutex.
101+ */
102+static void ccs_memory_free(const void *ptr, const enum ccs_policy_id type)
103+{
104+ /* Size of an element. */
105+ static const u8 e[CCS_MAX_POLICY] = {
106+#ifdef CONFIG_CCSECURITY_PORTRESERVE
107+ [CCS_ID_RESERVEDPORT] = sizeof(struct ccs_reserved),
108+#endif
109+ [CCS_ID_GROUP] = sizeof(struct ccs_group),
110+#ifdef CONFIG_CCSECURITY_NETWORK
111+ [CCS_ID_ADDRESS_GROUP] = sizeof(struct ccs_address_group),
112+#endif
113+ [CCS_ID_PATH_GROUP] = sizeof(struct ccs_path_group),
114+ [CCS_ID_NUMBER_GROUP] = sizeof(struct ccs_number_group),
115+ [CCS_ID_AGGREGATOR] = sizeof(struct ccs_aggregator),
116+ [CCS_ID_TRANSITION_CONTROL]
117+ = sizeof(struct ccs_transition_control),
118+ [CCS_ID_MANAGER] = sizeof(struct ccs_manager),
119+ /* [CCS_ID_CONDITION] = "struct ccs_condition"->size, */
120+ /* [CCS_ID_NAME] = "struct ccs_name"->size, */
121+ /* [CCS_ID_ACL] = a["struct ccs_acl_info"->type], */
122+ [CCS_ID_DOMAIN] = sizeof(struct ccs_domain_info),
123+ };
124+ /* Size of a domain ACL element. */
125+ static const u8 a[] = {
126+ [CCS_TYPE_PATH_ACL] = sizeof(struct ccs_path_acl),
127+ [CCS_TYPE_PATH2_ACL] = sizeof(struct ccs_path2_acl),
128+ [CCS_TYPE_PATH_NUMBER_ACL]
129+ = sizeof(struct ccs_path_number_acl),
130+ [CCS_TYPE_MKDEV_ACL] = sizeof(struct ccs_mkdev_acl),
131+ [CCS_TYPE_MOUNT_ACL] = sizeof(struct ccs_mount_acl),
132+#ifdef CONFIG_CCSECURITY_NETWORK
133+ [CCS_TYPE_INET_ACL] = sizeof(struct ccs_inet_acl),
134+ [CCS_TYPE_UNIX_ACL] = sizeof(struct ccs_unix_acl),
135+#endif
136+#ifdef CONFIG_CCSECURITY_MISC
137+ [CCS_TYPE_ENV_ACL] = sizeof(struct ccs_env_acl),
138+#endif
139+#ifdef CONFIG_CCSECURITY_CAPABILITY
140+ [CCS_TYPE_CAPABILITY_ACL] = sizeof(struct ccs_capability_acl),
141+#endif
142+#ifdef CONFIG_CCSECURITY_IPC
143+ [CCS_TYPE_SIGNAL_ACL] = sizeof(struct ccs_signal_acl),
144+#endif
145+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
146+ [CCS_TYPE_AUTO_EXECUTE_HANDLER]
147+ = sizeof(struct ccs_handler_acl),
148+ [CCS_TYPE_DENIED_EXECUTE_HANDLER]
149+ = sizeof(struct ccs_handler_acl),
150+#endif
151+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
152+ [CCS_TYPE_AUTO_TASK_ACL] = sizeof(struct ccs_task_acl),
153+ [CCS_TYPE_MANUAL_TASK_ACL] = sizeof(struct ccs_task_acl),
154+#endif
155+ };
156+ size_t size;
157+ if (type == CCS_ID_ACL)
158+ size = a[container_of(ptr, typeof(struct ccs_acl_info),
159+ list)->type];
160+ else if (type == CCS_ID_NAME)
161+ size = container_of(ptr, typeof(struct ccs_name),
162+ head.list)->size;
163+ else if (type == CCS_ID_CONDITION)
164+ size = container_of(ptr, typeof(struct ccs_condition),
165+ head.list)->size;
166+ else
167+ size = e[type];
168+ ccs_memory_used[CCS_MEMORY_POLICY] -= ccs_round2(size);
169+ kfree(ptr);
170+}
171+
172+/**
173+ * ccs_put_name_union - Drop reference on "struct ccs_name_union".
174+ *
175+ * @ptr: Pointer to "struct ccs_name_union".
176+ *
177+ * Returns nothing.
178+ */
179+static void ccs_put_name_union(struct ccs_name_union *ptr)
180+{
181+ ccs_put_group(ptr->group);
182+ ccs_put_name(ptr->filename);
183+}
184+
185+/**
186+ * ccs_put_number_union - Drop reference on "struct ccs_number_union".
187+ *
188+ * @ptr: Pointer to "struct ccs_number_union".
189+ *
190+ * Returns nothing.
191+ */
192+static void ccs_put_number_union(struct ccs_number_union *ptr)
193+{
194+ ccs_put_group(ptr->group);
195+}
196+
197+/**
198+ * ccs_struct_used_by_io_buffer - Check whether the list element is used by /proc/ccs/ users or not.
199+ *
200+ * @element: Pointer to "struct list_head".
201+ *
202+ * Returns true if @element is used by /proc/ccs/ users, false otherwise.
203+ */
204+static bool ccs_struct_used_by_io_buffer(const struct list_head *element)
205+{
206+ struct ccs_io_buffer *head;
207+ bool in_use = false;
208+ spin_lock(&ccs_io_buffer_list_lock);
209+ list_for_each_entry(head, &ccs_io_buffer_list, list) {
210+ head->users++;
211+ spin_unlock(&ccs_io_buffer_list_lock);
212+ mutex_lock(&head->io_sem);
213+ if (head->r.domain == element || head->r.group == element ||
214+ head->r.acl == element || &head->w.domain->list == element)
215+ in_use = true;
216+ mutex_unlock(&head->io_sem);
217+ spin_lock(&ccs_io_buffer_list_lock);
218+ head->users--;
219+ if (in_use)
220+ break;
221+ }
222+ spin_unlock(&ccs_io_buffer_list_lock);
223+ return in_use;
224+}
225+
226+/**
227+ * ccs_name_used_by_io_buffer - Check whether the string is used by /proc/ccs/ users or not.
228+ *
229+ * @string: String to check.
230+ * @size: Memory allocated for @string .
231+ *
232+ * Returns true if @string is used by /proc/ccs/ users, false otherwise.
233+ */
234+static bool ccs_name_used_by_io_buffer(const char *string, const size_t size)
235+{
236+ struct ccs_io_buffer *head;
237+ bool in_use = false;
238+ spin_lock(&ccs_io_buffer_list_lock);
239+ list_for_each_entry(head, &ccs_io_buffer_list, list) {
240+ int i;
241+ head->users++;
242+ spin_unlock(&ccs_io_buffer_list_lock);
243+ mutex_lock(&head->io_sem);
244+ for (i = 0; i < CCS_MAX_IO_READ_QUEUE; i++) {
245+ const char *w = head->r.w[i];
246+ if (w < string || w > string + size)
247+ continue;
248+ in_use = true;
249+ break;
250+ }
251+ mutex_unlock(&head->io_sem);
252+ spin_lock(&ccs_io_buffer_list_lock);
253+ head->users--;
254+ if (in_use)
255+ break;
256+ }
257+ spin_unlock(&ccs_io_buffer_list_lock);
258+ return in_use;
259+}
260+
261+/**
262+ * ccs_del_transition_control - Delete members in "struct ccs_transition_control".
263+ *
264+ * @element: Pointer to "struct list_head".
265+ *
266+ * Returns nothing.
267+ */
268+static inline void ccs_del_transition_control(struct list_head *element)
269+{
270+ struct ccs_transition_control *ptr =
271+ container_of(element, typeof(*ptr), head.list);
272+ ccs_put_name(ptr->domainname);
273+ ccs_put_name(ptr->program);
274+}
275+
276+/**
277+ * ccs_del_aggregator - Delete members in "struct ccs_aggregator".
278+ *
279+ * @element: Pointer to "struct list_head".
280+ *
281+ * Returns nothing.
282+ */
283+static inline void ccs_del_aggregator(struct list_head *element)
284+{
285+ struct ccs_aggregator *ptr =
286+ container_of(element, typeof(*ptr), head.list);
287+ ccs_put_name(ptr->original_name);
288+ ccs_put_name(ptr->aggregated_name);
289+}
290+
291+/**
292+ * ccs_del_manager - Delete members in "struct ccs_manager".
293+ *
294+ * @element: Pointer to "struct list_head".
295+ *
296+ * Returns nothing.
297+ */
298+static inline void ccs_del_manager(struct list_head *element)
299+{
300+ struct ccs_manager *ptr =
301+ container_of(element, typeof(*ptr), head.list);
302+ ccs_put_name(ptr->manager);
303+}
304+
305+/**
306+ * ccs_domain_used_by_task - Check whether the given pointer is referenced by a task.
307+ *
308+ * @domain: Pointer to "struct ccs_domain_info".
309+ *
310+ * Returns true if @domain is in use, false otherwise.
311+ */
312+static bool ccs_domain_used_by_task(struct ccs_domain_info *domain)
313+{
314+ bool in_use = false;
315+ /*
316+ * Don't delete this domain if somebody is doing execve().
317+ *
318+ * Since ccs_finish_execve() first reverts ccs_domain_info and then
319+ * updates ccs_flags, we need smp_rmb() to make sure that GC first
320+ * checks ccs_flags and then checks ccs_domain_info.
321+ */
322+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
323+ int idx;
324+ rcu_read_lock();
325+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
326+ struct ccs_security *ptr;
327+ struct list_head *list = &ccs_task_security_list[idx];
328+ list_for_each_entry_rcu(ptr, list, list) {
329+ if (!(ptr->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
330+ smp_rmb(); /* Avoid out of order execution. */
331+ if (ptr->ccs_domain_info != domain)
332+ continue;
333+ }
334+ in_use = true;
335+ goto out;
336+ }
337+ }
338+ in_use = ccs_used_by_cred(domain);
339+out:
340+ rcu_read_unlock();
341+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
342+ struct task_struct *g;
343+ struct task_struct *t;
344+ ccs_tasklist_lock();
345+ do_each_thread(g, t) {
346+ if (!(t->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
347+ smp_rmb(); /* Avoid out of order execution. */
348+ if (t->ccs_domain_info != domain)
349+ continue;
350+ }
351+ in_use = true;
352+ goto out;
353+ } while_each_thread(g, t);
354+out:
355+ ccs_tasklist_unlock();
356+#else
357+ struct task_struct *p;
358+ ccs_tasklist_lock();
359+ for_each_process(p) {
360+ if (!(p->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
361+ smp_rmb(); /* Avoid out of order execution. */
362+ if (p->ccs_domain_info != domain)
363+ continue;
364+ }
365+ in_use = true;
366+ break;
367+ }
368+ ccs_tasklist_unlock();
369+#endif
370+ return in_use;
371+}
372+
373+/**
374+ * ccs_del_acl - Delete members in "struct ccs_acl_info".
375+ *
376+ * @element: Pointer to "struct list_head".
377+ *
378+ * Returns nothing.
379+ */
380+void ccs_del_acl(struct list_head *element)
381+{
382+ struct ccs_acl_info *acl = container_of(element, typeof(*acl), list);
383+ ccs_put_condition(acl->cond);
384+ switch (acl->type) {
385+ case CCS_TYPE_PATH_ACL:
386+ {
387+ struct ccs_path_acl *entry =
388+ container_of(acl, typeof(*entry), head);
389+ ccs_put_name_union(&entry->name);
390+ }
391+ break;
392+ case CCS_TYPE_PATH2_ACL:
393+ {
394+ struct ccs_path2_acl *entry =
395+ container_of(acl, typeof(*entry), head);
396+ ccs_put_name_union(&entry->name1);
397+ ccs_put_name_union(&entry->name2);
398+ }
399+ break;
400+ case CCS_TYPE_PATH_NUMBER_ACL:
401+ {
402+ struct ccs_path_number_acl *entry =
403+ container_of(acl, typeof(*entry), head);
404+ ccs_put_name_union(&entry->name);
405+ ccs_put_number_union(&entry->number);
406+ }
407+ break;
408+ case CCS_TYPE_MKDEV_ACL:
409+ {
410+ struct ccs_mkdev_acl *entry =
411+ container_of(acl, typeof(*entry), head);
412+ ccs_put_name_union(&entry->name);
413+ ccs_put_number_union(&entry->mode);
414+ ccs_put_number_union(&entry->major);
415+ ccs_put_number_union(&entry->minor);
416+ }
417+ break;
418+ case CCS_TYPE_MOUNT_ACL:
419+ {
420+ struct ccs_mount_acl *entry =
421+ container_of(acl, typeof(*entry), head);
422+ ccs_put_name_union(&entry->dev_name);
423+ ccs_put_name_union(&entry->dir_name);
424+ ccs_put_name_union(&entry->fs_type);
425+ ccs_put_number_union(&entry->flags);
426+ }
427+ break;
428+#ifdef CONFIG_CCSECURITY_NETWORK
429+ case CCS_TYPE_INET_ACL:
430+ {
431+ struct ccs_inet_acl *entry =
432+ container_of(acl, typeof(*entry), head);
433+ ccs_put_group(entry->address.group);
434+ ccs_put_number_union(&entry->port);
435+ }
436+ break;
437+ case CCS_TYPE_UNIX_ACL:
438+ {
439+ struct ccs_unix_acl *entry =
440+ container_of(acl, typeof(*entry), head);
441+ ccs_put_name_union(&entry->name);
442+ }
443+ break;
444+#endif
445+#ifdef CONFIG_CCSECURITY_MISC
446+ case CCS_TYPE_ENV_ACL:
447+ {
448+ struct ccs_env_acl *entry =
449+ container_of(acl, typeof(*entry), head);
450+ ccs_put_name(entry->env);
451+ }
452+ break;
453+#endif
454+#ifdef CONFIG_CCSECURITY_CAPABILITY
455+ case CCS_TYPE_CAPABILITY_ACL:
456+ {
457+ /* Nothing to do. */
458+ }
459+ break;
460+#endif
461+#ifdef CONFIG_CCSECURITY_IPC
462+ case CCS_TYPE_SIGNAL_ACL:
463+ {
464+ struct ccs_signal_acl *entry =
465+ container_of(acl, typeof(*entry), head);
466+ ccs_put_number_union(&entry->sig);
467+ ccs_put_name(entry->domainname);
468+ }
469+ break;
470+#endif
471+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
472+ case CCS_TYPE_AUTO_EXECUTE_HANDLER:
473+ case CCS_TYPE_DENIED_EXECUTE_HANDLER:
474+ {
475+ struct ccs_handler_acl *entry =
476+ container_of(acl, typeof(*entry), head);
477+ ccs_put_name(entry->handler);
478+ }
479+ break;
480+#endif
481+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
482+ case CCS_TYPE_AUTO_TASK_ACL:
483+ case CCS_TYPE_MANUAL_TASK_ACL:
484+ {
485+ struct ccs_task_acl *entry =
486+ container_of(acl, typeof(*entry), head);
487+ ccs_put_name(entry->domainname);
488+ }
489+ break;
490+#endif
491+ }
492+}
493+
494+/**
495+ * ccs_del_domain - Delete members in "struct ccs_domain_info".
496+ *
497+ * @element: Pointer to "struct list_head".
498+ *
499+ * Returns nothing.
500+ *
501+ * Caller holds ccs_policy_lock mutex.
502+ */
503+static inline void ccs_del_domain(struct list_head *element)
504+{
505+ struct ccs_domain_info *domain =
506+ container_of(element, typeof(*domain), list);
507+ struct ccs_acl_info *acl;
508+ struct ccs_acl_info *tmp;
509+ /*
510+ * Since this domain is referenced from neither "struct ccs_io_buffer"
511+ * nor "struct task_struct", we can delete elements without checking
512+ * for is_deleted flag.
513+ */
514+ list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
515+ ccs_del_acl(&acl->list);
516+ ccs_memory_free(acl, CCS_ID_ACL);
517+ }
518+ ccs_put_name(domain->domainname);
519+}
520+
521+/**
522+ * ccs_del_path_group - Delete members in "struct ccs_path_group".
523+ *
524+ * @element: Pointer to "struct list_head".
525+ *
526+ * Returns nothing.
527+ */
528+static inline void ccs_del_path_group(struct list_head *element)
529+{
530+ struct ccs_path_group *member =
531+ container_of(element, typeof(*member), head.list);
532+ ccs_put_name(member->member_name);
533+}
534+
535+/**
536+ * ccs_del_group - Delete "struct ccs_group".
537+ *
538+ * @element: Pointer to "struct list_head".
539+ *
540+ * Returns nothing.
541+ */
542+static inline void ccs_del_group(struct list_head *element)
543+{
544+ struct ccs_group *group =
545+ container_of(element, typeof(*group), head.list);
546+ ccs_put_name(group->group_name);
547+}
548+
549+/**
550+ * ccs_del_address_group - Delete members in "struct ccs_address_group".
551+ *
552+ * @element: Pointer to "struct list_head".
553+ *
554+ * Returns nothing.
555+ */
556+static inline void ccs_del_address_group(struct list_head *element)
557+{
558+ /* Nothing to do. */
559+}
560+
561+/**
562+ * ccs_del_number_group - Delete members in "struct ccs_number_group".
563+ *
564+ * @element: Pointer to "struct list_head".
565+ *
566+ * Returns nothing.
567+ */
568+static inline void ccs_del_number_group(struct list_head *element)
569+{
570+ /* Nothing to do. */
571+}
572+
573+/**
574+ * ccs_del_reservedport - Delete members in "struct ccs_reserved".
575+ *
576+ * @element: Pointer to "struct list_head".
577+ *
578+ * Returns nothing.
579+ */
580+static inline void ccs_del_reservedport(struct list_head *element)
581+{
582+ /* Nothing to do. */
583+}
584+
585+/**
586+ * ccs_del_condition - Delete members in "struct ccs_condition".
587+ *
588+ * @element: Pointer to "struct list_head".
589+ *
590+ * Returns nothing.
591+ */
592+void ccs_del_condition(struct list_head *element)
593+{
594+ struct ccs_condition *cond = container_of(element, typeof(*cond),
595+ head.list);
596+ const u16 condc = cond->condc;
597+ const u16 numbers_count = cond->numbers_count;
598+ const u16 names_count = cond->names_count;
599+ const u16 argc = cond->argc;
600+ const u16 envc = cond->envc;
601+ unsigned int i;
602+ const struct ccs_condition_element *condp
603+ = (const struct ccs_condition_element *) (cond + 1);
604+ struct ccs_number_union *numbers_p
605+ = (struct ccs_number_union *) (condp + condc);
606+ struct ccs_name_union *names_p
607+ = (struct ccs_name_union *) (numbers_p + numbers_count);
608+ const struct ccs_argv *argv
609+ = (const struct ccs_argv *) (names_p + names_count);
610+ const struct ccs_envp *envp
611+ = (const struct ccs_envp *) (argv + argc);
612+ for (i = 0; i < numbers_count; i++)
613+ ccs_put_number_union(numbers_p++);
614+ for (i = 0; i < names_count; i++)
615+ ccs_put_name_union(names_p++);
616+ for (i = 0; i < argc; argv++, i++)
617+ ccs_put_name(argv->value);
618+ for (i = 0; i < envc; envp++, i++) {
619+ ccs_put_name(envp->name);
620+ ccs_put_name(envp->value);
621+ }
622+ ccs_put_name(cond->transit);
623+}
624+
625+/**
626+ * ccs_del_name - Delete members in "struct ccs_name".
627+ *
628+ * @element: Pointer to "struct list_head".
629+ *
630+ * Returns nothing.
631+ */
632+static inline void ccs_del_name(struct list_head *element)
633+{
634+ /* Nothing to do. */
635+}
636+
637+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
638+
639+/**
640+ * ccs_lock - Alternative for srcu_read_lock().
641+ *
642+ * Returns index number which has to be passed to ccs_unlock().
643+ */
644+int ccs_lock(void)
645+{
646+ int idx;
647+ spin_lock(&ccs_counter_lock);
648+ idx = ccs_counter.counter_idx;
649+ ccs_counter.counter[idx]++;
650+ spin_unlock(&ccs_counter_lock);
651+ return idx;
652+}
653+
654+/**
655+ * ccs_unlock - Alternative for srcu_read_unlock().
656+ *
657+ * @idx: Index number returned by ccs_lock().
658+ *
659+ * Returns nothing.
660+ */
661+void ccs_unlock(const int idx)
662+{
663+ spin_lock(&ccs_counter_lock);
664+ ccs_counter.counter[idx]--;
665+ spin_unlock(&ccs_counter_lock);
666+}
667+
668+/**
669+ * ccs_synchronize_counter - Alternative for synchronize_srcu().
670+ *
671+ * Returns nothing.
672+ */
673+static void ccs_synchronize_counter(void)
674+{
675+ int idx;
676+ int v;
677+ /*
678+ * Change currently active counter's index. Make it visible to other
679+ * threads by doing it with ccs_counter_lock held.
680+ * This function is called by garbage collector thread, and the garbage
681+ * collector thread is exclusive. Therefore, it is guaranteed that
682+ * SRCU grace period has expired when returning from this function.
683+ */
684+ spin_lock(&ccs_counter_lock);
685+ idx = ccs_counter.counter_idx;
686+ ccs_counter.counter_idx ^= 1;
687+ v = ccs_counter.counter[idx];
688+ spin_unlock(&ccs_counter_lock);
689+ /* Wait for previously active counter to become 0. */
690+ while (v) {
691+ ssleep(1);
692+ spin_lock(&ccs_counter_lock);
693+ v = ccs_counter.counter[idx];
694+ spin_unlock(&ccs_counter_lock);
695+ }
696+}
697+
698+#endif
699+
700+/**
701+ * ccs_try_to_gc - Try to kfree() an entry.
702+ *
703+ * @type: One of values in "enum ccs_policy_id".
704+ * @element: Pointer to "st

Part of diff was cut off due to size limit. Use your local client to view the full diff.

Show on old repository browser