• R/O
  • SSH
  • HTTPS

akari: 提交


Commit MetaInfo

修订版431 (tree)
时间2012-11-04 17:29:07
作者kumaneko

Log Message

1.0.29

更改概述

差异

--- tags/patches/1.0.29/memory.c (nonexistent)
+++ tags/patches/1.0.29/memory.c (revision 431)
@@ -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+ 2012/05/05
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.29/lsm.c (nonexistent)
+++ tags/patches/1.0.29/lsm.c (revision 431)
@@ -0,0 +1,3307 @@
1+/*
2+ * lsm.c
3+ *
4+ * Copyright (C) 2010-2012 Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
5+ *
6+ * Version: 1.0.29 2012/11/04
7+ */
8+
9+#include "internal.h"
10+#include <linux/security.h>
11+#include <linux/namei.h>
12+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
13+#define USE_UMODE_T
14+#else
15+#include "check_umode_t.h"
16+#endif
17+
18+/* Prototype definition. */
19+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
20+static void ccs_task_security_gc(void);
21+static int ccs_copy_cred_security(const struct cred *new,
22+ const struct cred *old, gfp_t gfp);
23+static struct ccs_security *ccs_find_cred_security(const struct cred *cred);
24+static DEFINE_SPINLOCK(ccs_task_security_list_lock);
25+static atomic_t ccs_in_execve_tasks = ATOMIC_INIT(0);
26+/*
27+ * List of "struct ccs_security" for "struct pid".
28+ *
29+ * All instances on this list is guaranteed that "struct ccs_security"->pid !=
30+ * NULL. Also, instances on this list that are in execve() are guaranteed that
31+ * "struct ccs_security"->cred remembers "struct linux_binprm"->cred with a
32+ * refcount on "struct linux_binprm"->cred.
33+ */
34+struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
35+/*
36+ * List of "struct ccs_security" for "struct cred".
37+ *
38+ * Since the number of "struct cred" is nearly equals to the number of
39+ * "struct pid", we allocate hash tables like ccs_task_security_list.
40+ *
41+ * All instances on this list are guaranteed that "struct ccs_security"->pid ==
42+ * NULL and "struct ccs_security"->cred != NULL.
43+ */
44+static struct list_head ccs_cred_security_list[CCS_MAX_TASK_SECURITY_HASH];
45+
46+/* Dummy security context for avoiding NULL pointer dereference. */
47+static struct ccs_security ccs_oom_security = {
48+ .ccs_domain_info = &ccs_kernel_domain
49+};
50+
51+/* Dummy security context for avoiding NULL pointer dereference. */
52+static struct ccs_security ccs_default_security = {
53+ .ccs_domain_info = &ccs_kernel_domain
54+};
55+#else
56+/* Dummy security context for avoiding NULL pointer dereference. */
57+extern struct ccs_security ccs_oom_security;
58+/* Dummy security context for avoiding NULL pointer dereference. */
59+extern struct ccs_security ccs_default_security;
60+/* Dummy marker for calling security_bprm_free(). */
61+static const unsigned long ccs_bprm_security;
62+#endif
63+
64+/* For exporting variables and functions. */
65+struct ccsecurity_exports ccsecurity_exports;
66+/* Members are updated by loadable kernel module. */
67+struct ccsecurity_operations ccsecurity_ops;
68+
69+/* Function pointers originally registered by register_security(). */
70+static struct security_operations original_security_ops /* = *security_ops; */;
71+
72+/*
73+ * AppArmor patch added "struct vfsmount *" to security_inode_\*() hooks.
74+ * Detect it by checking whether D_PATH_DISCONNECT is defined or not.
75+ * Also, there may be other kernels with "struct vfsmount *" added.
76+ * If you got build failure, check security_inode_\*() hooks in
77+ * include/linux/security.h.
78+ */
79+#if defined(D_PATH_DISCONNECT)
80+#define CCS_INODE_HOOK_HAS_MNT
81+#elif defined(CONFIG_SUSE_KERNEL) && LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 25)
82+#define CCS_INODE_HOOK_HAS_MNT
83+#elif defined(CONFIG_SECURITY_APPARMOR) && LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 24)
84+#define CCS_INODE_HOOK_HAS_MNT
85+#endif
86+
87+#ifdef CONFIG_AKARI_TRACE_EXECVE_COUNT
88+
89+/**
90+ * ccs_update_ee_counter - Update "struct ccs_execve" counter.
91+ *
92+ * @count: Count to increment or decrement.
93+ *
94+ * Returns updated counter.
95+ */
96+static unsigned int ccs_update_ee_counter(int count)
97+{
98+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) || defined(atomic_add_return)
99+ /* Debug counter for detecting "struct ccs_execve" memory leak. */
100+ static atomic_t ccs_ee_counter = ATOMIC_INIT(0);
101+ return atomic_add_return(count, &ccs_ee_counter);
102+#else
103+ static DEFINE_SPINLOCK(ccs_ee_lock);
104+ static unsigned int ccs_ee_counter;
105+ unsigned long flags;
106+ spin_lock_irqsave(&ccs_ee_lock, flags);
107+ ccs_ee_counter += count;
108+ count = ccs_ee_counter;
109+ spin_unlock_irqrestore(&ccs_ee_lock, flags);
110+ return count;
111+#endif
112+}
113+
114+/**
115+ * ccs_audit_alloc_execve - Audit allocation of "struct ccs_execve".
116+ *
117+ * @ee: Pointer to "struct ccs_execve".
118+ *
119+ * Returns nothing.
120+ */
121+void ccs_audit_alloc_execve(const struct ccs_execve * const ee)
122+{
123+ printk(KERN_INFO "AKARI: Allocated %p by pid=%u (count=%u)\n", ee,
124+ current->pid, ccs_update_ee_counter(1) - 1);
125+}
126+
127+/**
128+ * ccs_audit_free_execve - Audit release of "struct ccs_execve".
129+ *
130+ * @ee: Pointer to "struct ccs_execve".
131+ * @task: True if released by current task, false otherwise.
132+ *
133+ * Returns nothing.
134+ */
135+void ccs_audit_free_execve(const struct ccs_execve * const ee,
136+ const bool is_current)
137+{
138+ const unsigned int tmp = ccs_update_ee_counter(-1);
139+ if (is_current)
140+ printk(KERN_INFO "AKARI: Releasing %p by pid=%u (count=%u)\n",
141+ ee, current->pid, tmp);
142+ else
143+ printk(KERN_INFO "AKARI: Releasing %p by kernel (count=%u)\n",
144+ ee, tmp);
145+}
146+
147+#endif
148+
149+/**
150+ * ccs_clear_execve - Release memory used by do_execve().
151+ *
152+ * @ret: 0 if do_execve() succeeded, negative value otherwise.
153+ * @security: Pointer to "struct ccs_security".
154+ *
155+ * Returns nothing.
156+ */
157+static void ccs_clear_execve(int ret, struct ccs_security *security)
158+{
159+ struct ccs_execve *ee;
160+ if (security == &ccs_default_security || security == &ccs_oom_security)
161+ return;
162+ ee = security->ee;
163+ security->ee = NULL;
164+ if (!ee)
165+ return;
166+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
167+ /*
168+ * Drop refcount on "struct cred" in "struct linux_binprm" and forget
169+ * it.
170+ */
171+ put_cred(security->cred);
172+ security->cred = NULL;
173+ atomic_dec(&ccs_in_execve_tasks);
174+#endif
175+ ccs_finish_execve(ret, ee);
176+}
177+
178+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
179+
180+/**
181+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
182+ *
183+ * @rcu: Pointer to "struct rcu_head".
184+ *
185+ * Returns nothing.
186+ */
187+static void ccs_rcu_free(struct rcu_head *rcu)
188+{
189+ struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
190+ struct ccs_execve *ee = ptr->ee;
191+ /*
192+ * If this security context was associated with "struct pid" and
193+ * remembers "struct cred" in "struct linux_binprm", it indicates that
194+ * a "struct task_struct" associated with this security context exited
195+ * immediately after do_execve() has failed.
196+ */
197+ if (ptr->pid && ptr->cred) {
198+#ifdef CONFIG_AKARI_DEBUG
199+ static bool done;
200+ if (!done) {
201+ printk(KERN_INFO "AKARI: Dropping refcount on "
202+ "\"struct cred\" in \"struct linux_binprm\" "
203+ "because some \"struct task_struct\" has "
204+ "exit()ed immediately after do_execve() has "
205+ "failed.\n");
206+ done = true;
207+ }
208+#endif
209+ put_cred(ptr->cred);
210+ atomic_dec(&ccs_in_execve_tasks);
211+ }
212+ /*
213+ * If this security context was associated with "struct pid",
214+ * drop refcount obtained by get_pid() in ccs_find_task_security().
215+ */
216+ if (ptr->pid) {
217+#ifdef CONFIG_AKARI_DEBUG
218+ static bool done;
219+ if (!done) {
220+ printk(KERN_INFO "AKARI: Dropping refcount on "
221+ "\"struct pid\".\n");
222+ done = true;
223+ }
224+#endif
225+ put_pid(ptr->pid);
226+ }
227+ if (ee) {
228+#ifdef CONFIG_AKARI_DEBUG
229+ static bool done;
230+ if (!done) {
231+ printk(KERN_INFO "AKARI: Releasing memory in "
232+ "\"struct ccs_execve\" because some "
233+ "\"struct task_struct\" has exit()ed "
234+ "immediately after do_execve() has failed.\n");
235+ done = true;
236+ }
237+#endif
238+ ccs_audit_free_execve(ee, false);
239+ kfree(ee->handler_path);
240+ kfree(ee);
241+ }
242+ kfree(ptr);
243+}
244+
245+/**
246+ * ccs_del_security - Release "struct ccs_security".
247+ *
248+ * @ptr: Pointer to "struct ccs_security".
249+ *
250+ * Returns nothing.
251+ */
252+static void ccs_del_security(struct ccs_security *ptr)
253+{
254+ unsigned long flags;
255+ if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
256+ return;
257+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
258+ list_del_rcu(&ptr->list);
259+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
260+ call_rcu(&ptr->rcu, ccs_rcu_free);
261+}
262+
263+/**
264+ * ccs_add_cred_security - Add "struct ccs_security" to list.
265+ *
266+ * @ptr: Pointer to "struct ccs_security".
267+ *
268+ * Returns nothing.
269+ */
270+static void ccs_add_cred_security(struct ccs_security *ptr)
271+{
272+ unsigned long flags;
273+ struct list_head *list = &ccs_cred_security_list
274+ [hash_ptr((void *) ptr->cred, CCS_TASK_SECURITY_HASH_BITS)];
275+#ifdef CONFIG_AKARI_DEBUG
276+ if (ptr->pid)
277+ printk(KERN_INFO "AKARI: \"struct ccs_security\"->pid != NULL"
278+ "\n");
279+#endif
280+ ptr->pid = NULL;
281+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
282+ list_add_rcu(&ptr->list, list);
283+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
284+}
285+
286+/**
287+ * ccs_task_create - Make snapshot of security context for new task.
288+ *
289+ * @clone_flags: Flags passed to clone().
290+ *
291+ * Returns 0 on success, negative value otherwise.
292+ */
293+static int ccs_task_create(unsigned long clone_flags)
294+{
295+ int rc;
296+ struct ccs_security *old_security;
297+ struct ccs_security *new_security;
298+ struct cred *cred = prepare_creds();
299+ if (!cred)
300+ return -ENOMEM;
301+ while (!original_security_ops.task_create);
302+ rc = original_security_ops.task_create(clone_flags);
303+ if (rc) {
304+ abort_creds(cred);
305+ return rc;
306+ }
307+ old_security = ccs_find_task_security(current);
308+ new_security = ccs_find_cred_security(cred);
309+ new_security->ccs_domain_info = old_security->ccs_domain_info;
310+ new_security->ccs_flags = old_security->ccs_flags;
311+ return commit_creds(cred);
312+}
313+
314+/**
315+ * ccs_cred_prepare - Allocate memory for new credentials.
316+ *
317+ * @new: Pointer to "struct cred".
318+ * @old: Pointer to "struct cred".
319+ * @gfp: Memory allocation flags.
320+ *
321+ * Returns 0 on success, negative value otherwise.
322+ */
323+static int ccs_cred_prepare(struct cred *new, const struct cred *old,
324+ gfp_t gfp)
325+{
326+ int rc = ccs_copy_cred_security(new, old, gfp);
327+ if (rc)
328+ return rc;
329+ if (gfp == GFP_KERNEL)
330+ ccs_task_security_gc();
331+ while (!original_security_ops.cred_prepare);
332+ rc = original_security_ops.cred_prepare(new, old, gfp);
333+ if (rc)
334+ ccs_del_security(ccs_find_cred_security(new));
335+ return rc;
336+}
337+
338+/**
339+ * ccs_cred_free - Release memory used by credentials.
340+ *
341+ * @cred: Pointer to "struct cred".
342+ *
343+ * Returns nothing.
344+ */
345+static void ccs_cred_free(struct cred *cred)
346+{
347+ while (!original_security_ops.cred_free);
348+ original_security_ops.cred_free(cred);
349+ ccs_del_security(ccs_find_cred_security(cred));
350+}
351+
352+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
353+
354+/**
355+ * ccs_alloc_cred_security - Allocate memory for new credentials.
356+ *
357+ * @cred: Pointer to "struct cred".
358+ * @gfp: Memory allocation flags.
359+ *
360+ * Returns 0 on success, negative value otherwise.
361+ */
362+static int ccs_alloc_cred_security(const struct cred *cred, gfp_t gfp)
363+{
364+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
365+ gfp);
366+ if (!new_security)
367+ return -ENOMEM;
368+ new_security->cred = cred;
369+ ccs_add_cred_security(new_security);
370+ return 0;
371+}
372+
373+/**
374+ * ccs_cred_alloc_blank - Allocate memory for new credentials.
375+ *
376+ * @new: Pointer to "struct cred".
377+ * @gfp: Memory allocation flags.
378+ *
379+ * Returns 0 on success, negative value otherwise.
380+ */
381+static int ccs_cred_alloc_blank(struct cred *new, gfp_t gfp)
382+{
383+ int rc = ccs_alloc_cred_security(new, gfp);
384+ if (rc)
385+ return rc;
386+ while (!original_security_ops.cred_alloc_blank);
387+ rc = original_security_ops.cred_alloc_blank(new, gfp);
388+ if (rc)
389+ ccs_del_security(ccs_find_cred_security(new));
390+ return rc;
391+}
392+
393+/**
394+ * ccs_cred_transfer - Transfer "struct ccs_security" between credentials.
395+ *
396+ * @new: Pointer to "struct cred".
397+ * @old: Pointer to "struct cred".
398+ *
399+ * Returns nothing.
400+ */
401+static void ccs_cred_transfer(struct cred *new, const struct cred *old)
402+{
403+ struct ccs_security *new_security;
404+ struct ccs_security *old_security;
405+ while (!original_security_ops.cred_transfer);
406+ original_security_ops.cred_transfer(new, old);
407+ new_security = ccs_find_cred_security(new);
408+ old_security = ccs_find_cred_security(old);
409+ if (new_security == &ccs_default_security ||
410+ new_security == &ccs_oom_security ||
411+ old_security == &ccs_default_security ||
412+ old_security == &ccs_oom_security)
413+ return;
414+ new_security->ccs_flags = old_security->ccs_flags;
415+ new_security->ccs_domain_info = old_security->ccs_domain_info;
416+}
417+
418+#endif
419+
420+#else
421+
422+/**
423+ * ccs_task_alloc_security - Allocate memory for new tasks.
424+ *
425+ * @p: Pointer to "struct task_struct".
426+ *
427+ * Returns 0 on success, negative value otherwise.
428+ */
429+static int ccs_task_alloc_security(struct task_struct *p)
430+{
431+ int rc = ccs_alloc_task_security(p);
432+ if (rc)
433+ return rc;
434+ while (!original_security_ops.task_alloc_security);
435+ rc = original_security_ops.task_alloc_security(p);
436+ if (rc)
437+ ccs_free_task_security(p);
438+ return rc;
439+}
440+
441+/**
442+ * ccs_task_free_security - Release memory for "struct task_struct".
443+ *
444+ * @p: Pointer to "struct task_struct".
445+ *
446+ * Returns nothing.
447+ */
448+static void ccs_task_free_security(struct task_struct *p)
449+{
450+ while (!original_security_ops.task_free_security);
451+ original_security_ops.task_free_security(p);
452+ ccs_free_task_security(p);
453+}
454+
455+/**
456+ * ccs_bprm_alloc_security - Allocate memory for "struct linux_binprm".
457+ *
458+ * @bprm: Pointer to "struct linux_binprm".
459+ *
460+ * Returns 0 on success, negative value otherwise.
461+ */
462+static int ccs_bprm_alloc_security(struct linux_binprm *bprm)
463+{
464+ int rc;
465+ while (!original_security_ops.bprm_alloc_security);
466+ rc = original_security_ops.bprm_alloc_security(bprm);
467+ if (bprm->security || rc)
468+ return rc;
469+ /*
470+ * Update bprm->security to &ccs_bprm_security so that
471+ * security_bprm_free() is called even if do_execve() failed at
472+ * search_binary_handler() without allocating memory at
473+ * security_bprm_alloc(). This trick assumes that active LSM module
474+ * does not access bprm->security if that module did not allocate
475+ * memory at security_bprm_alloc().
476+ */
477+ bprm->security = (void *) &ccs_bprm_security;
478+ return 0;
479+}
480+
481+/**
482+ * ccs_bprm_free_security - Release memory for "struct linux_binprm".
483+ *
484+ * @bprm: Pointer to "struct linux_binprm".
485+ *
486+ * Returns nothing.
487+ */
488+static void ccs_bprm_free_security(struct linux_binprm *bprm)
489+{
490+ /*
491+ * If do_execve() succeeded, bprm->security will be updated to NULL at
492+ * security_bprm_compute_creds()/security_bprm_apply_creds() if
493+ * bprm->security was set to &ccs_bprm_security at
494+ * security_bprm_alloc().
495+ *
496+ * If do_execve() failed, bprm->security remains at &ccs_bprm_security
497+ * if bprm->security was set to &ccs_bprm_security at
498+ * security_bprm_alloc().
499+ *
500+ * And do_execve() does not call security_bprm_free() if do_execve()
501+ * failed and bprm->security == NULL. Therefore, do not call
502+ * original_security_ops.bprm_free_security() if bprm->security remains
503+ * at &ccs_bprm_security .
504+ */
505+ if (bprm->security != &ccs_bprm_security) {
506+ while (!original_security_ops.bprm_free_security);
507+ original_security_ops.bprm_free_security(bprm);
508+ }
509+ /*
510+ * If do_execve() succeeded,
511+ * ccs_clear_execve(0, ccs_current_security());
512+ * is called before calling below one.
513+ * Thus, below call becomes no-op if do_execve() succeeded.
514+ */
515+ ccs_clear_execve(-1, ccs_current_security());
516+}
517+
518+#endif
519+
520+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6)
521+
522+/**
523+ * ccs_bprm_compute_creds - A hook which is called when do_execve() succeeded.
524+ *
525+ * @bprm: Pointer to "struct linux_binprm".
526+ *
527+ * Returns nothing.
528+ */
529+static void ccs_bprm_compute_creds(struct linux_binprm *bprm)
530+{
531+ if (bprm->security == &ccs_bprm_security)
532+ bprm->security = NULL;
533+ while (!original_security_ops.bprm_compute_creds);
534+ original_security_ops.bprm_compute_creds(bprm);
535+ ccs_clear_execve(0, ccs_current_security());
536+}
537+
538+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
539+
540+/**
541+ * ccs_bprm_apply_creds - A hook which is called when do_execve() succeeded.
542+ *
543+ * @bprm: Pointer to "struct linux_binprm".
544+ * @unsafe: Unsafe flag.
545+ *
546+ * Returns nothing.
547+ */
548+static void ccs_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
549+{
550+ if (bprm->security == &ccs_bprm_security)
551+ bprm->security = NULL;
552+ while (!original_security_ops.bprm_apply_creds);
553+ original_security_ops.bprm_apply_creds(bprm, unsafe);
554+ ccs_clear_execve(0, ccs_current_security());
555+}
556+
557+#else
558+
559+/**
560+ * ccs_bprm_committing_creds - A hook which is called when do_execve() succeeded.
561+ *
562+ * @bprm: Pointer to "struct linux_binprm".
563+ *
564+ * Returns nothing.
565+ */
566+static void ccs_bprm_committing_creds(struct linux_binprm *bprm)
567+{
568+ struct ccs_security *old_security;
569+ struct ccs_security *new_security;
570+ while (!original_security_ops.bprm_committing_creds);
571+ original_security_ops.bprm_committing_creds(bprm);
572+ old_security = ccs_current_security();
573+ if (old_security == &ccs_default_security ||
574+ old_security == &ccs_oom_security)
575+ return;
576+ ccs_clear_execve(0, old_security);
577+ /* Update current task's cred's domain for future fork(). */
578+ new_security = ccs_find_cred_security(bprm->cred);
579+ new_security->ccs_flags = old_security->ccs_flags;
580+ new_security->ccs_domain_info = old_security->ccs_domain_info;
581+}
582+
583+#endif
584+
585+/**
586+ * ccs_bprm_check_security - Check permission for execve().
587+ *
588+ * @bprm: Pointer to "struct linux_binprm".
589+ *
590+ * Returns 0 on success, negative value otherwise.
591+ */
592+static int ccs_bprm_check_security(struct linux_binprm *bprm)
593+{
594+ struct ccs_security *security = ccs_current_security();
595+ if (security == &ccs_default_security || security == &ccs_oom_security)
596+ return -ENOMEM;
597+ if (!security->ee) {
598+ int rc;
599+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
600+ if (!ccs_policy_loaded)
601+ ccs_load_policy(bprm->filename);
602+#endif
603+ rc = ccs_start_execve(bprm, &security->ee);
604+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
605+ if (security->ee) {
606+ /*
607+ * Get refcount on "struct cred" in
608+ * "struct linux_binprm" and remember it.
609+ */
610+ get_cred(bprm->cred);
611+ security->cred = bprm->cred;
612+ atomic_inc(&ccs_in_execve_tasks);
613+ }
614+#endif
615+ if (rc)
616+ return rc;
617+ }
618+ while (!original_security_ops.bprm_check_security);
619+ return original_security_ops.bprm_check_security(bprm);
620+}
621+
622+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
623+
624+/**
625+ * ccs_open - Check permission for open().
626+ *
627+ * @f: Pointer to "struct file".
628+ *
629+ * Returns 0 on success, negative value otherwise.
630+ */
631+static int ccs_open(struct file *f)
632+{
633+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
634+ return ccs_open_permission(f);
635+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
636+ return ccs_open_permission(f->f_path.dentry, f->f_path.mnt,
637+ f->f_flags);
638+#else
639+ return ccs_open_permission(f->f_path.dentry, f->f_path.mnt,
640+ f->f_flags + 1);
641+#endif
642+}
643+
644+#endif
645+
646+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
647+
648+/**
649+ * ccs_file_open - Check permission for open().
650+ *
651+ * @f: Pointer to "struct file".
652+ * @cred: Pointer to "struct cred".
653+ *
654+ * Returns 0 on success, negative value otherwise.
655+ */
656+static int ccs_file_open(struct file *f, const struct cred *cred)
657+{
658+ int rc = ccs_open(f);
659+ if (rc)
660+ return rc;
661+ while (!original_security_ops.file_open);
662+ return original_security_ops.file_open(f, cred);
663+}
664+
665+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
666+
667+/**
668+ * ccs_dentry_open - Check permission for open().
669+ *
670+ * @f: Pointer to "struct file".
671+ * @cred: Pointer to "struct cred".
672+ *
673+ * Returns 0 on success, negative value otherwise.
674+ */
675+static int ccs_dentry_open(struct file *f, const struct cred *cred)
676+{
677+ int rc = ccs_open(f);
678+ if (rc)
679+ return rc;
680+ while (!original_security_ops.dentry_open);
681+ return original_security_ops.dentry_open(f, cred);
682+}
683+
684+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
685+
686+/**
687+ * ccs_dentry_open - Check permission for open().
688+ *
689+ * @f: Pointer to "struct file".
690+ *
691+ * Returns 0 on success, negative value otherwise.
692+ */
693+static int ccs_dentry_open(struct file *f)
694+{
695+ int rc = ccs_open(f);
696+ if (rc)
697+ return rc;
698+ while (!original_security_ops.dentry_open);
699+ return original_security_ops.dentry_open(f);
700+}
701+
702+#else
703+
704+/**
705+ * ccs_open - Check permission for open().
706+ *
707+ * @inode: Pointer to "struct inode".
708+ * @mask: Open mode.
709+ * @nd: Pointer to "struct nameidata".
710+ *
711+ * Returns 0 on success, negative value otherwise.
712+ */
713+static int ccs_open(struct inode *inode, int mask, struct nameidata *nd)
714+{
715+ int flags;
716+ if (!nd || !nd->dentry)
717+ return 0;
718+ /* open_exec() passes MAY_EXEC . */
719+ if (mask == MAY_EXEC && inode && S_ISREG(inode->i_mode) &&
720+ (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE))
721+ mask = MAY_READ;
722+ /*
723+ * This flags value is passed to ACC_MODE().
724+ * ccs_open_permission() for older versions uses old ACC_MODE().
725+ */
726+ switch (mask & (MAY_READ | MAY_WRITE)) {
727+ case MAY_READ:
728+ flags = 01;
729+ break;
730+ case MAY_WRITE:
731+ flags = 02;
732+ break;
733+ case MAY_READ | MAY_WRITE:
734+ flags = 03;
735+ break;
736+ default:
737+ return 0;
738+ }
739+ return ccs_open_permission(nd->dentry, nd->mnt, flags);
740+}
741+
742+/**
743+ * ccs_inode_permission - Check permission for open().
744+ *
745+ * @inode: Pointer to "struct inode".
746+ * @mask: Open mode.
747+ * @nd: Pointer to "struct nameidata".
748+ *
749+ * Returns 0 on success, negative value otherwise.
750+ *
751+ * Note that this hook is called from permission(), and may not be called for
752+ * open(). Maybe it is better to use security_file_permission().
753+ */
754+static int ccs_inode_permission(struct inode *inode, int mask,
755+ struct nameidata *nd)
756+{
757+ int rc = ccs_open(inode, mask, nd);
758+ if (rc)
759+ return rc;
760+ while (!original_security_ops.inode_permission);
761+ return original_security_ops.inode_permission(inode, mask, nd);
762+}
763+
764+#endif
765+
766+#if defined(CONFIG_SECURITY_PATH)
767+
768+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
769+
770+/**
771+ * ccs_path_chown - Check permission for chown()/chgrp().
772+ *
773+ * @path: Pointer to "struct path".
774+ * @user: User ID.
775+ * @group: Group ID.
776+ *
777+ * Returns 0 on success, negative value otherwise.
778+ */
779+static int ccs_path_chown(struct path *path, kuid_t user, kgid_t group)
780+{
781+ int rc = ccs_chown_permission(path->dentry, path->mnt, user, group);
782+ if (rc)
783+ return rc;
784+ while (!original_security_ops.path_chown);
785+ return original_security_ops.path_chown(path, user, group);
786+}
787+
788+/**
789+ * ccs_path_chmod - Check permission for chmod().
790+ *
791+ * @path: Pointer to "struct path".
792+ * @mode: Mode.
793+ *
794+ * Returns 0 on success, negative value otherwise.
795+ */
796+static int ccs_path_chmod(struct path *path, umode_t mode)
797+{
798+ int rc = ccs_chmod_permission(path->dentry, path->mnt, mode);
799+ if (rc)
800+ return rc;
801+ while (!original_security_ops.path_chmod);
802+ return original_security_ops.path_chmod(path, mode);
803+}
804+
805+/**
806+ * ccs_path_chroot - Check permission for chroot().
807+ *
808+ * @path: Pointer to "struct path".
809+ *
810+ * Returns 0 on success, negative value otherwise.
811+ */
812+static int ccs_path_chroot(struct path *path)
813+{
814+ int rc = ccs_chroot_permission(path);
815+ if (rc)
816+ return rc;
817+ while (!original_security_ops.path_chroot);
818+ return original_security_ops.path_chroot(path);
819+}
820+
821+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
822+
823+/**
824+ * ccs_path_chown - Check permission for chown()/chgrp().
825+ *
826+ * @path: Pointer to "struct path".
827+ * @user: User ID.
828+ * @group: Group ID.
829+ *
830+ * Returns 0 on success, negative value otherwise.
831+ */
832+static int ccs_path_chown(struct path *path, uid_t user, gid_t group)
833+{
834+ int rc = ccs_chown_permission(path->dentry, path->mnt, user, group);
835+ if (rc)
836+ return rc;
837+ while (!original_security_ops.path_chown);
838+ return original_security_ops.path_chown(path, user, group);
839+}
840+
841+#if defined(USE_UMODE_T)
842+
843+/**
844+ * ccs_path_chmod - Check permission for chmod().
845+ *
846+ * @path: Pointer to "struct path".
847+ * @mode: Mode.
848+ *
849+ * Returns 0 on success, negative value otherwise.
850+ */
851+static int ccs_path_chmod(struct path *path, umode_t mode)
852+{
853+ int rc = ccs_chmod_permission(path->dentry, path->mnt, mode);
854+ if (rc)
855+ return rc;
856+ while (!original_security_ops.path_chmod);
857+ return original_security_ops.path_chmod(path, mode);
858+}
859+
860+#else
861+
862+/**
863+ * ccs_path_chmod - Check permission for chmod().
864+ *
865+ * @dentry: Pointer to "struct dentry".
866+ * @vfsmnt: Pointer to "struct vfsmount".
867+ * @mode: Mode.
868+ *
869+ * Returns 0 on success, negative value otherwise.
870+ */
871+static int ccs_path_chmod(struct dentry *dentry, struct vfsmount *vfsmnt,
872+ mode_t mode)
873+{
874+ int rc = ccs_chmod_permission(dentry, vfsmnt, mode);
875+ if (rc)
876+ return rc;
877+ while (!original_security_ops.path_chmod);
878+ return original_security_ops.path_chmod(dentry, vfsmnt, mode);
879+}
880+
881+#endif
882+
883+/**
884+ * ccs_path_chroot - Check permission for chroot().
885+ *
886+ * @path: Pointer to "struct path".
887+ *
888+ * Returns 0 on success, negative value otherwise.
889+ */
890+static int ccs_path_chroot(struct path *path)
891+{
892+ int rc = ccs_chroot_permission(path);
893+ if (rc)
894+ return rc;
895+ while (!original_security_ops.path_chroot);
896+ return original_security_ops.path_chroot(path);
897+}
898+
899+#endif
900+
901+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
902+
903+/**
904+ * ccs_path_truncate - Check permission for truncate().
905+ *
906+ * @path: Pointer to "struct path".
907+ *
908+ * Returns 0 on success, negative value otherwise.
909+ */
910+static int ccs_path_truncate(struct path *path)
911+{
912+ int rc = ccs_truncate_permission(path->dentry, path->mnt);
913+ if (rc)
914+ return rc;
915+ while (!original_security_ops.path_truncate);
916+ return original_security_ops.path_truncate(path);
917+}
918+
919+#else
920+
921+/**
922+ * ccs_path_truncate - Check permission for truncate().
923+ *
924+ * @path: Pointer to "struct path".
925+ * @length: New length.
926+ * @time_attrs: New time attributes.
927+ *
928+ * Returns 0 on success, negative value otherwise.
929+ */
930+static int ccs_path_truncate(struct path *path, loff_t length,
931+ unsigned int time_attrs)
932+{
933+ int rc = ccs_truncate_permission(path->dentry, path->mnt);
934+ if (rc)
935+ return rc;
936+ while (!original_security_ops.path_truncate);
937+ return original_security_ops.path_truncate(path, length, time_attrs);
938+}
939+
940+#endif
941+
942+#endif
943+
944+#ifdef CCS_INODE_HOOK_HAS_MNT
945+
946+/**
947+ * ccs_inode_setattr - Check permission for chown()/chgrp()/chmod()/truncate().
948+ *
949+ * @dentry: Pointer to "struct dentry".
950+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
951+ * @attr: Pointer to "struct iattr".
952+ *
953+ * Returns 0 on success, negative value otherwise.
954+ */
955+static int ccs_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
956+ struct iattr *attr)
957+{
958+ int rc = 0;
959+#if !defined(CONFIG_SECURITY_PATH) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
960+ if (attr->ia_valid & ATTR_UID)
961+ rc = ccs_chown_permission(dentry, mnt, attr->ia_uid, -1);
962+ if (!rc && (attr->ia_valid & ATTR_GID))
963+ rc = ccs_chown_permission(dentry, mnt, -1, attr->ia_gid);
964+ if (!rc && (attr->ia_valid & ATTR_MODE))
965+ rc = ccs_chmod_permission(dentry, mnt, attr->ia_mode);
966+#endif
967+#if !defined(CONFIG_SECURITY_PATH)
968+ if (!rc && (attr->ia_valid & ATTR_SIZE))
969+ rc = ccs_truncate_permission(dentry, mnt);
970+#endif
971+ if (rc)
972+ return rc;
973+ while (!original_security_ops.inode_setattr);
974+ return original_security_ops.inode_setattr(dentry, mnt, attr);
975+}
976+
977+#else
978+
979+/**
980+ * ccs_inode_setattr - Check permission for chown()/chgrp()/chmod()/truncate().
981+ *
982+ * @dentry: Pointer to "struct dentry".
983+ * @attr: Pointer to "struct iattr".
984+ *
985+ * Returns 0 on success, negative value otherwise.
986+ */
987+static int ccs_inode_setattr(struct dentry *dentry, struct iattr *attr)
988+{
989+ int rc = 0;
990+#if !defined(CONFIG_SECURITY_PATH) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
991+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
992+ if (attr->ia_valid & ATTR_UID)
993+ rc = ccs_chown_permission(dentry, NULL, attr->ia_uid, INVALID_GID);
994+ if (!rc && (attr->ia_valid & ATTR_GID))
995+ rc = ccs_chown_permission(dentry, NULL, INVALID_UID, attr->ia_gid);
996+#else
997+ if (attr->ia_valid & ATTR_UID)
998+ rc = ccs_chown_permission(dentry, NULL, attr->ia_uid, -1);
999+ if (!rc && (attr->ia_valid & ATTR_GID))
1000+ rc = ccs_chown_permission(dentry, NULL, -1, attr->ia_gid);
1001+#endif
1002+ if (!rc && (attr->ia_valid & ATTR_MODE))
1003+ rc = ccs_chmod_permission(dentry, NULL, attr->ia_mode);
1004+#endif
1005+#if !defined(CONFIG_SECURITY_PATH)
1006+ if (!rc && (attr->ia_valid & ATTR_SIZE))
1007+ rc = ccs_truncate_permission(dentry, NULL);
1008+#endif
1009+ if (rc)
1010+ return rc;
1011+ while (!original_security_ops.inode_setattr);
1012+ return original_security_ops.inode_setattr(dentry, attr);
1013+}
1014+
1015+#endif
1016+
1017+/**
1018+ * ccs_inode_getattr - Check permission for stat().
1019+ *
1020+ * @mnt: Pointer to "struct vfsmount".
1021+ * @dentry: Pointer to "struct dentry".
1022+ *
1023+ * Returns 0 on success, negative value otherwise.
1024+ */
1025+static int ccs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
1026+{
1027+ int rc = ccs_getattr_permission(mnt, dentry);
1028+ if (rc)
1029+ return rc;
1030+ while (!original_security_ops.inode_getattr);
1031+ return original_security_ops.inode_getattr(mnt, dentry);
1032+}
1033+
1034+#if defined(CONFIG_SECURITY_PATH)
1035+
1036+#if defined(USE_UMODE_T)
1037+
1038+/**
1039+ * ccs_path_mknod - Check permission for mknod().
1040+ *
1041+ * @dir: Pointer to "struct path".
1042+ * @dentry: Pointer to "struct dentry".
1043+ * @mode: Create mode.
1044+ * @dev: Device major/minor number.
1045+ *
1046+ * Returns 0 on success, negative value otherwise.
1047+ */
1048+static int ccs_path_mknod(struct path *dir, struct dentry *dentry,
1049+ umode_t mode, unsigned int dev)
1050+{
1051+ int rc = ccs_mknod_permission(dentry, dir->mnt, mode, dev);
1052+ if (rc)
1053+ return rc;
1054+ while (!original_security_ops.path_mknod);
1055+ return original_security_ops.path_mknod(dir, dentry, mode, dev);
1056+}
1057+
1058+/**
1059+ * ccs_path_mkdir - Check permission for mkdir().
1060+ *
1061+ * @dir: Pointer to "struct path".
1062+ * @dentry: Pointer to "struct dentry".
1063+ * @mode: Create mode.
1064+ *
1065+ * Returns 0 on success, negative value otherwise.
1066+ */
1067+static int ccs_path_mkdir(struct path *dir, struct dentry *dentry,
1068+ umode_t mode)
1069+{
1070+ int rc = ccs_mkdir_permission(dentry, dir->mnt, mode);
1071+ if (rc)
1072+ return rc;
1073+ while (!original_security_ops.path_mkdir);
1074+ return original_security_ops.path_mkdir(dir, dentry, mode);
1075+}
1076+
1077+#else
1078+
1079+/**
1080+ * ccs_path_mknod - Check permission for mknod().
1081+ *
1082+ * @dir: Pointer to "struct path".
1083+ * @dentry: Pointer to "struct dentry".
1084+ * @mode: Create mode.
1085+ * @dev: Device major/minor number.
1086+ *
1087+ * Returns 0 on success, negative value otherwise.
1088+ */
1089+static int ccs_path_mknod(struct path *dir, struct dentry *dentry, int mode,
1090+ unsigned int dev)
1091+{
1092+ int rc = ccs_mknod_permission(dentry, dir->mnt, mode, dev);
1093+ if (rc)
1094+ return rc;
1095+ while (!original_security_ops.path_mknod);
1096+ return original_security_ops.path_mknod(dir, dentry, mode, dev);
1097+}
1098+
1099+/**
1100+ * ccs_path_mkdir - Check permission for mkdir().
1101+ *
1102+ * @dir: Pointer to "struct path".
1103+ * @dentry: Pointer to "struct dentry".
1104+ * @mode: Create mode.
1105+ *
1106+ * Returns 0 on success, negative value otherwise.
1107+ */
1108+static int ccs_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
1109+{
1110+ int rc = ccs_mkdir_permission(dentry, dir->mnt, mode);
1111+ if (rc)
1112+ return rc;
1113+ while (!original_security_ops.path_mkdir);
1114+ return original_security_ops.path_mkdir(dir, dentry, mode);
1115+}
1116+
1117+#endif
1118+
1119+/**
1120+ * ccs_path_rmdir - Check permission for rmdir().
1121+ *
1122+ * @dir: Pointer to "struct path".
1123+ * @dentry: Pointer to "struct dentry".
1124+ *
1125+ * Returns 0 on success, negative value otherwise.
1126+ */
1127+static int ccs_path_rmdir(struct path *dir, struct dentry *dentry)
1128+{
1129+ int rc = ccs_rmdir_permission(dentry, dir->mnt);
1130+ if (rc)
1131+ return rc;
1132+ while (!original_security_ops.path_rmdir);
1133+ return original_security_ops.path_rmdir(dir, dentry);
1134+}
1135+
1136+/**
1137+ * ccs_path_unlink - Check permission for unlink().
1138+ *
1139+ * @dir: Pointer to "struct path".
1140+ * @dentry: Pointer to "struct dentry".
1141+ *
1142+ * Returns 0 on success, negative value otherwise.
1143+ */
1144+static int ccs_path_unlink(struct path *dir, struct dentry *dentry)
1145+{
1146+ int rc = ccs_unlink_permission(dentry, dir->mnt);
1147+ if (rc)
1148+ return rc;
1149+ while (!original_security_ops.path_unlink);
1150+ return original_security_ops.path_unlink(dir, dentry);
1151+}
1152+
1153+/**
1154+ * ccs_path_symlink - Check permission for symlink().
1155+ *
1156+ * @dir: Pointer to "struct path".
1157+ * @dentry: Pointer to "struct dentry".
1158+ * @old_name: Content of symbolic link.
1159+ *
1160+ * Returns 0 on success, negative value otherwise.
1161+ */
1162+static int ccs_path_symlink(struct path *dir, struct dentry *dentry,
1163+ const char *old_name)
1164+{
1165+ int rc = ccs_symlink_permission(dentry, dir->mnt, old_name);
1166+ if (rc)
1167+ return rc;
1168+ while (!original_security_ops.path_symlink);
1169+ return original_security_ops.path_symlink(dir, dentry, old_name);
1170+}
1171+
1172+/**
1173+ * ccs_path_rename - Check permission for rename().
1174+ *
1175+ * @old_dir: Pointer to "struct path".
1176+ * @old_dentry: Pointer to "struct dentry".
1177+ * @new_dir: Pointer to "struct path".
1178+ * @new_dentry: Pointer to "struct dentry".
1179+ *
1180+ * Returns 0 on success, negative value otherwise.
1181+ */
1182+static int ccs_path_rename(struct path *old_dir, struct dentry *old_dentry,
1183+ struct path *new_dir, struct dentry *new_dentry)
1184+{
1185+ int rc = ccs_rename_permission(old_dentry, new_dentry, old_dir->mnt);
1186+ if (rc)
1187+ return rc;
1188+ while (!original_security_ops.path_rename);
1189+ return original_security_ops.path_rename(old_dir, old_dentry, new_dir,
1190+ new_dentry);
1191+}
1192+
1193+/**
1194+ * ccs_path_link - Check permission for link().
1195+ *
1196+ * @old_dentry: Pointer to "struct dentry".
1197+ * @new_dir: Pointer to "struct path".
1198+ * @new_dentry: Pointer to "struct dentry".
1199+ *
1200+ * Returns 0 on success, negative value otherwise.
1201+ */
1202+static int ccs_path_link(struct dentry *old_dentry, struct path *new_dir,
1203+ struct dentry *new_dentry)
1204+{
1205+ int rc = ccs_link_permission(old_dentry, new_dentry, new_dir->mnt);
1206+ if (rc)
1207+ return rc;
1208+ while (!original_security_ops.path_link);
1209+ return original_security_ops.path_link(old_dentry, new_dir,
1210+ new_dentry);
1211+}
1212+
1213+#elif defined(CCS_INODE_HOOK_HAS_MNT)
1214+
1215+/**
1216+ * ccs_inode_mknod - Check permission for mknod().
1217+ *
1218+ * @dir: Pointer to "struct inode".
1219+ * @dentry: Pointer to "struct dentry".
1220+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1221+ * @mode: Create mode.
1222+ * @dev: Device major/minor number.
1223+ *
1224+ * Returns 0 on success, negative value otherwise.
1225+ */
1226+static int ccs_inode_mknod(struct inode *dir, struct dentry *dentry,
1227+ struct vfsmount *mnt, int mode, dev_t dev)
1228+{
1229+ int rc = ccs_mknod_permission(dentry, mnt, mode, dev);
1230+ if (rc)
1231+ return rc;
1232+ while (!original_security_ops.inode_mknod);
1233+ return original_security_ops.inode_mknod(dir, dentry, mnt, mode, dev);
1234+}
1235+
1236+/**
1237+ * ccs_inode_mkdir - Check permission for mkdir().
1238+ *
1239+ * @dir: Pointer to "struct inode".
1240+ * @dentry: Pointer to "struct dentry".
1241+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1242+ * @mode: Create mode.
1243+ *
1244+ * Returns 0 on success, negative value otherwise.
1245+ */
1246+static int ccs_inode_mkdir(struct inode *dir, struct dentry *dentry,
1247+ struct vfsmount *mnt, int mode)
1248+{
1249+ int rc = ccs_mkdir_permission(dentry, mnt, mode);
1250+ if (rc)
1251+ return rc;
1252+ while (!original_security_ops.inode_mkdir);
1253+ return original_security_ops.inode_mkdir(dir, dentry, mnt, mode);
1254+}
1255+
1256+/**
1257+ * ccs_inode_rmdir - Check permission for rmdir().
1258+ *
1259+ * @dir: Pointer to "struct inode".
1260+ * @dentry: Pointer to "struct dentry".
1261+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1262+ *
1263+ * Returns 0 on success, negative value otherwise.
1264+ */
1265+static int ccs_inode_rmdir(struct inode *dir, struct dentry *dentry,
1266+ struct vfsmount *mnt)
1267+{
1268+ int rc = ccs_rmdir_permission(dentry, mnt);
1269+ if (rc)
1270+ return rc;
1271+ while (!original_security_ops.inode_rmdir);
1272+ return original_security_ops.inode_rmdir(dir, dentry, mnt);
1273+}
1274+
1275+/**
1276+ * ccs_inode_unlink - Check permission for unlink().
1277+ *
1278+ * @dir: Pointer to "struct inode".
1279+ * @dentry: Pointer to "struct dentry".
1280+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1281+ *
1282+ * Returns 0 on success, negative value otherwise.
1283+ */
1284+static int ccs_inode_unlink(struct inode *dir, struct dentry *dentry,
1285+ struct vfsmount *mnt)
1286+{
1287+ int rc = ccs_unlink_permission(dentry, mnt);
1288+ if (rc)
1289+ return rc;
1290+ while (!original_security_ops.inode_unlink);
1291+ return original_security_ops.inode_unlink(dir, dentry, mnt);
1292+}
1293+
1294+/**
1295+ * ccs_inode_symlink - Check permission for symlink().
1296+ *
1297+ * @dir: Pointer to "struct inode".
1298+ * @dentry: Pointer to "struct dentry".
1299+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1300+ * @old_name: Content of symbolic link.
1301+ *
1302+ * Returns 0 on success, negative value otherwise.
1303+ */
1304+static int ccs_inode_symlink(struct inode *dir, struct dentry *dentry,
1305+ struct vfsmount *mnt, const char *old_name)
1306+{
1307+ int rc = ccs_symlink_permission(dentry, mnt, old_name);
1308+ if (rc)
1309+ return rc;
1310+ while (!original_security_ops.inode_symlink);
1311+ return original_security_ops.inode_symlink(dir, dentry, mnt, old_name);
1312+}
1313+
1314+/**
1315+ * ccs_inode_rename - Check permission for rename().
1316+ *
1317+ * @old_dir: Pointer to "struct inode".
1318+ * @old_dentry: Pointer to "struct dentry".
1319+ * @old_mnt: Pointer to "struct vfsmount". Maybe NULL.
1320+ * @new_dir: Pointer to "struct inode".
1321+ * @new_dentry: Pointer to "struct dentry".
1322+ * @new_mnt: Pointer to "struct vfsmount". Maybe NULL.
1323+ *
1324+ * Returns 0 on success, negative value otherwise.
1325+ */
1326+static int ccs_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
1327+ struct vfsmount *old_mnt, struct inode *new_dir,
1328+ struct dentry *new_dentry,
1329+ struct vfsmount *new_mnt)
1330+{
1331+ int rc = ccs_rename_permission(old_dentry, new_dentry, new_mnt);
1332+ if (rc)
1333+ return rc;
1334+ while (!original_security_ops.inode_rename);
1335+ return original_security_ops.inode_rename(old_dir, old_dentry, old_mnt,
1336+ new_dir, new_dentry,
1337+ new_mnt);
1338+}
1339+
1340+/**
1341+ * ccs_inode_link - Check permission for link().
1342+ *
1343+ * @old_dentry: Pointer to "struct dentry".
1344+ * @old_mnt: Pointer to "struct vfsmount". Maybe NULL.
1345+ * @dir: Pointer to "struct inode".
1346+ * @new_dentry: Pointer to "struct dentry".
1347+ * @new_mnt: Pointer to "struct vfsmount". Maybe NULL.
1348+ *
1349+ * Returns 0 on success, negative value otherwise.
1350+ */
1351+static int ccs_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
1352+ struct inode *dir, struct dentry *new_dentry,
1353+ struct vfsmount *new_mnt)
1354+{
1355+ int rc = ccs_link_permission(old_dentry, new_dentry, new_mnt);
1356+ if (rc)
1357+ return rc;
1358+ while (!original_security_ops.inode_link);
1359+ return original_security_ops.inode_link(old_dentry, old_mnt, dir,
1360+ new_dentry, new_mnt);
1361+}
1362+
1363+/**
1364+ * ccs_inode_create - Check permission for creat().
1365+ *
1366+ * @dir: Pointer to "struct inode".
1367+ * @dentry: Pointer to "struct dentry".
1368+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1369+ * @mode: Create mode.
1370+ *
1371+ * Returns 0 on success, negative value otherwise.
1372+ */
1373+static int ccs_inode_create(struct inode *dir, struct dentry *dentry,
1374+ struct vfsmount *mnt, int mode)
1375+{
1376+ int rc = ccs_mknod_permission(dentry, mnt, mode, 0);
1377+ if (rc)
1378+ return rc;
1379+ while (!original_security_ops.inode_create);
1380+ return original_security_ops.inode_create(dir, dentry, mnt, mode);
1381+}
1382+
1383+#else
1384+
1385+#if defined(USE_UMODE_T)
1386+
1387+/**
1388+ * ccs_inode_mknod - Check permission for mknod().
1389+ *
1390+ * @dir: Pointer to "struct inode".
1391+ * @dentry: Pointer to "struct dentry".
1392+ * @mode: Create mode.
1393+ * @dev: Device major/minor number.
1394+ *
1395+ * Returns 0 on success, negative value otherwise.
1396+ */
1397+static int ccs_inode_mknod(struct inode *dir, struct dentry *dentry,
1398+ umode_t mode, dev_t dev)
1399+{
1400+ int rc = ccs_mknod_permission(dentry, NULL, mode, dev);
1401+ if (rc)
1402+ return rc;
1403+ while (!original_security_ops.inode_mknod);
1404+ return original_security_ops.inode_mknod(dir, dentry, mode, dev);
1405+}
1406+
1407+/**
1408+ * ccs_inode_mkdir - Check permission for mkdir().
1409+ *
1410+ * @dir: Pointer to "struct inode".
1411+ * @dentry: Pointer to "struct dentry".
1412+ * @mode: Create mode.
1413+ *
1414+ * Returns 0 on success, negative value otherwise.
1415+ */
1416+static int ccs_inode_mkdir(struct inode *dir, struct dentry *dentry,
1417+ umode_t mode)
1418+{
1419+ int rc = ccs_mkdir_permission(dentry, NULL, mode);
1420+ if (rc)
1421+ return rc;
1422+ while (!original_security_ops.inode_mkdir);
1423+ return original_security_ops.inode_mkdir(dir, dentry, mode);
1424+}
1425+
1426+#else
1427+
1428+/**
1429+ * ccs_inode_mknod - Check permission for mknod().
1430+ *
1431+ * @dir: Pointer to "struct inode".
1432+ * @dentry: Pointer to "struct dentry".
1433+ * @mode: Create mode.
1434+ * @dev: Device major/minor number.
1435+ *
1436+ * Returns 0 on success, negative value otherwise.
1437+ */
1438+static int ccs_inode_mknod(struct inode *dir, struct dentry *dentry, int mode,
1439+ dev_t dev)
1440+{
1441+ int rc = ccs_mknod_permission(dentry, NULL, mode, dev);
1442+ if (rc)
1443+ return rc;
1444+ while (!original_security_ops.inode_mknod);
1445+ return original_security_ops.inode_mknod(dir, dentry, mode, dev);
1446+}
1447+
1448+/**
1449+ * ccs_inode_mkdir - Check permission for mkdir().
1450+ *
1451+ * @dir: Pointer to "struct inode".
1452+ * @dentry: Pointer to "struct dentry".
1453+ * @mode: Create mode.
1454+ *
1455+ * Returns 0 on success, negative value otherwise.
1456+ */
1457+static int ccs_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1458+{
1459+ int rc = ccs_mkdir_permission(dentry, NULL, mode);
1460+ if (rc)
1461+ return rc;
1462+ while (!original_security_ops.inode_mkdir);
1463+ return original_security_ops.inode_mkdir(dir, dentry, mode);
1464+}
1465+
1466+#endif
1467+
1468+/**
1469+ * ccs_inode_rmdir - Check permission for rmdir().
1470+ *
1471+ * @dir: Pointer to "struct inode".
1472+ * @dentry: Pointer to "struct dentry".
1473+ *
1474+ * Returns 0 on success, negative value otherwise.
1475+ */
1476+static int ccs_inode_rmdir(struct inode *dir, struct dentry *dentry)
1477+{
1478+ int rc = ccs_rmdir_permission(dentry, NULL);
1479+ if (rc)
1480+ return rc;
1481+ while (!original_security_ops.inode_rmdir);
1482+ return original_security_ops.inode_rmdir(dir, dentry);
1483+}
1484+
1485+/**
1486+ * ccs_inode_unlink - Check permission for unlink().
1487+ *
1488+ * @dir: Pointer to "struct inode".
1489+ * @dentry: Pointer to "struct dentry".
1490+ *
1491+ * Returns 0 on success, negative value otherwise.
1492+ */
1493+static int ccs_inode_unlink(struct inode *dir, struct dentry *dentry)
1494+{
1495+ int rc = ccs_unlink_permission(dentry, NULL);
1496+ if (rc)
1497+ return rc;
1498+ while (!original_security_ops.inode_unlink);
1499+ return original_security_ops.inode_unlink(dir, dentry);
1500+}
1501+
1502+/**
1503+ * ccs_inode_symlink - Check permission for symlink().
1504+ *
1505+ * @dir: Pointer to "struct inode".
1506+ * @dentry: Pointer to "struct dentry".
1507+ * @old_name: Content of symbolic link.
1508+ *
1509+ * Returns 0 on success, negative value otherwise.
1510+ */
1511+static int ccs_inode_symlink(struct inode *dir, struct dentry *dentry,
1512+ const char *old_name)
1513+{
1514+ int rc = ccs_symlink_permission(dentry, NULL, old_name);
1515+ if (rc)
1516+ return rc;
1517+ while (!original_security_ops.inode_symlink);
1518+ return original_security_ops.inode_symlink(dir, dentry, old_name);
1519+}
1520+
1521+/**
1522+ * ccs_inode_rename - Check permission for rename().
1523+ *
1524+ * @old_dir: Pointer to "struct inode".
1525+ * @old_dentry: Pointer to "struct dentry".
1526+ * @new_dir: Pointer to "struct inode".
1527+ * @new_dentry: Pointer to "struct dentry".
1528+ *
1529+ * Returns 0 on success, negative value otherwise.
1530+ */
1531+static int ccs_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
1532+ struct inode *new_dir, struct dentry *new_dentry)
1533+{
1534+ int rc = ccs_rename_permission(old_dentry, new_dentry, NULL);
1535+ if (rc)
1536+ return rc;
1537+ while (!original_security_ops.inode_rename);
1538+ return original_security_ops.inode_rename(old_dir, old_dentry, new_dir,
1539+ new_dentry);
1540+}
1541+
1542+/**
1543+ * ccs_inode_link - Check permission for link().
1544+ *
1545+ * @old_dentry: Pointer to "struct dentry".
1546+ * @dir: Pointer to "struct inode".
1547+ * @new_dentry: Pointer to "struct dentry".
1548+ *
1549+ * Returns 0 on success, negative value otherwise.
1550+ */
1551+static int ccs_inode_link(struct dentry *old_dentry, struct inode *dir,
1552+ struct dentry *new_dentry)
1553+{
1554+ int rc = ccs_link_permission(old_dentry, new_dentry, NULL);
1555+ if (rc)
1556+ return rc;
1557+ while (!original_security_ops.inode_link);
1558+ return original_security_ops.inode_link(old_dentry, dir, new_dentry);
1559+}
1560+
1561+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
1562+
1563+/**
1564+ * ccs_inode_create - Check permission for creat().
1565+ *
1566+ * @dir: Pointer to "struct inode".
1567+ * @dentry: Pointer to "struct dentry".
1568+ * @mode: Create mode.
1569+ *
1570+ * Returns 0 on success, negative value otherwise.
1571+ */
1572+static int ccs_inode_create(struct inode *dir, struct dentry *dentry,
1573+ umode_t mode)
1574+{
1575+ int rc = ccs_mknod_permission(dentry, NULL, mode, 0);
1576+ if (rc)
1577+ return rc;
1578+ while (!original_security_ops.inode_create);
1579+ return original_security_ops.inode_create(dir, dentry, mode);
1580+}
1581+
1582+#else
1583+
1584+/**
1585+ * ccs_inode_create - Check permission for creat().
1586+ *
1587+ * @dir: Pointer to "struct inode".
1588+ * @dentry: Pointer to "struct dentry".
1589+ * @mode: Create mode.
1590+ *
1591+ * Returns 0 on success, negative value otherwise.
1592+ */
1593+static int ccs_inode_create(struct inode *dir, struct dentry *dentry,
1594+ int mode)
1595+{
1596+ int rc = ccs_mknod_permission(dentry, NULL, mode, 0);
1597+ if (rc)
1598+ return rc;
1599+ while (!original_security_ops.inode_create);
1600+ return original_security_ops.inode_create(dir, dentry, mode);
1601+}
1602+
1603+#endif
1604+
1605+#endif
1606+
1607+#ifdef CONFIG_SECURITY_NETWORK
1608+
1609+#include <net/sock.h>
1610+
1611+/* Structure for remembering an accept()ed socket's status. */
1612+struct ccs_socket_tag {
1613+ struct list_head list;
1614+ struct inode *inode;
1615+ int status;
1616+ struct rcu_head rcu;
1617+};
1618+
1619+/*
1620+ * List for managing accept()ed sockets.
1621+ * Since we don't need to keep an accept()ed socket into this list after
1622+ * once the permission was granted, the number of entries in this list is
1623+ * likely small. Therefore, we don't use hash tables.
1624+ */
1625+static LIST_HEAD(ccs_accepted_socket_list);
1626+/* Lock for protecting ccs_accepted_socket_list . */
1627+static DEFINE_SPINLOCK(ccs_accepted_socket_list_lock);
1628+
1629+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
1630+
1631+/**
1632+ * ccs_socket_rcu_free - RCU callback for releasing "struct ccs_socket_tag".
1633+ *
1634+ * @rcu: Pointer to "struct rcu_head".
1635+ *
1636+ * Returns nothing.
1637+ */
1638+static void ccs_socket_rcu_free(struct rcu_head *rcu)
1639+{
1640+ struct ccs_socket_tag *ptr = container_of(rcu, typeof(*ptr), rcu);
1641+ kfree(ptr);
1642+}
1643+
1644+#else
1645+
1646+/**
1647+ * ccs_socket_rcu_free - RCU callback for releasing "struct ccs_socket_tag".
1648+ *
1649+ * @arg: Pointer to "void".
1650+ *
1651+ * Returns nothing.
1652+ */
1653+static void ccs_socket_rcu_free(void *arg)
1654+{
1655+ struct ccs_socket_tag *ptr = arg;
1656+ kfree(ptr);
1657+}
1658+
1659+#endif
1660+
1661+/**
1662+ * ccs_update_socket_tag - Update tag associated with accept()ed sockets.
1663+ *
1664+ * @inode: Pointer to "struct inode".
1665+ * @status: New status.
1666+ *
1667+ * Returns nothing.
1668+ *
1669+ * If @status == 0, memory for that socket will be released after RCU grace
1670+ * period.
1671+ */
1672+static void ccs_update_socket_tag(struct inode *inode, int status)
1673+{
1674+ struct ccs_socket_tag *ptr;
1675+ /*
1676+ * Protect whole section because multiple threads may call this
1677+ * function with same "sock" via ccs_validate_socket().
1678+ */
1679+ spin_lock(&ccs_accepted_socket_list_lock);
1680+ rcu_read_lock();
1681+ list_for_each_entry_rcu(ptr, &ccs_accepted_socket_list, list) {
1682+ if (ptr->inode != inode)
1683+ continue;
1684+ ptr->status = status;
1685+ if (status)
1686+ break;
1687+ list_del_rcu(&ptr->list);
1688+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
1689+ call_rcu(&ptr->rcu, ccs_socket_rcu_free);
1690+#else
1691+ call_rcu(&ptr->rcu, ccs_socket_rcu_free, ptr);
1692+#endif
1693+ break;
1694+ }
1695+ rcu_read_unlock();
1696+ spin_unlock(&ccs_accepted_socket_list_lock);
1697+}
1698+
1699+/**
1700+ * ccs_validate_socket - Check post accept() permission if needed.
1701+ *
1702+ * @sock: Pointer to "struct socket".
1703+ *
1704+ * Returns 0 on success, negative value otherwise.
1705+ */
1706+static int ccs_validate_socket(struct socket *sock)
1707+{
1708+ struct inode *inode = SOCK_INODE(sock);
1709+ struct ccs_socket_tag *ptr;
1710+ int ret = 0;
1711+ rcu_read_lock();
1712+ list_for_each_entry_rcu(ptr, &ccs_accepted_socket_list, list) {
1713+ if (ptr->inode != inode)
1714+ continue;
1715+ ret = ptr->status;
1716+ break;
1717+ }
1718+ rcu_read_unlock();
1719+ if (ret <= 0)
1720+ /*
1721+ * This socket is not an accept()ed socket or this socket is
1722+ * an accept()ed socket and post accept() permission is done.
1723+ */
1724+ return ret;
1725+ /*
1726+ * Check post accept() permission now.
1727+ *
1728+ * Strictly speaking, we need to pass both listen()ing socket and
1729+ * accept()ed socket to __ccs_socket_post_accept_permission().
1730+ * But since socket's family and type are same for both sockets,
1731+ * passing the accept()ed socket in place for the listen()ing socket
1732+ * will work.
1733+ */
1734+ ret = ccs_socket_post_accept_permission(sock, sock);
1735+ /*
1736+ * If permission was granted, we forget that this is an accept()ed
1737+ * socket. Otherwise, we remember that this socket needs to return
1738+ * error for subsequent socketcalls.
1739+ */
1740+ ccs_update_socket_tag(inode, ret);
1741+ return ret;
1742+}
1743+
1744+/**
1745+ * ccs_socket_accept - Check permission for accept().
1746+ *
1747+ * @sock: Pointer to "struct socket".
1748+ * @newsock: Pointer to "struct socket".
1749+ *
1750+ * Returns 0 on success, negative value otherwise.
1751+ *
1752+ * This hook is used for setting up environment for doing post accept()
1753+ * permission check. If dereferencing sock->ops->something() were ordered by
1754+ * rcu_dereference(), we could replace sock->ops with "a copy of original
1755+ * sock->ops with modified sock->ops->accept()" using rcu_assign_pointer()
1756+ * in order to do post accept() permission check before returning to userspace.
1757+ * If we make the copy in security_socket_post_create(), it would be possible
1758+ * to safely replace sock->ops here, but we don't do so because we don't want
1759+ * to allocate memory for sockets which do not call sock->ops->accept().
1760+ * Therefore, we do post accept() permission check upon next socket syscalls
1761+ * rather than between sock->ops->accept() and returning to userspace.
1762+ * This means that if a socket was close()d before calling some socket
1763+ * syscalls, post accept() permission check will not be done.
1764+ */
1765+static int ccs_socket_accept(struct socket *sock, struct socket *newsock)
1766+{
1767+ struct ccs_socket_tag *ptr;
1768+ int rc = ccs_validate_socket(sock);
1769+ if (rc < 0)
1770+ return rc;
1771+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
1772+ if (!ptr)
1773+ return -ENOMEM;
1774+ while (!original_security_ops.socket_accept);
1775+ rc = original_security_ops.socket_accept(sock, newsock);
1776+ if (rc) {
1777+ kfree(ptr);
1778+ return rc;
1779+ }
1780+ /*
1781+ * Subsequent LSM hooks will receive "newsock". Therefore, I mark
1782+ * "newsock" as "an accept()ed socket but post accept() permission
1783+ * check is not done yet" by allocating memory using inode of the
1784+ * "newsock" as a search key.
1785+ */
1786+ ptr->inode = SOCK_INODE(newsock);
1787+ ptr->status = 1; /* Check post accept() permission later. */
1788+ spin_lock(&ccs_accepted_socket_list_lock);
1789+ list_add_tail_rcu(&ptr->list, &ccs_accepted_socket_list);
1790+ spin_unlock(&ccs_accepted_socket_list_lock);
1791+ return 0;
1792+}
1793+
1794+/**
1795+ * ccs_socket_listen - Check permission for listen().
1796+ *
1797+ * @sock: Pointer to "struct socket".
1798+ * @backlog: Backlog parameter.
1799+ *
1800+ * Returns 0 on success, negative value otherwise.
1801+ */
1802+static int ccs_socket_listen(struct socket *sock, int backlog)
1803+{
1804+ int rc = ccs_validate_socket(sock);
1805+ if (rc < 0)
1806+ return rc;
1807+ rc = ccs_socket_listen_permission(sock);
1808+ if (rc)
1809+ return rc;
1810+ while (!original_security_ops.socket_listen);
1811+ return original_security_ops.socket_listen(sock, backlog);
1812+}
1813+
1814+/**
1815+ * ccs_socket_connect - Check permission for connect().
1816+ *
1817+ * @sock: Pointer to "struct socket".
1818+ * @addr: Pointer to "struct sockaddr".
1819+ * @addr_len: Size of @addr.
1820+ *
1821+ * Returns 0 on success, negative value otherwise.
1822+ */
1823+static int ccs_socket_connect(struct socket *sock, struct sockaddr *addr,
1824+ int addr_len)
1825+{
1826+ int rc = ccs_validate_socket(sock);
1827+ if (rc < 0)
1828+ return rc;
1829+ rc = ccs_socket_connect_permission(sock, addr, addr_len);
1830+ if (rc)
1831+ return rc;
1832+ while (!original_security_ops.socket_connect);
1833+ return original_security_ops.socket_connect(sock, addr, addr_len);
1834+}
1835+
1836+/**
1837+ * ccs_socket_bind - Check permission for bind().
1838+ *
1839+ * @sock: Pointer to "struct socket".
1840+ * @addr: Pointer to "struct sockaddr".
1841+ * @addr_len: Size of @addr.
1842+ *
1843+ * Returns 0 on success, negative value otherwise.
1844+ */
1845+static int ccs_socket_bind(struct socket *sock, struct sockaddr *addr,
1846+ int addr_len)
1847+{
1848+ int rc = ccs_validate_socket(sock);
1849+ if (rc < 0)
1850+ return rc;
1851+ rc = ccs_socket_bind_permission(sock, addr, addr_len);
1852+ if (rc)
1853+ return rc;
1854+ while (!original_security_ops.socket_bind);
1855+ return original_security_ops.socket_bind(sock, addr, addr_len);
1856+}
1857+
1858+/**
1859+ * ccs_socket_sendmsg - Check permission for sendmsg().
1860+ *
1861+ * @sock: Pointer to "struct socket".
1862+ * @msg: Pointer to "struct msghdr".
1863+ * @size: Size of message.
1864+ *
1865+ * Returns 0 on success, negative value otherwise.
1866+ */
1867+static int ccs_socket_sendmsg(struct socket *sock, struct msghdr *msg,
1868+ int size)
1869+{
1870+ int rc = ccs_validate_socket(sock);
1871+ if (rc < 0)
1872+ return rc;
1873+ rc = ccs_socket_sendmsg_permission(sock, msg, size);
1874+ if (rc)
1875+ return rc;
1876+ while (!original_security_ops.socket_sendmsg);
1877+ return original_security_ops.socket_sendmsg(sock, msg, size);
1878+}
1879+
1880+/**
1881+ * ccs_socket_recvmsg - Check permission for recvmsg().
1882+ *
1883+ * @sock: Pointer to "struct socket".
1884+ * @msg: Pointer to "struct msghdr".
1885+ * @size: Size of message.
1886+ * @flags: Flags.
1887+ *
1888+ * Returns 0 on success, negative value otherwise.
1889+ */
1890+static int ccs_socket_recvmsg(struct socket *sock, struct msghdr *msg,
1891+ int size, int flags)
1892+{
1893+ int rc = ccs_validate_socket(sock);
1894+ if (rc < 0)
1895+ return rc;
1896+ while (!original_security_ops.socket_recvmsg);
1897+ return original_security_ops.socket_recvmsg(sock, msg, size, flags);
1898+}
1899+
1900+/**
1901+ * ccs_socket_getsockname - Check permission for getsockname().
1902+ *
1903+ * @sock: Pointer to "struct socket".
1904+ *
1905+ * Returns 0 on success, negative value otherwise.
1906+ */
1907+static int ccs_socket_getsockname(struct socket *sock)
1908+{
1909+ int rc = ccs_validate_socket(sock);
1910+ if (rc < 0)
1911+ return rc;
1912+ while (!original_security_ops.socket_getsockname);
1913+ return original_security_ops.socket_getsockname(sock);
1914+}
1915+
1916+/**
1917+ * ccs_socket_getpeername - Check permission for getpeername().
1918+ *
1919+ * @sock: Pointer to "struct socket".
1920+ *
1921+ * Returns 0 on success, negative value otherwise.
1922+ */
1923+static int ccs_socket_getpeername(struct socket *sock)
1924+{
1925+ int rc = ccs_validate_socket(sock);
1926+ if (rc < 0)
1927+ return rc;
1928+ while (!original_security_ops.socket_getpeername);
1929+ return original_security_ops.socket_getpeername(sock);
1930+}
1931+
1932+/**
1933+ * ccs_socket_getsockopt - Check permission for getsockopt().
1934+ *
1935+ * @sock: Pointer to "struct socket".
1936+ * @level: Level.
1937+ * @optname: Option's name,
1938+ *
1939+ * Returns 0 on success, negative value otherwise.
1940+ */
1941+static int ccs_socket_getsockopt(struct socket *sock, int level, int optname)
1942+{
1943+ int rc = ccs_validate_socket(sock);
1944+ if (rc < 0)
1945+ return rc;
1946+ while (!original_security_ops.socket_getsockopt);
1947+ return original_security_ops.socket_getsockopt(sock, level, optname);
1948+}
1949+
1950+/**
1951+ * ccs_socket_setsockopt - Check permission for setsockopt().
1952+ *
1953+ * @sock: Pointer to "struct socket".
1954+ * @level: Level.
1955+ * @optname: Option's name,
1956+ *
1957+ * Returns 0 on success, negative value otherwise.
1958+ */
1959+static int ccs_socket_setsockopt(struct socket *sock, int level, int optname)
1960+{
1961+ int rc = ccs_validate_socket(sock);
1962+ if (rc < 0)
1963+ return rc;
1964+ while (!original_security_ops.socket_setsockopt);
1965+ return original_security_ops.socket_setsockopt(sock, level, optname);
1966+}
1967+
1968+/**
1969+ * ccs_socket_shutdown - Check permission for shutdown().
1970+ *
1971+ * @sock: Pointer to "struct socket".
1972+ * @how: Shutdown mode.
1973+ *
1974+ * Returns 0 on success, negative value otherwise.
1975+ */
1976+static int ccs_socket_shutdown(struct socket *sock, int how)
1977+{
1978+ int rc = ccs_validate_socket(sock);
1979+ if (rc < 0)
1980+ return rc;
1981+ while (!original_security_ops.socket_shutdown);
1982+ return original_security_ops.socket_shutdown(sock, how);
1983+}
1984+
1985+#define SOCKFS_MAGIC 0x534F434B
1986+
1987+/**
1988+ * ccs_inode_free_security - Release memory associated with an inode.
1989+ *
1990+ * @inode: Pointer to "struct inode".
1991+ *
1992+ * Returns nothing.
1993+ *
1994+ * We use this hook for releasing memory associated with an accept()ed socket.
1995+ */
1996+static void ccs_inode_free_security(struct inode *inode)
1997+{
1998+ while (!original_security_ops.inode_free_security);
1999+ original_security_ops.inode_free_security(inode);
2000+ if (inode->i_sb && inode->i_sb->s_magic == SOCKFS_MAGIC)
2001+ ccs_update_socket_tag(inode, 0);
2002+}
2003+
2004+#endif
2005+
2006+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
2007+
2008+/**
2009+ * ccs_sb_pivotroot - Check permission for pivot_root().
2010+ *
2011+ * @old_nd: Pointer to "struct nameidata".
2012+ * @new_nd: Pointer to "struct nameidata".
2013+ *
2014+ * Returns 0 on success, negative value otherwise.
2015+ */
2016+static int ccs_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd)
2017+{
2018+ int rc = ccs_pivot_root_permission(old_nd, new_nd);
2019+ if (rc)
2020+ return rc;
2021+ while (!original_security_ops.sb_pivotroot);
2022+ return original_security_ops.sb_pivotroot(old_nd, new_nd);
2023+}
2024+
2025+/**
2026+ * ccs_sb_mount - Check permission for mount().
2027+ *
2028+ * @dev_name: Name of device file.
2029+ * @nd: Pointer to "struct nameidata".
2030+ * @type: Name of filesystem type. Maybe NULL.
2031+ * @flags: Mount options.
2032+ * @data_page: Optional data. Maybe NULL.
2033+ *
2034+ * Returns 0 on success, negative value otherwise.
2035+ */
2036+static int ccs_sb_mount(char *dev_name, struct nameidata *nd, char *type,
2037+ unsigned long flags, void *data_page)
2038+{
2039+ int rc = ccs_mount_permission(dev_name, nd, type, flags, data_page);
2040+ if (rc)
2041+ return rc;
2042+ while (!original_security_ops.sb_mount);
2043+ return original_security_ops.sb_mount(dev_name, nd, type, flags,
2044+ data_page);
2045+}
2046+
2047+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
2048+
2049+/**
2050+ * ccs_sb_pivotroot - Check permission for pivot_root().
2051+ *
2052+ * @old_nd: Pointer to "struct nameidata".
2053+ * @new_nd: Pointer to "struct nameidata".
2054+ *
2055+ * Returns 0 on success, negative value otherwise.
2056+ */
2057+static int ccs_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd)
2058+{
2059+ int rc = ccs_pivot_root_permission(&old_nd->path, &new_nd->path);
2060+ if (rc)
2061+ return rc;
2062+ while (!original_security_ops.sb_pivotroot);
2063+ return original_security_ops.sb_pivotroot(old_nd, new_nd);
2064+}
2065+
2066+/**
2067+ * ccs_sb_mount - Check permission for mount().
2068+ *
2069+ * @dev_name: Name of device file.
2070+ * @nd: Pointer to "struct nameidata".
2071+ * @type: Name of filesystem type. Maybe NULL.
2072+ * @flags: Mount options.
2073+ * @data_page: Optional data. Maybe NULL.
2074+ *
2075+ * Returns 0 on success, negative value otherwise.
2076+ */
2077+static int ccs_sb_mount(char *dev_name, struct nameidata *nd, char *type,
2078+ unsigned long flags, void *data_page)
2079+{
2080+ int rc = ccs_mount_permission(dev_name, &nd->path, type, flags,
2081+ data_page);
2082+ if (rc)
2083+ return rc;
2084+ while (!original_security_ops.sb_mount);
2085+ return original_security_ops.sb_mount(dev_name, nd, type, flags,
2086+ data_page);
2087+}
2088+
2089+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
2090+
2091+/**
2092+ * ccs_sb_pivotroot - Check permission for pivot_root().
2093+ *
2094+ * @old_path: Pointer to "struct path".
2095+ * @new_path: Pointer to "struct path".
2096+ *
2097+ * Returns 0 on success, negative value otherwise.
2098+ */
2099+static int ccs_sb_pivotroot(struct path *old_path, struct path *new_path)
2100+{
2101+ int rc = ccs_pivot_root_permission(old_path, new_path);
2102+ if (rc)
2103+ return rc;
2104+ while (!original_security_ops.sb_pivotroot);
2105+ return original_security_ops.sb_pivotroot(old_path, new_path);
2106+}
2107+
2108+/**
2109+ * ccs_sb_mount - Check permission for mount().
2110+ *
2111+ * @dev_name: Name of device file.
2112+ * @path: Pointer to "struct path".
2113+ * @type: Name of filesystem type. Maybe NULL.
2114+ * @flags: Mount options.
2115+ * @data_page: Optional data. Maybe NULL.
2116+ *
2117+ * Returns 0 on success, negative value otherwise.
2118+ */
2119+static int ccs_sb_mount(char *dev_name, struct path *path, char *type,
2120+ unsigned long flags, void *data_page)
2121+{
2122+ int rc = ccs_mount_permission(dev_name, path, type, flags, data_page);
2123+ if (rc)
2124+ return rc;
2125+ while (!original_security_ops.sb_mount);
2126+ return original_security_ops.sb_mount(dev_name, path, type, flags,
2127+ data_page);
2128+}
2129+
2130+#else
2131+
2132+/**
2133+ * ccs_sb_pivotroot - Check permission for pivot_root().
2134+ *
2135+ * @old_path: Pointer to "struct path".
2136+ * @new_path: Pointer to "struct path".
2137+ *
2138+ * Returns 0 on success, negative value otherwise.
2139+ */
2140+static int ccs_sb_pivotroot(struct path *old_path, struct path *new_path)
2141+{
2142+ int rc = ccs_pivot_root_permission(old_path, new_path);
2143+ if (rc)
2144+ return rc;
2145+ while (!original_security_ops.sb_pivotroot);
2146+ return original_security_ops.sb_pivotroot(old_path, new_path);
2147+}
2148+
2149+/**
2150+ * ccs_sb_mount - Check permission for mount().
2151+ *
2152+ * @dev_name: Name of device file.
2153+ * @path: Pointer to "struct path".
2154+ * @type: Name of filesystem type. Maybe NULL.
2155+ * @flags: Mount options.
2156+ * @data_page: Optional data. Maybe NULL.
2157+ *
2158+ * Returns 0 on success, negative value otherwise.
2159+ */
2160+static int ccs_sb_mount(const char *dev_name, struct path *path,
2161+ const char *type, unsigned long flags, void *data_page)
2162+{
2163+ int rc = ccs_mount_permission(dev_name, path, type, flags, data_page);
2164+ if (rc)
2165+ return rc;
2166+ while (!original_security_ops.sb_mount);
2167+ return original_security_ops.sb_mount(dev_name, path, type, flags,
2168+ data_page);
2169+}
2170+
2171+#endif
2172+
2173+/**
2174+ * ccs_sb_umount - Check permission for umount().
2175+ *
2176+ * @mnt: Pointer to "struct vfsmount".
2177+ * @flags: Unmount flags.
2178+ *
2179+ * Returns 0 on success, negative value otherwise.
2180+ */
2181+static int ccs_sb_umount(struct vfsmount *mnt, int flags)
2182+{
2183+ int rc = ccs_umount_permission(mnt, flags);
2184+ if (rc)
2185+ return rc;
2186+ while (!original_security_ops.sb_umount);
2187+ return original_security_ops.sb_umount(mnt, flags);
2188+}
2189+
2190+/**
2191+ * ccs_file_fcntl - Check permission for fcntl().
2192+ *
2193+ * @file: Pointer to "struct file".
2194+ * @cmd: Command number.
2195+ * @arg: Value for @cmd.
2196+ *
2197+ * Returns 0 on success, negative value otherwise.
2198+ */
2199+static int ccs_file_fcntl(struct file *file, unsigned int cmd,
2200+ unsigned long arg)
2201+{
2202+ int rc = ccs_fcntl_permission(file, cmd, arg);
2203+ if (rc)
2204+ return rc;
2205+ while (!original_security_ops.file_fcntl);
2206+ return original_security_ops.file_fcntl(file, cmd, arg);
2207+}
2208+
2209+/**
2210+ * ccs_file_ioctl - Check permission for ioctl().
2211+ *
2212+ * @filp: Pointer to "struct file".
2213+ * @cmd: Command number.
2214+ * @arg: Value for @cmd.
2215+ *
2216+ * Returns 0 on success, negative value otherwise.
2217+ */
2218+static int ccs_file_ioctl(struct file *filp, unsigned int cmd,
2219+ unsigned long arg)
2220+{
2221+ int rc = ccs_ioctl_permission(filp, cmd, arg);
2222+ if (rc)
2223+ return rc;
2224+ while (!original_security_ops.file_ioctl);
2225+ return original_security_ops.file_ioctl(filp, cmd, arg);
2226+}
2227+
2228+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
2229+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
2230+ const struct ccs_path_info *filename);
2231+
2232+/**
2233+ * ccs_prepend - Copy of prepend() in fs/dcache.c.
2234+ *
2235+ * @buffer: Pointer to "struct char *".
2236+ * @buflen: Pointer to int which holds size of @buffer.
2237+ * @str: String to copy.
2238+ *
2239+ * Returns 0 on success, negative value otherwise.
2240+ *
2241+ * @buffer and @buflen are updated upon success.
2242+ */
2243+static int ccs_prepend(char **buffer, int *buflen, const char *str)
2244+{
2245+ int namelen = strlen(str);
2246+ if (*buflen < namelen)
2247+ return -ENOMEM;
2248+ *buflen -= namelen;
2249+ *buffer -= namelen;
2250+ memcpy(*buffer, str, namelen);
2251+ return 0;
2252+}
2253+
2254+/**
2255+ * ccs_sysctl_permission - Check permission for sysctl().
2256+ *
2257+ * @table: Pointer to "struct ctl_table".
2258+ * @op: Operation. (MAY_READ and/or MAY_WRITE)
2259+ *
2260+ * Returns 0 on success, negative value otherwise.
2261+ */
2262+static int ccs_sysctl(struct ctl_table *table, int op)
2263+{
2264+ int error;
2265+ struct ccs_path_info buf;
2266+ struct ccs_request_info r;
2267+ int buflen;
2268+ char *buffer;
2269+ int idx;
2270+ while (!original_security_ops.sysctl);
2271+ error = original_security_ops.sysctl(table, op);
2272+ if (error)
2273+ return error;
2274+ op &= MAY_READ | MAY_WRITE;
2275+ if (!op)
2276+ return 0;
2277+ buffer = NULL;
2278+ buf.name = NULL;
2279+ idx = ccs_read_lock();
2280+ if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2281+ == CCS_CONFIG_DISABLED)
2282+ goto out;
2283+ error = -ENOMEM;
2284+ buflen = 4096;
2285+ buffer = kmalloc(buflen, CCS_GFP_FLAGS);
2286+ if (buffer) {
2287+ char *end = buffer + buflen;
2288+ *--end = '\0';
2289+ buflen--;
2290+ while (table) {
2291+ char num[32];
2292+ const char *sp = table->procname;
2293+ if (!sp) {
2294+ memset(num, 0, sizeof(num));
2295+ snprintf(num, sizeof(num) - 1, "=%d=",
2296+ table->ctl_name);
2297+ sp = num;
2298+ }
2299+ if (ccs_prepend(&end, &buflen, sp) ||
2300+ ccs_prepend(&end, &buflen, "/"))
2301+ goto out;
2302+ table = table->parent;
2303+ }
2304+ if (ccs_prepend(&end, &buflen, "proc:/sys"))
2305+ goto out;
2306+ buf.name = ccs_encode(end);
2307+ }
2308+ if (buf.name) {
2309+ ccs_fill_path_info(&buf);
2310+ if (op & MAY_READ)
2311+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
2312+ else
2313+ error = 0;
2314+ if (!error && (op & MAY_WRITE))
2315+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
2316+ }
2317+out:
2318+ ccs_read_unlock(idx);
2319+ kfree(buf.name);
2320+ kfree(buffer);
2321+ return error;
2322+}
2323+
2324+#endif
2325+
2326+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2327+
2328+#include <linux/mount.h>
2329+#include <linux/fs_struct.h>
2330+
2331+/**
2332+ * ccs_kernel_read - Wrapper for kernel_read().
2333+ *
2334+ * @file: Pointer to "struct file".
2335+ * @offset: Starting position.
2336+ * @addr: Buffer.
2337+ * @count: Size of @addr.
2338+ *
2339+ * Returns return value from kernel_read().
2340+ */
2341+static int __init ccs_kernel_read(struct file *file, unsigned long offset,
2342+ char *addr, unsigned long count)
2343+{
2344+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
2345+ /*
2346+ * I can't use kernel_read() because seq_read() returns -EPIPE
2347+ * if &pos != &file->f_pos .
2348+ */
2349+ mm_segment_t old_fs;
2350+ unsigned long pos = file->f_pos;
2351+ int result;
2352+ file->f_pos = offset;
2353+ old_fs = get_fs();
2354+ set_fs(get_ds());
2355+ result = vfs_read(file, (void __user *)addr, count, &file->f_pos);
2356+ set_fs(old_fs);
2357+ file->f_pos = pos;
2358+ return result;
2359+#else
2360+ return kernel_read(file, offset, addr, count);
2361+#endif
2362+}
2363+
2364+/**
2365+ * ccs_find_symbol - Find function's address from /proc/kallsyms .
2366+ *
2367+ * @keyline: Function to find.
2368+ *
2369+ * Returns address of specified function on success, NULL otherwise.
2370+ */
2371+static void *__init ccs_find_symbol(const char *keyline)
2372+{
2373+ struct file *file = NULL;
2374+ char *buf;
2375+ unsigned long entry = 0;
2376+ {
2377+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
2378+ struct file_system_type *fstype = get_fs_type("proc");
2379+ struct vfsmount *mnt = vfs_kern_mount(fstype, 0, "proc", NULL);
2380+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
2381+ struct file_system_type *fstype = NULL;
2382+ struct vfsmount *mnt = do_kern_mount("proc", 0, "proc", NULL);
2383+#else
2384+ struct file_system_type *fstype = get_fs_type("proc");
2385+ struct vfsmount *mnt = kern_mount(fstype);
2386+#endif
2387+ struct dentry *root;
2388+ struct dentry *dentry;
2389+ /*
2390+ * We embed put_filesystem() here because it is not exported.
2391+ */
2392+ if (fstype)
2393+ module_put(fstype->owner);
2394+ if (IS_ERR(mnt))
2395+ goto out;
2396+ root = dget(mnt->mnt_root);
2397+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
2398+ mutex_lock(&root->d_inode->i_mutex);
2399+ dentry = lookup_one_len("kallsyms", root, 8);
2400+ mutex_unlock(&root->d_inode->i_mutex);
2401+#else
2402+ down(&root->d_inode->i_sem);
2403+ dentry = lookup_one_len("kallsyms", root, 8);
2404+ up(&root->d_inode->i_sem);
2405+#endif
2406+ dput(root);
2407+ if (IS_ERR(dentry))
2408+ mntput(mnt);
2409+ else {
2410+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
2411+ struct path path = { mnt, dentry };
2412+ file = dentry_open(&path, O_RDONLY, current_cred());
2413+#else
2414+ file = dentry_open(dentry, mnt, O_RDONLY
2415+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2416+ , current_cred()
2417+#endif
2418+ );
2419+#endif
2420+ }
2421+ }
2422+ if (IS_ERR(file) || !file)
2423+ goto out;
2424+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2425+ if (buf) {
2426+ int len;
2427+ int offset = 0;
2428+ while ((len = ccs_kernel_read(file, offset, buf,
2429+ PAGE_SIZE - 1)) > 0) {
2430+ char *cp;
2431+ buf[len] = '\0';
2432+ cp = strrchr(buf, '\n');
2433+ if (!cp)
2434+ break;
2435+ *(cp + 1) = '\0';
2436+ offset += strlen(buf);
2437+ cp = strstr(buf, keyline);
2438+ if (!cp)
2439+ continue;
2440+ *cp = '\0';
2441+ while (cp > buf && *(cp - 1) != '\n')
2442+ cp--;
2443+ entry = simple_strtoul(cp, NULL, 16);
2444+ break;
2445+ }
2446+ kfree(buf);
2447+ }
2448+ filp_close(file, NULL);
2449+out:
2450+ return (void *) entry;
2451+}
2452+
2453+#endif
2454+
2455+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2456+static int lsm_addr_calculator(struct file *file);
2457+static void * __init ccs_find_security_ops_on_arm(unsigned int *base);
2458+#endif
2459+
2460+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
2461+/**
2462+ * ccs_find_vfsmount_lock_on_arm - Find vfsmount_lock spinlock on ARM.
2463+ *
2464+ * @ip: Address of dummy function's entry point.
2465+ * @addr: Address of the variable which is used within @function.
2466+ * @base: Address of function's entry point.
2467+ *
2468+ * Returns address of vfsmount_lock on success, NULL otherwise.
2469+ */
2470+static void * __init ccs_find_vfsmount_lock_on_arm(unsigned int *ip,
2471+ unsigned long addr,
2472+ unsigned int *base)
2473+{
2474+ int i;
2475+ for (i = 0; i < 32; ip++, i++) {
2476+ static unsigned int *ip4ret;
2477+ if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr)
2478+ continue;
2479+ ip = base + i;
2480+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
2481+ return &ip4ret;
2482+ }
2483+ return NULL;
2484+}
2485+#endif
2486+
2487+/**
2488+ * ccs_find_variable - Find variable's address using dummy.
2489+ *
2490+ * @function: Pointer to dummy function's entry point.
2491+ * @addr: Address of the variable which is used within @function.
2492+ * @symbol: Name of symbol to resolve.
2493+ *
2494+ * This trick depends on below assumptions.
2495+ *
2496+ * (1) @addr is found within 128 bytes from @function, even if additional
2497+ * code (e.g. debug symbols) is added.
2498+ * (2) It is safe to read 128 bytes from @function.
2499+ * (3) @addr != Byte code except @addr.
2500+ */
2501+static void * __init ccs_find_variable(void *function, unsigned long addr,
2502+ const char *symbol)
2503+{
2504+ int i;
2505+ u8 *base;
2506+ u8 *cp = function;
2507+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2508+ if (*symbol == ' ')
2509+ base = ccs_find_symbol(symbol);
2510+ else
2511+#endif
2512+ base = __symbol_get(symbol);
2513+ if (!base)
2514+ return NULL;
2515+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2516+ if (function == lsm_addr_calculator)
2517+ return ccs_find_security_ops_on_arm((unsigned int *) base);
2518+#endif
2519+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
2520+ return ccs_find_vfsmount_lock_on_arm(function, addr,
2521+ (unsigned int *) base);
2522+#endif
2523+ /* First, assume absolute adressing mode is used. */
2524+ for (i = 0; i < 128; i++) {
2525+ if (*(unsigned long *) cp == addr)
2526+ return base + i;
2527+ cp++;
2528+ }
2529+ /* Next, assume PC-relative addressing mode is used. */
2530+ cp = function;
2531+ for (i = 0; i < 128; i++) {
2532+ if ((unsigned long) (cp + sizeof(int) + *(int *) cp) == addr) {
2533+ static void *cp4ret;
2534+ cp = base + i;
2535+ cp += sizeof(int) + *(int *) cp;
2536+ cp4ret = cp;
2537+ return &cp4ret;
2538+ }
2539+ cp++;
2540+ }
2541+ cp = function;
2542+ for (i = 0; i < 128; i++) {
2543+ if ((unsigned long) (long) (*(int *) cp) == addr) {
2544+ static void *cp4ret;
2545+ cp = base + i;
2546+ cp = (void *) (long) (*(int *) cp);
2547+ cp4ret = cp;
2548+ return &cp4ret;
2549+ }
2550+ cp++;
2551+ }
2552+ return NULL;
2553+}
2554+
2555+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2556+
2557+/* Never mark this variable as __initdata . */
2558+static struct security_operations *ccs_security_ops;
2559+
2560+/**
2561+ * lsm_addr_calculator - Dummy function which does identical to security_file_alloc() in security/security.c.
2562+ *
2563+ * @file: Pointer to "struct file".
2564+ *
2565+ * Returns return value from security_file_alloc().
2566+ *
2567+ * Never mark this function as __init in order to make sure that compiler
2568+ * generates identical code for security_file_alloc() and this function.
2569+ */
2570+static int lsm_addr_calculator(struct file *file)
2571+{
2572+ return ccs_security_ops->file_alloc_security(file);
2573+}
2574+
2575+#ifdef CONFIG_ARM
2576+/**
2577+ * ccs_find_security_ops_on_arm - Find security_ops on ARM.
2578+ *
2579+ * @base: Address of security_file_alloc().
2580+ *
2581+ * Returns address of security_ops on success, NULL otherwise.
2582+ */
2583+static void * __init ccs_find_security_ops_on_arm(unsigned int *base)
2584+{
2585+ static unsigned int *ip4ret;
2586+ int i;
2587+ const unsigned long addr = (unsigned long) &ccs_security_ops;
2588+ unsigned int *ip = (unsigned int *) lsm_addr_calculator;
2589+ for (i = 0; i < 32; ip++, i++) {
2590+ if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr)
2591+ continue;
2592+ ip = base + i;
2593+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
2594+ return &ip4ret;
2595+ }
2596+ ip = (unsigned int *) lsm_addr_calculator;
2597+ for (i = 0; i < 32; ip++, i++) {
2598+ /*
2599+ * Find
2600+ * ldr r3, [pc, #offset1]
2601+ * ldr r3, [r3, #offset2]
2602+ * sequence.
2603+ */
2604+ if ((*ip & 0xFFFFF000) != 0xE59F3000 ||
2605+ (*(ip + 1) & 0xFFFFF000) != 0xE5933000)
2606+ continue;
2607+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
2608+ ip4ret += (*(ip + 1) & 0xFFF) >> 2;
2609+ if ((unsigned long) ip4ret != addr)
2610+ continue;
2611+ ip = base + i;
2612+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
2613+ ip4ret += (*(ip + 1) & 0xFFF) >> 2;
2614+ return &ip4ret;
2615+ }
2616+ return NULL;
2617+}
2618+#endif
2619+#endif
2620+
2621+/**
2622+ * ccs_find_find_security_ops - Find address of "struct security_operations *security_ops".
2623+ *
2624+ * Returns pointer to "struct security_operations" on success, NULL otherwise.
2625+ */
2626+static struct security_operations * __init ccs_find_security_ops(void)
2627+{
2628+ struct security_operations **ptr;
2629+ struct security_operations *ops;
2630+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2631+ void *cp;
2632+ /* Guess "struct security_operations *security_ops;". */
2633+ cp = ccs_find_variable(lsm_addr_calculator, (unsigned long)
2634+ &ccs_security_ops, " security_file_alloc\n");
2635+ if (!cp) {
2636+ printk(KERN_ERR "Can't resolve security_file_alloc().\n");
2637+ goto out;
2638+ }
2639+ /* This should be "struct security_operations *security_ops;". */
2640+ ptr = *(struct security_operations ***) cp;
2641+#else
2642+ /* This is "struct security_operations *security_ops;". */
2643+ ptr = (struct security_operations **) __symbol_get("security_ops");
2644+#endif
2645+ if (!ptr) {
2646+ printk(KERN_ERR "Can't resolve security_ops structure.\n");
2647+ goto out;
2648+ }
2649+ printk(KERN_INFO "security_ops=%p\n", ptr);
2650+ ops = *ptr;
2651+ if (!ops) {
2652+ printk(KERN_ERR "No security_operations registered.\n");
2653+ goto out;
2654+ }
2655+ return ops;
2656+out:
2657+ return NULL;
2658+}
2659+
2660+/**
2661+ * ccs_find_find_task_by_pid - Find address of find_task_by_pid().
2662+ *
2663+ * Returns true on success, false otherwise.
2664+ */
2665+static bool __init ccs_find_find_task_by_pid(void)
2666+{
2667+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2668+ void *ptr;
2669+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
2670+ ptr = ccs_find_symbol(" find_task_by_vpid\n");
2671+#else
2672+ ptr = __symbol_get("find_task_by_vpid");
2673+#endif
2674+ if (!ptr) {
2675+ printk(KERN_ERR "Can't resolve find_task_by_vpid().\n");
2676+ goto out;
2677+ }
2678+ ccsecurity_exports.find_task_by_vpid = ptr;
2679+ printk(KERN_INFO "find_task_by_vpid=%p\n", ptr);
2680+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
2681+ ptr = ccs_find_symbol(" find_task_by_pid_ns\n");
2682+#else
2683+ ptr = __symbol_get("find_task_by_pid_ns");
2684+#endif
2685+ if (!ptr) {
2686+ printk(KERN_ERR "Can't resolve find_task_by_pid_ns().\n");
2687+ goto out;
2688+ }
2689+ ccsecurity_exports.find_task_by_pid_ns = ptr;
2690+ printk(KERN_INFO "find_task_by_pid_ns=%p\n", ptr);
2691+ return true;
2692+out:
2693+ return false;
2694+#else
2695+ return true;
2696+#endif
2697+}
2698+
2699+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
2700+
2701+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2702+
2703+/* Never mark this variable as __initdata . */
2704+static spinlock_t ccs_vfsmount_lock __cacheline_aligned_in_smp =
2705+SPIN_LOCK_UNLOCKED;
2706+
2707+static struct list_head *mount_hashtable;
2708+static int hash_mask, hash_bits;
2709+
2710+/**
2711+ * hash - Copy of hash() in fs/namespace.c.
2712+ *
2713+ * @mnt: Pointer to "struct vfsmount".
2714+ * @dentry: Pointer to "struct dentry".
2715+ *
2716+ * Returns hash value.
2717+ */
2718+static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
2719+{
2720+ unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
2721+ tmp += ((unsigned long) dentry / L1_CACHE_BYTES);
2722+ tmp = tmp + (tmp >> hash_bits);
2723+ return tmp & hash_mask;
2724+}
2725+
2726+/**
2727+ * lsm_lu_mnt - Dummy function which does identical to lookup_mnt() in fs/namespace.c.
2728+ *
2729+ * @mnt: Pointer to "struct vfsmount".
2730+ * @dentry: Pointer to "struct dentry".
2731+ *
2732+ * Returns pointer to "struct vfsmount".
2733+ *
2734+ * Never mark this function as __init in order to make sure that compiler
2735+ * generates identical code for lookup_mnt() and this function.
2736+ */
2737+static struct vfsmount *lsm_lu_mnt(struct vfsmount *mnt, struct dentry *dentry)
2738+{
2739+ struct list_head *head = mount_hashtable + hash(mnt, dentry);
2740+ struct list_head *tmp = head;
2741+ struct vfsmount *p, *found = NULL;
2742+
2743+ spin_lock(&ccs_vfsmount_lock);
2744+ for (;;) {
2745+ tmp = tmp->next;
2746+ p = NULL;
2747+ if (tmp == head)
2748+ break;
2749+ p = list_entry(tmp, struct vfsmount, mnt_hash);
2750+ if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
2751+ found = mntget(p);
2752+ break;
2753+ }
2754+ }
2755+ spin_unlock(&ccs_vfsmount_lock);
2756+ return found;
2757+}
2758+
2759+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
2760+
2761+/* Never mark this variable as __initdata . */
2762+static spinlock_t ccs_vfsmount_lock;
2763+
2764+/**
2765+ * lsm_flwup - Dummy function which does identical to follow_up() in fs/namei.c.
2766+ *
2767+ * @mnt: Pointer to "struct vfsmount *".
2768+ * @dentry: Pointer to "struct dentry *".
2769+ *
2770+ * Returns 1 if followed up, 0 otehrwise.
2771+ *
2772+ * Never mark this function as __init in order to make sure that compiler
2773+ * generates identical code for follow_up() and this function.
2774+ */
2775+static int lsm_flwup(struct vfsmount **mnt, struct dentry **dentry)
2776+{
2777+ struct vfsmount *parent;
2778+ struct dentry *mountpoint;
2779+ spin_lock(&ccs_vfsmount_lock);
2780+ parent = (*mnt)->mnt_parent;
2781+ if (parent == *mnt) {
2782+ spin_unlock(&ccs_vfsmount_lock);
2783+ return 0;
2784+ }
2785+ mntget(parent);
2786+ mountpoint = dget((*mnt)->mnt_mountpoint);
2787+ spin_unlock(&ccs_vfsmount_lock);
2788+ dput(*dentry);
2789+ *dentry = mountpoint;
2790+ mntput(*mnt);
2791+ *mnt = parent;
2792+ return 1;
2793+}
2794+
2795+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
2796+
2797+/* Never mark this variable as __initdata . */
2798+static spinlock_t ccs_vfsmount_lock;
2799+
2800+/**
2801+ * lsm_pin - Dummy function which does identical to mnt_pin() in fs/namespace.c.
2802+ *
2803+ * @mnt: Pointer to "struct vfsmount".
2804+ *
2805+ * Returns nothing.
2806+ *
2807+ * Never mark this function as __init in order to make sure that compiler
2808+ * generates identical code for mnt_pin() and this function.
2809+ */
2810+static void lsm_pin(struct vfsmount *mnt)
2811+{
2812+ spin_lock(&ccs_vfsmount_lock);
2813+ mnt->mnt_pinned++;
2814+ spin_unlock(&ccs_vfsmount_lock);
2815+}
2816+
2817+#endif
2818+
2819+/**
2820+ * ccs_find_vfsmount_lock - Find address of "spinlock_t vfsmount_lock".
2821+ *
2822+ * Returns true on success, false otherwise.
2823+ */
2824+static bool __init ccs_find_vfsmount_lock(void)
2825+{
2826+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2827+ void *cp;
2828+ spinlock_t *ptr;
2829+ /* Guess "spinlock_t vfsmount_lock;". */
2830+ cp = ccs_find_variable(lsm_lu_mnt, (unsigned long) &ccs_vfsmount_lock,
2831+ " lookup_mnt\n");
2832+ if (!cp) {
2833+ printk(KERN_ERR "Can't resolve lookup_mnt().\n");
2834+ goto out;
2835+ }
2836+ /* This should be "spinlock_t *vfsmount_lock;". */
2837+ ptr = *(spinlock_t **) cp;
2838+ if (!ptr) {
2839+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
2840+ goto out;
2841+ }
2842+ ccsecurity_exports.vfsmount_lock = ptr;
2843+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
2844+ return true;
2845+out:
2846+ return false;
2847+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
2848+ void *cp;
2849+ spinlock_t *ptr;
2850+ /* Guess "spinlock_t vfsmount_lock;". */
2851+ cp = ccs_find_variable(lsm_flwup, (unsigned long) &ccs_vfsmount_lock,
2852+ "follow_up");
2853+ if (!cp) {
2854+ printk(KERN_ERR "Can't resolve follow_up().\n");
2855+ goto out;
2856+ }
2857+ /* This should be "spinlock_t *vfsmount_lock;". */
2858+ ptr = *(spinlock_t **) cp;
2859+ if (!ptr) {
2860+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
2861+ goto out;
2862+ }
2863+ ccsecurity_exports.vfsmount_lock = ptr;
2864+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
2865+ return true;
2866+out:
2867+ return false;
2868+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
2869+ void *cp;
2870+ spinlock_t *ptr;
2871+ /* Guess "spinlock_t vfsmount_lock;". */
2872+ cp = ccs_find_variable(lsm_pin, (unsigned long) &ccs_vfsmount_lock,
2873+ "mnt_pin");
2874+ if (!cp) {
2875+ printk(KERN_ERR "Can't resolve mnt_pin().\n");
2876+ goto out;
2877+ }
2878+ /* This should be "spinlock_t *vfsmount_lock;". */
2879+ ptr = *(spinlock_t **) cp;
2880+ if (!ptr) {
2881+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
2882+ goto out;
2883+ }
2884+ ccsecurity_exports.vfsmount_lock = ptr;
2885+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
2886+ return true;
2887+out:
2888+ return false;
2889+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
2890+ void *ptr = ccs_find_symbol(" __d_path\n");
2891+ if (!ptr) {
2892+ printk(KERN_ERR "Can't resolve __d_path().\n");
2893+ return false;
2894+ }
2895+ ccsecurity_exports.__d_path = ptr;
2896+ printk(KERN_INFO "__d_path=%p\n", ptr);
2897+ return true;
2898+#else
2899+ void *ptr = ccs_find_symbol(" d_absolute_path\n");
2900+ if (!ptr) {
2901+ printk(KERN_ERR "Can't resolve d_absolute_path().\n");
2902+ return false;
2903+ }
2904+ ccsecurity_exports.d_absolute_path = ptr;
2905+ printk(KERN_INFO "d_absolute_path=%p\n", ptr);
2906+ return true;
2907+#endif
2908+}
2909+
2910+#else
2911+
2912+/* Never mark this variable as __initdata . */
2913+static spinlock_t ccs_vfsmount_lock;
2914+
2915+/**
2916+ * ccs_find_vfsmount_lock - Find address of "spinlock_t vfsmount_lock".
2917+ *
2918+ * Returns true on success, false otherwise.
2919+ */
2920+static bool __init ccs_find_vfsmount_lock(void)
2921+{
2922+ ccsecurity_exports.vfsmount_lock = &ccs_vfsmount_lock;
2923+ return true;
2924+}
2925+
2926+#endif
2927+
2928+/*
2929+ * Why not to copy all operations by "original_security_ops = *ops" ?
2930+ * Because copying byte array is not atomic. Reader checks
2931+ * original_security_ops.op != NULL before doing original_security_ops.op().
2932+ * Thus, modifying original_security_ops.op has to be atomic.
2933+ */
2934+#define swap_security_ops(op) \
2935+ original_security_ops.op = ops->op; smp_wmb(); ops->op = ccs_##op;
2936+
2937+/**
2938+ * ccs_update_security_ops - Overwrite original "struct security_operations".
2939+ *
2940+ * @ops: Pointer to "struct security_operations".
2941+ *
2942+ * Returns nothing.
2943+ */
2944+static void __init ccs_update_security_ops(struct security_operations *ops)
2945+{
2946+ /* Security context allocator. */
2947+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2948+ swap_security_ops(task_create);
2949+ swap_security_ops(cred_prepare);
2950+ swap_security_ops(cred_free);
2951+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
2952+ swap_security_ops(cred_alloc_blank);
2953+ swap_security_ops(cred_transfer);
2954+#endif
2955+#else
2956+ swap_security_ops(task_alloc_security);
2957+ swap_security_ops(task_free_security);
2958+ swap_security_ops(bprm_alloc_security);
2959+ swap_security_ops(bprm_free_security);
2960+#endif
2961+ /* Security context updater for successful execve(). */
2962+ swap_security_ops(bprm_check_security);
2963+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6)
2964+ swap_security_ops(bprm_compute_creds);
2965+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2966+ swap_security_ops(bprm_apply_creds);
2967+#else
2968+ swap_security_ops(bprm_committing_creds);
2969+#endif
2970+ /* Various permission checker. */
2971+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
2972+ swap_security_ops(file_open);
2973+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2974+ swap_security_ops(dentry_open);
2975+#else
2976+ swap_security_ops(inode_permission);
2977+#endif
2978+ swap_security_ops(file_fcntl);
2979+ swap_security_ops(file_ioctl);
2980+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
2981+ swap_security_ops(sysctl);
2982+#endif
2983+ swap_security_ops(sb_pivotroot);
2984+ swap_security_ops(sb_mount);
2985+ swap_security_ops(sb_umount);
2986+#if defined(CONFIG_SECURITY_PATH)
2987+ swap_security_ops(path_mknod);
2988+ swap_security_ops(path_mkdir);
2989+ swap_security_ops(path_rmdir);
2990+ swap_security_ops(path_unlink);
2991+ swap_security_ops(path_symlink);
2992+ swap_security_ops(path_rename);
2993+ swap_security_ops(path_link);
2994+ swap_security_ops(path_truncate);
2995+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2996+ swap_security_ops(path_chmod);
2997+ swap_security_ops(path_chown);
2998+ swap_security_ops(path_chroot);
2999+#endif
3000+#else
3001+ swap_security_ops(inode_mknod);
3002+ swap_security_ops(inode_mkdir);
3003+ swap_security_ops(inode_rmdir);
3004+ swap_security_ops(inode_unlink);
3005+ swap_security_ops(inode_symlink);
3006+ swap_security_ops(inode_rename);
3007+ swap_security_ops(inode_link);
3008+ swap_security_ops(inode_create);
3009+#endif
3010+ swap_security_ops(inode_setattr);
3011+ swap_security_ops(inode_getattr);
3012+#ifdef CONFIG_SECURITY_NETWORK
3013+ swap_security_ops(socket_bind);
3014+ swap_security_ops(socket_connect);
3015+ swap_security_ops(socket_listen);
3016+ swap_security_ops(socket_sendmsg);
3017+ swap_security_ops(socket_recvmsg);
3018+ swap_security_ops(socket_getsockname);
3019+ swap_security_ops(socket_getpeername);
3020+ swap_security_ops(socket_getsockopt);
3021+ swap_security_ops(socket_setsockopt);
3022+ swap_security_ops(socket_shutdown);
3023+ swap_security_ops(socket_accept);
3024+ swap_security_ops(inode_free_security);
3025+#endif
3026+}
3027+
3028+#undef swap_security_ops
3029+
3030+/**
3031+ * ccs_init - Initialize this module.
3032+ *
3033+ * Returns 0 on success, negative value otherwise.
3034+ */
3035+static int __init ccs_init(void)
3036+{
3037+ struct security_operations *ops = ccs_find_security_ops();
3038+ if (!ops || !ccs_find_find_task_by_pid() ||
3039+ !ccs_find_vfsmount_lock())
3040+ return -EINVAL;
3041+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
3042+ {
3043+ int idx;
3044+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
3045+ INIT_LIST_HEAD(&ccs_cred_security_list[idx]);
3046+ INIT_LIST_HEAD(&ccs_task_security_list[idx]);
3047+ }
3048+ }
3049+#endif
3050+ ccs_main_init();
3051+ ccs_update_security_ops(ops);
3052+ printk(KERN_INFO "AKARI: 1.0.29 2012/11/04\n");
3053+ printk(KERN_INFO
3054+ "Access Keeping And Regulating Instrument registered.\n");
3055+ return 0;
3056+}
3057+
3058+module_init(ccs_init);
3059+MODULE_LICENSE("GPL");
3060+
3061+/**
3062+ * ccs_used_by_cred - Check whether the given domain is in use or not.
3063+ *
3064+ * @domain: Pointer to "struct ccs_domain_info".
3065+ *
3066+ * Returns true if @domain is in use, false otherwise.
3067+ *
3068+ * Caller holds rcu_read_lock().
3069+ */
3070+bool ccs_used_by_cred(const struct ccs_domain_info *domain)
3071+{
3072+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
3073+ int idx;
3074+ struct ccs_security *ptr;
3075+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
3076+ struct list_head *list = &ccs_cred_security_list[idx];
3077+ list_for_each_entry_rcu(ptr, list, list) {
3078+ struct ccs_execve *ee = ptr->ee;
3079+ if (ptr->ccs_domain_info == domain ||
3080+ (ee && ee->previous_domain == domain)) {
3081+ return true;
3082+ }
3083+ }
3084+ }
3085+#endif
3086+ return false;
3087+}
3088+
3089+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
3090+
3091+/**
3092+ * ccs_add_task_security - Add "struct ccs_security" to list.
3093+ *
3094+ * @ptr: Pointer to "struct ccs_security".
3095+ * @list: Pointer to "struct list_head".
3096+ *
3097+ * Returns nothing.
3098+ */
3099+static void ccs_add_task_security(struct ccs_security *ptr,
3100+ struct list_head *list)
3101+{
3102+ unsigned long flags;
3103+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
3104+ list_add_rcu(&ptr->list, list);
3105+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
3106+}
3107+
3108+/**
3109+ * ccs_find_task_security - Find "struct ccs_security" for given task.
3110+ *
3111+ * @task: Pointer to "struct task_struct".
3112+ *
3113+ * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
3114+ * out of memory, &ccs_default_security otherwise.
3115+ *
3116+ * If @task is current thread and "struct ccs_security" for current thread was
3117+ * not found, I try to allocate it. But if allocation failed, current thread
3118+ * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
3119+ * won't work.
3120+ */
3121+struct ccs_security *ccs_find_task_security(const struct task_struct *task)
3122+{
3123+ struct ccs_security *ptr;
3124+ struct list_head *list = &ccs_task_security_list
3125+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
3126+ /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
3127+ while (!list->next);
3128+ rcu_read_lock();
3129+ list_for_each_entry_rcu(ptr, list, list) {
3130+ if (ptr->pid != task->pids[PIDTYPE_PID].pid)
3131+ continue;
3132+ rcu_read_unlock();
3133+ /*
3134+ * Current thread needs to transit from old domain to new
3135+ * domain before do_execve() succeeds in order to check
3136+ * permission for interpreters and environment variables using
3137+ * new domain's ACL rules. The domain transition has to be
3138+ * visible from other CPU in order to allow interactive
3139+ * enforcing mode. Also, the domain transition has to be
3140+ * reverted if do_execve() failed. However, an LSM hook for
3141+ * reverting domain transition is missing.
3142+ *
3143+ * When do_execve() failed, "struct cred" in
3144+ * "struct linux_binprm" is scheduled for destruction.
3145+ * But current thread returns to userspace without waiting for
3146+ * destruction. The security_cred_free() LSM hook is called
3147+ * after an RCU grace period has elapsed. Since some CPU may be
3148+ * doing long long RCU read side critical section, there is
3149+ * no guarantee that security_cred_free() is called before
3150+ * current thread again calls do_execve().
3151+ *
3152+ * To be able to revert domain transition before processing
3153+ * next do_execve() request, current thread gets a refcount on
3154+ * "struct cred" in "struct linux_binprm" and memorizes it.
3155+ * Current thread drops the refcount and forgets it when
3156+ * do_execve() succeeded.
3157+ *
3158+ * Therefore, if current thread hasn't forgotten it and
3159+ * current thread is the last one using that "struct cred",
3160+ * it indicates that do_execve() has failed and reverting
3161+ * domain transition is needed.
3162+ */
3163+ if (task == current && ptr->cred &&
3164+ atomic_read(&ptr->cred->usage) == 1) {
3165+#ifdef CONFIG_AKARI_DEBUG
3166+ static bool done;
3167+ if (!done) {
3168+ printk(KERN_INFO "AKARI: Reverting domain "
3169+ "transition because do_execve() has "
3170+ "failed.\n");
3171+ done = true;
3172+ }
3173+#endif
3174+ ccs_clear_execve(-1, ptr);
3175+ }
3176+ return ptr;
3177+ }
3178+ rcu_read_unlock();
3179+ if (task != current) {
3180+ /*
3181+ * If a thread does nothing after fork(), caller will reach
3182+ * here because "struct ccs_security" for that thread is not
3183+ * yet allocated. But that thread is keeping a snapshot of
3184+ * "struct ccs_security" taken as of ccs_task_create()
3185+ * associated with that thread's "struct cred".
3186+ *
3187+ * Since that snapshot will be used as initial data when that
3188+ * thread allocates "struct ccs_security" for that thread, we
3189+ * can return that snapshot rather than &ccs_default_security.
3190+ *
3191+ * Since this function is called by only ccs_select_one() and
3192+ * ccs_read_pid() (via ccs_task_domain() and ccs_task_flags()),
3193+ * it is guaranteed that caller has called rcu_read_lock()
3194+ * (via ccs_tasklist_lock()) before finding this thread and
3195+ * this thread is valid. Therefore, we can do __task_cred(task)
3196+ * like get_robust_list() does.
3197+ */
3198+ return ccs_find_cred_security(__task_cred(task));
3199+ }
3200+ /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
3201+ ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
3202+ if (!ptr) {
3203+ printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
3204+ task->pid);
3205+ send_sig(SIGKILL, current, 0);
3206+ return &ccs_oom_security;
3207+ }
3208+ *ptr = *ccs_find_cred_security(task->cred);
3209+ /* We can shortcut because task == current. */
3210+ ptr->pid = get_pid(((struct task_struct *) task)->
3211+ pids[PIDTYPE_PID].pid);
3212+ ptr->cred = NULL;
3213+ ccs_add_task_security(ptr, list);
3214+ return ptr;
3215+}
3216+
3217+/**
3218+ * ccs_copy_cred_security - Allocate memory for new credentials.
3219+ *
3220+ * @new: Pointer to "struct cred".
3221+ * @old: Pointer to "struct cred".
3222+ * @gfp: Memory allocation flags.
3223+ *
3224+ * Returns 0 on success, negative value otherwise.
3225+ */
3226+static int ccs_copy_cred_security(const struct cred *new,
3227+ const struct cred *old, gfp_t gfp)
3228+{
3229+ struct ccs_security *old_security = ccs_find_cred_security(old);
3230+ struct ccs_security *new_security =
3231+ kzalloc(sizeof(*new_security), gfp);
3232+ if (!new_security)
3233+ return -ENOMEM;
3234+ *new_security = *old_security;
3235+ new_security->cred = new;
3236+ ccs_add_cred_security(new_security);
3237+ return 0;
3238+}
3239+
3240+/**
3241+ * ccs_find_cred_security - Find "struct ccs_security" for given credential.
3242+ *
3243+ * @cred: Pointer to "struct cred".
3244+ *
3245+ * Returns pointer to "struct ccs_security" on success, &ccs_default_security
3246+ * otherwise.
3247+ */
3248+static struct ccs_security *ccs_find_cred_security(const struct cred *cred)
3249+{
3250+ struct ccs_security *ptr;
3251+ struct list_head *list = &ccs_cred_security_list
3252+ [hash_ptr((void *) cred, CCS_TASK_SECURITY_HASH_BITS)];
3253+ rcu_read_lock();
3254+ list_for_each_entry_rcu(ptr, list, list) {
3255+ if (ptr->cred != cred)
3256+ continue;
3257+ rcu_read_unlock();
3258+ return ptr;
3259+ }
3260+ rcu_read_unlock();
3261+ return &ccs_default_security;
3262+}
3263+
3264+/**
3265+ * ccs_task_security_gc - Do garbage collection for "struct task_struct".
3266+ *
3267+ * Returns nothing.
3268+ *
3269+ * Since security_task_free_security() is missing, I can't release memory
3270+ * associated with "struct task_struct" when a task dies. Therefore, I hold
3271+ * a reference on "struct pid" and runs garbage collection when associated
3272+ * "struct task_struct" has gone.
3273+ */
3274+static void ccs_task_security_gc(void)
3275+{
3276+ static DEFINE_MUTEX(lock);
3277+ static atomic_t gc_counter = ATOMIC_INIT(0);
3278+ unsigned int idx;
3279+ /*
3280+ * If some process is doing execve(), try to garbage collection now.
3281+ * We should kfree() memory associated with "struct ccs_security"->ee
3282+ * as soon as execve() has completed in order to compensate for lack of
3283+ * security_bprm_free() and security_task_free() hooks.
3284+ *
3285+ * Otherwise, reduce frequency for performance reason.
3286+ */
3287+ if (!atomic_read(&ccs_in_execve_tasks) &&
3288+ atomic_inc_return(&gc_counter) < 1024)
3289+ return;
3290+ atomic_set(&gc_counter, 0);
3291+ if (mutex_lock_interruptible(&lock))
3292+ return;
3293+ rcu_read_lock();
3294+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
3295+ struct ccs_security *ptr;
3296+ struct list_head *list = &ccs_task_security_list[idx];
3297+ list_for_each_entry_rcu(ptr, list, list) {
3298+ if (pid_task(ptr->pid, PIDTYPE_PID))
3299+ continue;
3300+ ccs_del_security(ptr);
3301+ }
3302+ }
3303+ rcu_read_unlock();
3304+ mutex_unlock(&lock);
3305+}
3306+
3307+#endif
--- tags/patches/1.0.29/README (nonexistent)
+++ tags/patches/1.0.29/README (revision 431)
@@ -0,0 +1,255 @@
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.
--- tags/patches/1.0.29/internal.h (nonexistent)
+++ tags/patches/1.0.29/internal.h (revision 431)
@@ -0,0 +1,2153 @@
1+/*
2+ * security/ccsecurity/internal.h
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2012/05/05
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+#include <stdarg.h>
60+#include <asm/uaccess.h>
61+#include <net/sock.h>
62+#include <net/af_unix.h>
63+#include <net/ip.h>
64+#include <net/ipv6.h>
65+#include <net/udp.h>
66+
67+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
68+#define sk_family family
69+#define sk_protocol protocol
70+#define sk_type type
71+#endif
72+
73+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
74+
75+/* Structure for holding "struct vfsmount *" and "struct dentry *". */
76+struct path {
77+ struct vfsmount *mnt;
78+ struct dentry *dentry;
79+};
80+
81+#endif
82+
83+#ifndef __printf
84+#define __printf(a,b) __attribute__((format(printf,a,b)))
85+#endif
86+#ifndef __packed
87+#define __packed __attribute__((__packed__))
88+#endif
89+#ifndef bool
90+#define bool _Bool
91+#endif
92+#ifndef false
93+#define false 0
94+#endif
95+#ifndef true
96+#define true 1
97+#endif
98+
99+#ifndef __user
100+#define __user
101+#endif
102+
103+#ifndef current_uid
104+#define current_uid() (current->uid)
105+#endif
106+#ifndef current_gid
107+#define current_gid() (current->gid)
108+#endif
109+#ifndef current_euid
110+#define current_euid() (current->euid)
111+#endif
112+#ifndef current_egid
113+#define current_egid() (current->egid)
114+#endif
115+#ifndef current_suid
116+#define current_suid() (current->suid)
117+#endif
118+#ifndef current_sgid
119+#define current_sgid() (current->sgid)
120+#endif
121+#ifndef current_fsuid
122+#define current_fsuid() (current->fsuid)
123+#endif
124+#ifndef current_fsgid
125+#define current_fsgid() (current->fsgid)
126+#endif
127+
128+#ifndef DEFINE_SPINLOCK
129+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
130+#endif
131+
132+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
133+#define mutex semaphore
134+#define mutex_init(mutex) init_MUTEX(mutex)
135+#define mutex_unlock(mutex) up(mutex)
136+#define mutex_lock(mutex) down(mutex)
137+#define mutex_lock_interruptible(mutex) down_interruptible(mutex)
138+#define mutex_trylock(mutex) (!down_trylock(mutex))
139+#define DEFINE_MUTEX(mutexname) DECLARE_MUTEX(mutexname)
140+#endif
141+
142+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
143+#define MS_UNBINDABLE (1<<17) /* change to unbindable */
144+#define MS_PRIVATE (1<<18) /* change to private */
145+#define MS_SLAVE (1<<19) /* change to slave */
146+#define MS_SHARED (1<<20) /* change to shared */
147+#endif
148+
149+#ifndef container_of
150+#define container_of(ptr, type, member) ({ \
151+ const typeof(((type *)0)->member) *__mptr = (ptr); \
152+ (type *)((char *)__mptr - offsetof(type, member)); })
153+#endif
154+
155+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
156+#define smp_read_barrier_depends smp_rmb
157+#endif
158+
159+#ifndef ACCESS_ONCE
160+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
161+#endif
162+
163+#ifndef rcu_dereference
164+#define rcu_dereference(p) ({ \
165+ typeof(p) _________p1 = ACCESS_ONCE(p); \
166+ smp_read_barrier_depends(); /* see RCU */ \
167+ (_________p1); \
168+ })
169+#endif
170+
171+#ifndef rcu_assign_pointer
172+#define rcu_assign_pointer(p, v) \
173+ ({ \
174+ if (!__builtin_constant_p(v) || \
175+ ((v) != NULL)) \
176+ smp_wmb(); /* see RCU */ \
177+ (p) = (v); \
178+ })
179+#endif
180+
181+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
182+
183+/**
184+ * kzalloc() - Allocate memory. The memory is set to zero.
185+ *
186+ * @size: Size to allocate.
187+ * @flags: GFP flags.
188+ *
189+ * Returns pointer to allocated memory on success, NULL otherwise.
190+ *
191+ * This is for compatibility with older kernels.
192+ *
193+ * Since several distributions backported kzalloc(), I define it as a macro
194+ * rather than an inlined function in order to avoid multiple definition error.
195+ */
196+#define kzalloc(size, flags) ({ \
197+ void *ret = kmalloc((size), (flags)); \
198+ if (ret) \
199+ memset(ret, 0, (size)); \
200+ ret; })
201+
202+#endif
203+
204+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
205+
206+/**
207+ * path_put - Drop reference on "struct path".
208+ *
209+ * @path: Pointer to "struct path".
210+ *
211+ * Returns nothing.
212+ *
213+ * This is for compatibility with older kernels.
214+ */
215+static inline void path_put(struct path *path)
216+{
217+ dput(path->dentry);
218+ mntput(path->mnt);
219+}
220+
221+#endif
222+
223+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
224+
225+/**
226+ * __list_add_rcu - Insert a new entry between two known consecutive entries.
227+ *
228+ * @new: Pointer to "struct list_head".
229+ * @prev: Pointer to "struct list_head".
230+ * @next: Pointer to "struct list_head".
231+ *
232+ * Returns nothing.
233+ *
234+ * This is for compatibility with older kernels.
235+ */
236+static inline void __list_add_rcu(struct list_head *new,
237+ struct list_head *prev,
238+ struct list_head *next)
239+{
240+ new->next = next;
241+ new->prev = prev;
242+ rcu_assign_pointer(prev->next, new);
243+ next->prev = new;
244+}
245+
246+/**
247+ * list_add_tail_rcu - Add a new entry to rcu-protected list.
248+ *
249+ * @new: Pointer to "struct list_head".
250+ * @head: Pointer to "struct list_head".
251+ *
252+ * Returns nothing.
253+ *
254+ * This is for compatibility with older kernels.
255+ */
256+static inline void list_add_tail_rcu(struct list_head *new,
257+ struct list_head *head)
258+{
259+ __list_add_rcu(new, head->prev, head);
260+}
261+
262+/**
263+ * list_add_rcu - Add a new entry to rcu-protected list.
264+ *
265+ * @new: Pointer to "struct list_head".
266+ * @head: Pointer to "struct list_head".
267+ *
268+ * Returns nothing.
269+ *
270+ * This is for compatibility with older kernels.
271+ */
272+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
273+{
274+ __list_add_rcu(new, head, head->next);
275+}
276+
277+#endif
278+
279+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
280+
281+/**
282+ * __list_del_entry - Deletes entry from list without re-initialization.
283+ *
284+ * @entry: Pointer to "struct list_head".
285+ *
286+ * Returns nothing.
287+ *
288+ * This is for compatibility with older kernels.
289+ */
290+static inline void __list_del_entry(struct list_head *entry)
291+{
292+ __list_del(entry->prev, entry->next);
293+}
294+
295+#endif
296+
297+#ifndef list_for_each_entry_safe
298+
299+/**
300+ * list_for_each_entry_safe - Iterate over list of given type safe against removal of list entry.
301+ *
302+ * @pos: The "type *" to use as a loop cursor.
303+ * @n: Another "type *" to use as temporary storage.
304+ * @head: Pointer to "struct list_head".
305+ * @member: The name of the list_struct within the struct.
306+ *
307+ * This is for compatibility with older kernels.
308+ */
309+#define list_for_each_entry_safe(pos, n, head, member) \
310+ for (pos = list_entry((head)->next, typeof(*pos), member), \
311+ n = list_entry(pos->member.next, typeof(*pos), member); \
312+ &pos->member != (head); \
313+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
314+
315+#endif
316+
317+#ifndef srcu_dereference
318+
319+/**
320+ * srcu_dereference - Fetch SRCU-protected pointer with checking.
321+ *
322+ * @p: The pointer to read, prior to dereferencing.
323+ * @ss: Pointer to "struct srcu_struct".
324+ *
325+ * Returns @p.
326+ *
327+ * This is for compatibility with older kernels.
328+ */
329+#define srcu_dereference(p, ss) rcu_dereference(p)
330+
331+#endif
332+
333+#ifndef list_for_each_entry_srcu
334+
335+/**
336+ * list_for_each_entry_srcu - Iterate over rcu list of given type.
337+ *
338+ * @pos: The type * to use as a loop cursor.
339+ * @head: The head for your list.
340+ * @member: The name of the list_struct within the struct.
341+ * @ss: Pointer to "struct srcu_struct".
342+ *
343+ * As of 2.6.36, this macro is not provided because only TOMOYO wants it.
344+ */
345+#define list_for_each_entry_srcu(pos, head, member, ss) \
346+ for (pos = list_entry(srcu_dereference((head)->next, ss), \
347+ typeof(*pos), member); \
348+ prefetch(pos->member.next), &pos->member != (head); \
349+ pos = list_entry(srcu_dereference(pos->member.next, ss), \
350+ typeof(*pos), member))
351+
352+#endif
353+
354+#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))
355+
356+#ifndef ssleep
357+
358+/**
359+ * ssleep - Sleep for specified seconds.
360+ *
361+ * @secs: Seconds to sleep.
362+ *
363+ * Returns nothing.
364+ *
365+ * This is for compatibility with older kernels.
366+ *
367+ * Since several distributions backported ssleep(), I define it as a macro
368+ * rather than an inlined function in order to avoid multiple definition error.
369+ */
370+#define ssleep(secs) { \
371+ set_current_state(TASK_UNINTERRUPTIBLE); \
372+ schedule_timeout((HZ * secs) + 1); \
373+ }
374+
375+#endif
376+
377+#endif
378+
379+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
380+
381+/**
382+ * from_kuid - Convert kuid_t to uid_t.
383+ *
384+ * @ns: Unused.
385+ * @uid: kuid_t value.
386+ *
387+ * Returns uid seen from init's user namespace.
388+ */
389+#define from_kuid(ns, uid) (uid)
390+
391+/**
392+ * from_kgid - Convert kgid_t to gid_t.
393+ *
394+ * @ns: Unused.
395+ * @gid: kgid_t value.
396+ *
397+ * Returns gid seen from init's user namespace.
398+ */
399+#define from_kgid(ns, gid) (gid)
400+
401+/**
402+ * uid_eq - Check whether the uids are equals or not.
403+ *
404+ * @left: Uid seen from current user namespace.
405+ * @right: Uid seen from current user namespace.
406+ *
407+ * Returns true if uid is root in init's user namespace, false otherwise.
408+ */
409+#define uid_eq(left, right) ((left) == (right))
410+#define GLOBAL_ROOT_UID 0
411+
412+#endif
413+
414+/*
415+ * TOMOYO specific part start.
416+ */
417+
418+/* Clear TOMOYO 1.8 config. */
419+#undef CONFIG_CCSECURITY
420+#undef CONFIG_CCSECURITY_LKM
421+#undef CONFIG_CCSECURITY_DISABLE_BY_DEFAULT
422+#undef CONFIG_CCSECURITY_MAX_AUDIT_LOG
423+#undef CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY
424+#undef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
425+#undef CONFIG_CCSECURITY_POLICY_LOADER
426+#undef CONFIG_CCSECURITY_ACTIVATION_TRIGGER
427+#undef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
428+#undef CONFIG_CCSECURITY_FILE_READDIR
429+#undef CONFIG_CCSECURITY_FILE_GETATTR
430+#undef CONFIG_CCSECURITY_NETWORK
431+#undef CONFIG_CCSECURITY_NETWORK_RECVMSG
432+#undef CONFIG_CCSECURITY_CAPABILITY
433+#undef CONFIG_CCSECURITY_IPC
434+#undef CONFIG_CCSECURITY_MISC
435+#undef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
436+#undef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
437+#undef CONFIG_CCSECURITY_PORTRESERVE
438+/* Define AKARI 1.0 config. */
439+#include "config.h"
440+#ifndef CONFIG_CCSECURITY
441+#define CONFIG_CCSECURITY
442+#endif
443+#ifndef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
444+#define CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
445+#endif
446+#ifndef CONFIG_CCSECURITY_MAX_AUDIT_LOG
447+#define CONFIG_CCSECURITY_MAX_AUDIT_LOG 1024
448+#endif
449+#ifndef CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY
450+#define CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY 2048
451+#endif
452+#ifndef CONFIG_CCSECURITY_POLICY_LOADER
453+#define CONFIG_CCSECURITY_POLICY_LOADER "/sbin/ccs-init"
454+#endif
455+#ifndef CONFIG_CCSECURITY_ACTIVATION_TRIGGER
456+#define CONFIG_CCSECURITY_ACTIVATION_TRIGGER "/sbin/init"
457+#endif
458+#include "ccsecurity.h"
459+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
460+#error This module supports only 2.6.0 and later kernels.
461+#endif
462+#ifndef CONFIG_SECURITY
463+#error You must choose CONFIG_SECURITY=y for building this module.
464+#endif
465+#ifndef CONFIG_KALLSYMS
466+#error You must choose CONFIG_KALLSYMS=y for building this module.
467+#endif
468+#ifndef CONFIG_PROC_FS
469+#error You must choose CONFIG_PROC_FS=y for building this module.
470+#endif
471+#ifndef CONFIG_MODULES
472+#error You must choose CONFIG_MODULES=y for building this module.
473+#endif
474+
475+/* Enumeration definition for internal use. */
476+
477+/* Index numbers for Access Controls. */
478+enum ccs_acl_entry_type_index {
479+ CCS_TYPE_PATH_ACL,
480+ CCS_TYPE_PATH2_ACL,
481+ CCS_TYPE_PATH_NUMBER_ACL,
482+ CCS_TYPE_MKDEV_ACL,
483+ CCS_TYPE_MOUNT_ACL,
484+#ifdef CONFIG_CCSECURITY_MISC
485+ CCS_TYPE_ENV_ACL,
486+#endif
487+#ifdef CONFIG_CCSECURITY_CAPABILITY
488+ CCS_TYPE_CAPABILITY_ACL,
489+#endif
490+#ifdef CONFIG_CCSECURITY_NETWORK
491+ CCS_TYPE_INET_ACL,
492+ CCS_TYPE_UNIX_ACL,
493+#endif
494+#ifdef CONFIG_CCSECURITY_IPC
495+ CCS_TYPE_SIGNAL_ACL,
496+#endif
497+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
498+ CCS_TYPE_AUTO_EXECUTE_HANDLER,
499+ CCS_TYPE_DENIED_EXECUTE_HANDLER,
500+#endif
501+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
502+ CCS_TYPE_AUTO_TASK_ACL,
503+ CCS_TYPE_MANUAL_TASK_ACL,
504+#endif
505+};
506+
507+/* Index numbers for "struct ccs_condition". */
508+enum ccs_conditions_index {
509+ CCS_TASK_UID, /* current_uid() */
510+ CCS_TASK_EUID, /* current_euid() */
511+ CCS_TASK_SUID, /* current_suid() */
512+ CCS_TASK_FSUID, /* current_fsuid() */
513+ CCS_TASK_GID, /* current_gid() */
514+ CCS_TASK_EGID, /* current_egid() */
515+ CCS_TASK_SGID, /* current_sgid() */
516+ CCS_TASK_FSGID, /* current_fsgid() */
517+ CCS_TASK_PID, /* sys_getpid() */
518+ CCS_TASK_PPID, /* sys_getppid() */
519+ CCS_EXEC_ARGC, /* "struct linux_binprm *"->argc */
520+ CCS_EXEC_ENVC, /* "struct linux_binprm *"->envc */
521+ CCS_TYPE_IS_SOCKET, /* S_IFSOCK */
522+ CCS_TYPE_IS_SYMLINK, /* S_IFLNK */
523+ CCS_TYPE_IS_FILE, /* S_IFREG */
524+ CCS_TYPE_IS_BLOCK_DEV, /* S_IFBLK */
525+ CCS_TYPE_IS_DIRECTORY, /* S_IFDIR */
526+ CCS_TYPE_IS_CHAR_DEV, /* S_IFCHR */
527+ CCS_TYPE_IS_FIFO, /* S_IFIFO */
528+ CCS_MODE_SETUID, /* S_ISUID */
529+ CCS_MODE_SETGID, /* S_ISGID */
530+ CCS_MODE_STICKY, /* S_ISVTX */
531+ CCS_MODE_OWNER_READ, /* S_IRUSR */
532+ CCS_MODE_OWNER_WRITE, /* S_IWUSR */
533+ CCS_MODE_OWNER_EXECUTE, /* S_IXUSR */
534+ CCS_MODE_GROUP_READ, /* S_IRGRP */
535+ CCS_MODE_GROUP_WRITE, /* S_IWGRP */
536+ CCS_MODE_GROUP_EXECUTE, /* S_IXGRP */
537+ CCS_MODE_OTHERS_READ, /* S_IROTH */
538+ CCS_MODE_OTHERS_WRITE, /* S_IWOTH */
539+ CCS_MODE_OTHERS_EXECUTE, /* S_IXOTH */
540+ CCS_TASK_TYPE, /* ((u8) task->ccs_flags) &
541+ CCS_TASK_IS_EXECUTE_HANDLER */
542+ CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
543+ CCS_EXEC_REALPATH,
544+ CCS_SYMLINK_TARGET,
545+ CCS_PATH1_UID,
546+ CCS_PATH1_GID,
547+ CCS_PATH1_INO,
548+ CCS_PATH1_MAJOR,
549+ CCS_PATH1_MINOR,
550+ CCS_PATH1_PERM,
551+ CCS_PATH1_TYPE,
552+ CCS_PATH1_DEV_MAJOR,
553+ CCS_PATH1_DEV_MINOR,
554+ CCS_PATH2_UID,
555+ CCS_PATH2_GID,
556+ CCS_PATH2_INO,
557+ CCS_PATH2_MAJOR,
558+ CCS_PATH2_MINOR,
559+ CCS_PATH2_PERM,
560+ CCS_PATH2_TYPE,
561+ CCS_PATH2_DEV_MAJOR,
562+ CCS_PATH2_DEV_MINOR,
563+ CCS_PATH1_PARENT_UID,
564+ CCS_PATH1_PARENT_GID,
565+ CCS_PATH1_PARENT_INO,
566+ CCS_PATH1_PARENT_PERM,
567+ CCS_PATH2_PARENT_UID,
568+ CCS_PATH2_PARENT_GID,
569+ CCS_PATH2_PARENT_INO,
570+ CCS_PATH2_PARENT_PERM,
571+ CCS_MAX_CONDITION_KEYWORD,
572+ CCS_NUMBER_UNION,
573+ CCS_NAME_UNION,
574+ CCS_ARGV_ENTRY,
575+ CCS_ENVP_ENTRY,
576+};
577+
578+/* Index numbers for domain's attributes. */
579+enum ccs_domain_info_flags_index {
580+ /* Quota warnning flag. */
581+ CCS_DIF_QUOTA_WARNED,
582+ /*
583+ * This domain was unable to create a new domain at
584+ * ccs_find_next_domain() because the name of the domain to be created
585+ * was too long or it could not allocate memory.
586+ * More than one process continued execve() without domain transition.
587+ */
588+ CCS_DIF_TRANSITION_FAILED,
589+ CCS_MAX_DOMAIN_INFO_FLAGS
590+};
591+
592+/* Index numbers for audit type. */
593+enum ccs_grant_log {
594+ /* Follow profile's configuration. */
595+ CCS_GRANTLOG_AUTO,
596+ /* Do not generate grant log. */
597+ CCS_GRANTLOG_NO,
598+ /* Generate grant_log. */
599+ CCS_GRANTLOG_YES,
600+};
601+
602+/* Index numbers for group entries. */
603+enum ccs_group_id {
604+ CCS_PATH_GROUP,
605+ CCS_NUMBER_GROUP,
606+#ifdef CONFIG_CCSECURITY_NETWORK
607+ CCS_ADDRESS_GROUP,
608+#endif
609+ CCS_MAX_GROUP
610+};
611+
612+/* Index numbers for category of functionality. */
613+enum ccs_mac_category_index {
614+ CCS_MAC_CATEGORY_FILE,
615+#ifdef CONFIG_CCSECURITY_NETWORK
616+ CCS_MAC_CATEGORY_NETWORK,
617+#endif
618+#ifdef CONFIG_CCSECURITY_MISC
619+ CCS_MAC_CATEGORY_MISC,
620+#endif
621+#ifdef CONFIG_CCSECURITY_IPC
622+ CCS_MAC_CATEGORY_IPC,
623+#endif
624+#ifdef CONFIG_CCSECURITY_CAPABILITY
625+ CCS_MAC_CATEGORY_CAPABILITY,
626+#endif
627+ CCS_MAX_MAC_CATEGORY_INDEX
628+};
629+
630+/* Index numbers for functionality. */
631+enum ccs_mac_index {
632+ CCS_MAC_FILE_EXECUTE,
633+ CCS_MAC_FILE_OPEN,
634+ CCS_MAC_FILE_CREATE,
635+ CCS_MAC_FILE_UNLINK,
636+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
637+ CCS_MAC_FILE_GETATTR,
638+#endif
639+ CCS_MAC_FILE_MKDIR,
640+ CCS_MAC_FILE_RMDIR,
641+ CCS_MAC_FILE_MKFIFO,
642+ CCS_MAC_FILE_MKSOCK,
643+ CCS_MAC_FILE_TRUNCATE,
644+ CCS_MAC_FILE_SYMLINK,
645+ CCS_MAC_FILE_MKBLOCK,
646+ CCS_MAC_FILE_MKCHAR,
647+ CCS_MAC_FILE_LINK,
648+ CCS_MAC_FILE_RENAME,
649+ CCS_MAC_FILE_CHMOD,
650+ CCS_MAC_FILE_CHOWN,
651+ CCS_MAC_FILE_CHGRP,
652+ CCS_MAC_FILE_IOCTL,
653+ CCS_MAC_FILE_CHROOT,
654+ CCS_MAC_FILE_MOUNT,
655+ CCS_MAC_FILE_UMOUNT,
656+ CCS_MAC_FILE_PIVOT_ROOT,
657+#ifdef CONFIG_CCSECURITY_NETWORK
658+ CCS_MAC_NETWORK_INET_STREAM_BIND,
659+ CCS_MAC_NETWORK_INET_STREAM_LISTEN,
660+ CCS_MAC_NETWORK_INET_STREAM_CONNECT,
661+ CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
662+ CCS_MAC_NETWORK_INET_DGRAM_BIND,
663+ CCS_MAC_NETWORK_INET_DGRAM_SEND,
664+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
665+ CCS_MAC_NETWORK_INET_DGRAM_RECV,
666+#endif
667+ CCS_MAC_NETWORK_INET_RAW_BIND,
668+ CCS_MAC_NETWORK_INET_RAW_SEND,
669+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
670+ CCS_MAC_NETWORK_INET_RAW_RECV,
671+#endif
672+ CCS_MAC_NETWORK_UNIX_STREAM_BIND,
673+ CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
674+ CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
675+ CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
676+ CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
677+ CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
678+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
679+ CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
680+#endif
681+ CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
682+ CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
683+ CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
684+ CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
685+#endif
686+#ifdef CONFIG_CCSECURITY_MISC
687+ CCS_MAC_ENVIRON,
688+#endif
689+#ifdef CONFIG_CCSECURITY_IPC
690+ CCS_MAC_SIGNAL,
691+#endif
692+#ifdef CONFIG_CCSECURITY_CAPABILITY
693+ CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
694+ CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
695+ CCS_MAC_CAPABILITY_SYS_REBOOT,
696+ CCS_MAC_CAPABILITY_SYS_VHANGUP,
697+ CCS_MAC_CAPABILITY_SYS_SETTIME,
698+ CCS_MAC_CAPABILITY_SYS_NICE,
699+ CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
700+ CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
701+ CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
702+ CCS_MAC_CAPABILITY_SYS_PTRACE,
703+#endif
704+ CCS_MAX_MAC_INDEX
705+};
706+
707+/* Index numbers for /proc/ccs/stat interface. */
708+enum ccs_memory_stat_type {
709+ CCS_MEMORY_POLICY,
710+ CCS_MEMORY_AUDIT,
711+ CCS_MEMORY_QUERY,
712+ CCS_MAX_MEMORY_STAT
713+};
714+
715+/* Index numbers for access controls with one pathname and three numbers. */
716+enum ccs_mkdev_acl_index {
717+ CCS_TYPE_MKBLOCK,
718+ CCS_TYPE_MKCHAR,
719+ CCS_MAX_MKDEV_OPERATION
720+};
721+
722+/* Index numbers for operation mode. */
723+enum ccs_mode_value {
724+ CCS_CONFIG_DISABLED,
725+ CCS_CONFIG_LEARNING,
726+ CCS_CONFIG_PERMISSIVE,
727+ CCS_CONFIG_ENFORCING,
728+ CCS_CONFIG_MAX_MODE,
729+ CCS_CONFIG_WANT_REJECT_LOG = 64,
730+ CCS_CONFIG_WANT_GRANT_LOG = 128,
731+ CCS_CONFIG_USE_DEFAULT = 255,
732+};
733+
734+/* Index numbers for socket operations. */
735+enum ccs_network_acl_index {
736+ CCS_NETWORK_BIND, /* bind() operation. */
737+ CCS_NETWORK_LISTEN, /* listen() operation. */
738+ CCS_NETWORK_CONNECT, /* connect() operation. */
739+ CCS_NETWORK_ACCEPT, /* accept() operation. */
740+ CCS_NETWORK_SEND, /* send() operation. */
741+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
742+ CCS_NETWORK_RECV, /* recv() operation. */
743+#endif
744+ CCS_MAX_NETWORK_OPERATION
745+};
746+
747+/* Index numbers for access controls with two pathnames. */
748+enum ccs_path2_acl_index {
749+ CCS_TYPE_LINK,
750+ CCS_TYPE_RENAME,
751+ CCS_TYPE_PIVOT_ROOT,
752+ CCS_MAX_PATH2_OPERATION
753+};
754+
755+/* Index numbers for access controls with one pathname. */
756+enum ccs_path_acl_index {
757+ CCS_TYPE_EXECUTE,
758+ CCS_TYPE_READ,
759+ CCS_TYPE_WRITE,
760+ CCS_TYPE_APPEND,
761+ CCS_TYPE_UNLINK,
762+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
763+ CCS_TYPE_GETATTR,
764+#endif
765+ CCS_TYPE_RMDIR,
766+ CCS_TYPE_TRUNCATE,
767+ CCS_TYPE_SYMLINK,
768+ CCS_TYPE_CHROOT,
769+ CCS_TYPE_UMOUNT,
770+ CCS_MAX_PATH_OPERATION
771+};
772+
773+/* Index numbers for access controls with one pathname and one number. */
774+enum ccs_path_number_acl_index {
775+ CCS_TYPE_CREATE,
776+ CCS_TYPE_MKDIR,
777+ CCS_TYPE_MKFIFO,
778+ CCS_TYPE_MKSOCK,
779+ CCS_TYPE_IOCTL,
780+ CCS_TYPE_CHMOD,
781+ CCS_TYPE_CHOWN,
782+ CCS_TYPE_CHGRP,
783+ CCS_MAX_PATH_NUMBER_OPERATION
784+};
785+
786+/* Index numbers for stat(). */
787+enum ccs_path_stat_index {
788+ /* Do not change this order. */
789+ CCS_PATH1,
790+ CCS_PATH1_PARENT,
791+ CCS_PATH2,
792+ CCS_PATH2_PARENT,
793+ CCS_MAX_PATH_STAT
794+};
795+
796+/* Index numbers for entry type. */
797+enum ccs_policy_id {
798+#ifdef CONFIG_CCSECURITY_PORTRESERVE
799+ CCS_ID_RESERVEDPORT,
800+#endif
801+ CCS_ID_GROUP,
802+#ifdef CONFIG_CCSECURITY_NETWORK
803+ CCS_ID_ADDRESS_GROUP,
804+#endif
805+ CCS_ID_PATH_GROUP,
806+ CCS_ID_NUMBER_GROUP,
807+ CCS_ID_AGGREGATOR,
808+ CCS_ID_TRANSITION_CONTROL,
809+ CCS_ID_MANAGER,
810+ CCS_ID_CONDITION,
811+ CCS_ID_NAME,
812+ CCS_ID_ACL,
813+ CCS_ID_DOMAIN,
814+ CCS_MAX_POLICY
815+};
816+
817+/* Index numbers for /proc/ccs/stat interface. */
818+enum ccs_policy_stat_type {
819+ /* Do not change this order. */
820+ CCS_STAT_POLICY_UPDATES,
821+ CCS_STAT_POLICY_LEARNING, /* == CCS_CONFIG_LEARNING */
822+ CCS_STAT_POLICY_PERMISSIVE, /* == CCS_CONFIG_PERMISSIVE */
823+ CCS_STAT_POLICY_ENFORCING, /* == CCS_CONFIG_ENFORCING */
824+ CCS_MAX_POLICY_STAT
825+};
826+
827+/* Index numbers for profile's PREFERENCE values. */
828+enum ccs_pref_index {
829+ CCS_PREF_MAX_AUDIT_LOG,
830+ CCS_PREF_MAX_LEARNING_ENTRY,
831+ CCS_PREF_ENFORCING_PENALTY,
832+ CCS_MAX_PREF
833+};
834+
835+/* Index numbers for /proc/ccs/ interfaces. */
836+enum ccs_proc_interface_index {
837+ CCS_DOMAIN_POLICY,
838+ CCS_EXCEPTION_POLICY,
839+ CCS_PROCESS_STATUS,
840+ CCS_STAT,
841+ CCS_AUDIT,
842+ CCS_VERSION,
843+ CCS_PROFILE,
844+ CCS_QUERY,
845+ CCS_MANAGER,
846+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
847+ CCS_EXECUTE_HANDLER,
848+#endif
849+};
850+
851+/* Index numbers for special mount operations. */
852+enum ccs_special_mount {
853+ CCS_MOUNT_BIND, /* mount --bind /source /dest */
854+ CCS_MOUNT_MOVE, /* mount --move /old /new */
855+ CCS_MOUNT_REMOUNT, /* mount -o remount /dir */
856+ CCS_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
857+ CCS_MOUNT_MAKE_PRIVATE, /* mount --make-private /dir */
858+ CCS_MOUNT_MAKE_SLAVE, /* mount --make-slave /dir */
859+ CCS_MOUNT_MAKE_SHARED, /* mount --make-shared /dir */
860+ CCS_MAX_SPECIAL_MOUNT
861+};
862+
863+/* Index numbers for domain transition control keywords. */
864+enum ccs_transition_type {
865+ /* Do not change this order, */
866+ CCS_TRANSITION_CONTROL_NO_RESET,
867+ CCS_TRANSITION_CONTROL_RESET,
868+ CCS_TRANSITION_CONTROL_NO_INITIALIZE,
869+ CCS_TRANSITION_CONTROL_INITIALIZE,
870+ CCS_TRANSITION_CONTROL_NO_KEEP,
871+ CCS_TRANSITION_CONTROL_KEEP,
872+ CCS_MAX_TRANSITION_TYPE
873+};
874+
875+/* Index numbers for type of numeric values. */
876+enum ccs_value_type {
877+ CCS_VALUE_TYPE_INVALID,
878+ CCS_VALUE_TYPE_DECIMAL,
879+ CCS_VALUE_TYPE_OCTAL,
880+ CCS_VALUE_TYPE_HEXADECIMAL,
881+};
882+
883+/* Constants definition for internal use. */
884+
885+/*
886+ * TOMOYO uses this hash only when appending a string into the string table.
887+ * Frequency of appending strings is very low. So we don't need large (e.g.
888+ * 64k) hash size. 256 will be sufficient.
889+ */
890+#define CCS_HASH_BITS 8
891+#define CCS_MAX_HASH (1u << CCS_HASH_BITS)
892+
893+/*
894+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
895+ * Therefore, we don't need SOCK_MAX.
896+ */
897+#define CCS_SOCK_MAX 6
898+
899+/* Size of temporary buffer for execve() operation. */
900+#define CCS_EXEC_TMPSIZE 4096
901+
902+/* Garbage collector is trying to kfree() this element. */
903+#define CCS_GC_IN_PROGRESS -1
904+
905+/* Profile number is an integer between 0 and 255. */
906+#define CCS_MAX_PROFILES 256
907+
908+/* Group number is an integer between 0 and 255. */
909+#define CCS_MAX_ACL_GROUPS 256
910+
911+/* Current thread is doing open(O_RDONLY | O_TRUNC) ? */
912+#define CCS_OPEN_FOR_READ_TRUNCATE 1
913+/* Current thread is doing open(3) ? */
914+#define CCS_OPEN_FOR_IOCTL_ONLY 2
915+/* Current thread is doing do_execve() ? */
916+#define CCS_TASK_IS_IN_EXECVE 4
917+/* Current thread is running as an execute handler program? */
918+#define CCS_TASK_IS_EXECUTE_HANDLER 8
919+/* Current thread is allowed to modify policy via /proc/ccs/ interface? */
920+#define CCS_TASK_IS_MANAGER 16
921+
922+/*
923+ * Retry this request. Returned by ccs_supervisor() if policy violation has
924+ * occurred in enforcing mode and the userspace daemon decided to retry.
925+ *
926+ * We must choose a positive value in order to distinguish "granted" (which is
927+ * 0) and "rejected" (which is a negative value) and "retry".
928+ */
929+#define CCS_RETRY_REQUEST 1
930+
931+/* Ignore gfp flags which are not supported. */
932+#ifndef __GFP_HIGHIO
933+#define __GFP_HIGHIO 0
934+#endif
935+#ifndef __GFP_NOWARN
936+#define __GFP_NOWARN 0
937+#endif
938+#ifndef __GFP_NORETRY
939+#define __GFP_NORETRY 0
940+#endif
941+#ifndef __GFP_NOMEMALLOC
942+#define __GFP_NOMEMALLOC 0
943+#endif
944+
945+/* The gfp flags used by TOMOYO. */
946+#define CCS_GFP_FLAGS (__GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_NOWARN | \
947+ __GFP_NORETRY | __GFP_NOMEMALLOC)
948+
949+/* Size of read buffer for /proc/ccs/ interface. */
950+#define CCS_MAX_IO_READ_QUEUE 64
951+
952+/* Structure definition for internal use. */
953+
954+/* Common header for holding ACL entries. */
955+struct ccs_acl_head {
956+ struct list_head list;
957+ s8 is_deleted; /* true or false or CCS_GC_IN_PROGRESS */
958+} __packed;
959+
960+/* Common header for shared entries. */
961+struct ccs_shared_acl_head {
962+ struct list_head list;
963+ atomic_t users;
964+} __packed;
965+
966+/* Common header for individual entries. */
967+struct ccs_acl_info {
968+ struct list_head list;
969+ struct ccs_condition *cond; /* Maybe NULL. */
970+ s8 is_deleted; /* true or false or CCS_GC_IN_PROGRESS */
971+ u8 type; /* One of values in "enum ccs_acl_entry_type_index". */
972+ u16 perm;
973+} __packed;
974+
975+/* Structure for holding a word. */
976+struct ccs_name_union {
977+ /* Either @filename or @group is NULL. */
978+ const struct ccs_path_info *filename;
979+ struct ccs_group *group;
980+};
981+
982+/* Structure for holding a number. */
983+struct ccs_number_union {
984+ unsigned long values[2];
985+ struct ccs_group *group; /* Maybe NULL. */
986+ /* One of values in "enum ccs_value_type". */
987+ u8 value_type[2];
988+};
989+
990+/* Structure for holding an IP address. */
991+struct ccs_ipaddr_union {
992+ struct in6_addr ip[2]; /* Big endian. */
993+ struct ccs_group *group; /* Pointer to address group. */
994+ bool is_ipv6; /* Valid only if @group == NULL. */
995+};
996+
997+/* Structure for "path_group"/"number_group"/"address_group" directive. */
998+struct ccs_group {
999+ struct ccs_shared_acl_head head;
1000+ /* Name of group (without leading '@'). */
1001+ const struct ccs_path_info *group_name;
1002+ /*
1003+ * List of "struct ccs_path_group" or "struct ccs_number_group" or
1004+ * "struct ccs_address_group".
1005+ */
1006+ struct list_head member_list;
1007+};
1008+
1009+/* Structure for "path_group" directive. */
1010+struct ccs_path_group {
1011+ struct ccs_acl_head head;
1012+ const struct ccs_path_info *member_name;
1013+};
1014+
1015+/* Structure for "number_group" directive. */
1016+struct ccs_number_group {
1017+ struct ccs_acl_head head;
1018+ struct ccs_number_union number;
1019+};
1020+
1021+/* Structure for "address_group" directive. */
1022+struct ccs_address_group {
1023+ struct ccs_acl_head head;
1024+ /* Structure for holding an IP address. */
1025+ struct ccs_ipaddr_union address;
1026+};
1027+
1028+/* Subset of "struct stat". Used by conditional ACL and audit logs. */
1029+struct ccs_mini_stat {
1030+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
1031+ kuid_t uid;
1032+ kgid_t gid;
1033+#else
1034+ uid_t uid;
1035+ gid_t gid;
1036+#endif
1037+ ino_t ino;
1038+ umode_t mode;
1039+ dev_t dev;
1040+ dev_t rdev;
1041+};
1042+
1043+/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
1044+struct ccs_page_dump {
1045+ struct page *page; /* Previously dumped page. */
1046+ char *data; /* Contents of "page". Size is PAGE_SIZE. */
1047+};
1048+
1049+/* Structure for attribute checks in addition to pathname checks. */
1050+struct ccs_obj_info {
1051+ /* True if ccs_get_attributes() was already called, false otherwise. */
1052+ bool validate_done;
1053+ /* True if @stat[] is valid. */
1054+ bool stat_valid[CCS_MAX_PATH_STAT];
1055+ /* First pathname. Initialized with { NULL, NULL } if no path. */
1056+ struct path path1;
1057+ /* Second pathname. Initialized with { NULL, NULL } if no path. */
1058+ struct path path2;
1059+ /*
1060+ * Information on @path1, @path1's parent directory, @path2, @path2's
1061+ * parent directory.
1062+ */
1063+ struct ccs_mini_stat stat[CCS_MAX_PATH_STAT];
1064+ /*
1065+ * Content of symbolic link to be created. NULL for operations other
1066+ * than symlink().
1067+ */
1068+ struct ccs_path_info *symlink_target;
1069+};
1070+
1071+/* Structure for entries which follows "struct ccs_condition". */
1072+struct ccs_condition_element {
1073+ /*
1074+ * Left hand operand. A "struct ccs_argv" for CCS_ARGV_ENTRY, a
1075+ * "struct ccs_envp" for CCS_ENVP_ENTRY is attached to the tail
1076+ * of the array of this struct.
1077+ */
1078+ u8 left;
1079+ /*
1080+ * Right hand operand. A "struct ccs_number_union" for
1081+ * CCS_NUMBER_UNION, a "struct ccs_name_union" for CCS_NAME_UNION is
1082+ * attached to the tail of the array of this struct.
1083+ */
1084+ u8 right;
1085+ /* Equation operator. True if equals or overlaps, false otherwise. */
1086+ bool equals;
1087+};
1088+
1089+/* Structure for optional arguments. */
1090+struct ccs_condition {
1091+ struct ccs_shared_acl_head head;
1092+ u32 size; /* Memory size allocated for this entry. */
1093+ u16 condc; /* Number of conditions in this struct. */
1094+ u16 numbers_count; /* Number of "struct ccs_number_union values". */
1095+ u16 names_count; /* Number of "struct ccs_name_union names". */
1096+ u16 argc; /* Number of "struct ccs_argv". */
1097+ u16 envc; /* Number of "struct ccs_envp". */
1098+ u8 grant_log; /* One of values in "enum ccs_grant_log". */
1099+ bool exec_transit; /* True if transit is for "file execute". */
1100+ const struct ccs_path_info *transit; /* Maybe NULL. */
1101+ /*
1102+ * struct ccs_condition_element condition[condc];
1103+ * struct ccs_number_union values[numbers_count];
1104+ * struct ccs_name_union names[names_count];
1105+ * struct ccs_argv argv[argc];
1106+ * struct ccs_envp envp[envc];
1107+ */
1108+};
1109+
1110+struct ccs_execve;
1111+struct ccs_policy_namespace;
1112+
1113+/* Structure for request info. */
1114+struct ccs_request_info {
1115+ /*
1116+ * For holding parameters specific to operations which deal files.
1117+ * NULL if not dealing files.
1118+ */
1119+ struct ccs_obj_info *obj;
1120+ /*
1121+ * For holding parameters specific to execve() request.
1122+ * NULL if not dealing do_execve().
1123+ */
1124+ struct ccs_execve *ee;
1125+ /*
1126+ * For holding parameters.
1127+ * Pointers in this union are not NULL except path->matched_path.
1128+ */
1129+ union {
1130+ struct {
1131+ const struct ccs_path_info *filename;
1132+ /*
1133+ * For using wildcards at ccs_find_next_domain().
1134+ *
1135+ * The matched_acl cannot be used because it may refer
1136+ * a "struct ccs_path_acl" with ->is_group == true.
1137+ * We want to use exact "struct ccs_path_info" rather
1138+ * than "struct ccs_path_acl".
1139+ */
1140+ const struct ccs_path_info *matched_path;
1141+ /* One of values in "enum ccs_path_acl_index". */
1142+ u8 operation;
1143+ } path;
1144+ struct {
1145+ const struct ccs_path_info *filename1;
1146+ const struct ccs_path_info *filename2;
1147+ /* One of values in "enum ccs_path2_acl_index". */
1148+ u8 operation;
1149+ } path2;
1150+ struct {
1151+ const struct ccs_path_info *filename;
1152+ unsigned int mode;
1153+ unsigned int major;
1154+ unsigned int minor;
1155+ /* One of values in "enum ccs_mkdev_acl_index". */
1156+ u8 operation;
1157+ } mkdev;
1158+ struct {
1159+ const struct ccs_path_info *filename;
1160+ unsigned long number;
1161+ /*
1162+ * One of values in "enum ccs_path_number_acl_index".
1163+ */
1164+ u8 operation;
1165+ } path_number;
1166+#ifdef CONFIG_CCSECURITY_NETWORK
1167+ struct {
1168+ const u32 *address; /* Big endian. */
1169+ u16 port; /* Host endian. */
1170+ /* One of values smaller than CCS_SOCK_MAX. */
1171+ u8 protocol;
1172+ /* One of values in "enum ccs_network_acl_index". */
1173+ u8 operation;
1174+ bool is_ipv6;
1175+ } inet_network;
1176+ struct {
1177+ const struct ccs_path_info *address;
1178+ /* One of values smaller than CCS_SOCK_MAX. */
1179+ u8 protocol;
1180+ /* One of values in "enum ccs_network_acl_index". */
1181+ u8 operation;
1182+ } unix_network;
1183+#endif
1184+#ifdef CONFIG_CCSECURITY_MISC
1185+ struct {
1186+ const struct ccs_path_info *name;
1187+ } environ;
1188+#endif
1189+#ifdef CONFIG_CCSECURITY_CAPABILITY
1190+ struct {
1191+ /* One of values in "enum ccs_capability_acl_index". */
1192+ u8 operation;
1193+ } capability;
1194+#endif
1195+#ifdef CONFIG_CCSECURITY_IPC
1196+ struct {
1197+ const char *dest_pattern;
1198+ int sig;
1199+ } signal;
1200+#endif
1201+ struct {
1202+ const struct ccs_path_info *type;
1203+ const struct ccs_path_info *dir;
1204+ const struct ccs_path_info *dev;
1205+ unsigned long flags;
1206+ int need_dev;
1207+ } mount;
1208+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
1209+ struct {
1210+ const struct ccs_path_info *domainname;
1211+ } task;
1212+#endif
1213+ } param;
1214+ /*
1215+ * For updating current->ccs_domain_info at ccs_update_task_domain().
1216+ * Initialized to NULL at ccs_init_request_info().
1217+ * Matching "struct ccs_acl_info" is copied if access request was
1218+ * granted. Re-initialized to NULL at ccs_update_task_domain().
1219+ */
1220+ struct ccs_acl_info *matched_acl;
1221+ u8 param_type; /* One of values in "enum ccs_acl_entry_type_index". */
1222+ bool granted; /* True if granted, false otherwise. */
1223+ /* True if current thread should not be carried sleep penalty. */
1224+ bool dont_sleep_on_enforce_error;
1225+ /*
1226+ * For counting number of retries made for this request.
1227+ * This counter is incremented whenever ccs_supervisor() returned
1228+ * CCS_RETRY_REQUEST.
1229+ */
1230+ u8 retry;
1231+ /*
1232+ * For holding profile number used for this request.
1233+ * One of values between 0 and CCS_MAX_PROFILES - 1.
1234+ */
1235+ u8 profile;
1236+ /*
1237+ * For holding operation mode used for this request.
1238+ * One of CCS_CONFIG_DISABLED, CCS_CONFIG_LEARNING,
1239+ * CCS_CONFIG_PERMISSIVE, CCS_CONFIG_ENFORCING.
1240+ */
1241+ u8 mode;
1242+ /*
1243+ * For holding operation index used for this request.
1244+ * Used by ccs_init_request_info() / ccs_get_mode() /
1245+ * ccs_write_log(). One of values in "enum ccs_mac_index".
1246+ */
1247+ u8 type;
1248+};
1249+
1250+/* Structure for holding a token. */
1251+struct ccs_path_info {
1252+ const char *name;
1253+ u32 hash; /* = full_name_hash(name, strlen(name)) */
1254+ u16 total_len; /* = strlen(name) */
1255+ u16 const_len; /* = ccs_const_part_length(name) */
1256+ bool is_dir; /* = ccs_strendswith(name, "/") */
1257+ bool is_patterned; /* = const_len < total_len */
1258+};
1259+
1260+/* Structure for execve() operation. */
1261+struct ccs_execve {
1262+ struct ccs_request_info r;
1263+ struct ccs_obj_info obj;
1264+ struct linux_binprm *bprm;
1265+ struct ccs_domain_info *previous_domain;
1266+ const struct ccs_path_info *transition;
1267+ /* For execute_handler */
1268+ const struct ccs_path_info *handler;
1269+ char *handler_path; /* = kstrdup(handler->name, CCS_GFP_FLAGS) */
1270+ /* For dumping argv[] and envp[]. */
1271+ struct ccs_page_dump dump;
1272+ /* For temporary use. */
1273+ char *tmp; /* Size is CCS_EXEC_TMPSIZE bytes */
1274+};
1275+
1276+/* Structure for domain information. */
1277+struct ccs_domain_info {
1278+ struct list_head list;
1279+ struct list_head acl_info_list;
1280+ /* Name of this domain. Never NULL. */
1281+ const struct ccs_path_info *domainname;
1282+ /* Namespace for this domain. Never NULL. */
1283+ struct ccs_policy_namespace *ns;
1284+ u8 profile; /* Profile number to use. */
1285+ u8 group; /* Group number to use. */
1286+ bool is_deleted; /* Delete flag. */
1287+ bool flags[CCS_MAX_DOMAIN_INFO_FLAGS];
1288+};
1289+
1290+/*
1291+ * Structure for "reset_domain"/"no_reset_domain"/"initialize_domain"/
1292+ * "no_initialize_domain"/"keep_domain"/"no_keep_domain" keyword.
1293+ */
1294+struct ccs_transition_control {
1295+ struct ccs_acl_head head;
1296+ u8 type; /* One of values in "enum ccs_transition_type" */
1297+ bool is_last_name; /* True if the domainname is ccs_last_word(). */
1298+ const struct ccs_path_info *domainname; /* Maybe NULL */
1299+ const struct ccs_path_info *program; /* Maybe NULL */
1300+};
1301+
1302+/* Structure for "aggregator" keyword. */
1303+struct ccs_aggregator {
1304+ struct ccs_acl_head head;
1305+ const struct ccs_path_info *original_name;
1306+ const struct ccs_path_info *aggregated_name;
1307+};
1308+
1309+/* Structure for "deny_autobind" keyword. */
1310+struct ccs_reserved {
1311+ struct ccs_acl_head head;
1312+ struct ccs_number_union port;
1313+};
1314+
1315+/* Structure for policy manager. */
1316+struct ccs_manager {
1317+ struct ccs_acl_head head;
1318+ /* A path to program or a domainname. */
1319+ const struct ccs_path_info *manager;
1320+};
1321+
1322+/* Structure for argv[]. */
1323+struct ccs_argv {
1324+ unsigned long index;
1325+ const struct ccs_path_info *value;
1326+ bool is_not;
1327+};
1328+
1329+/* Structure for envp[]. */
1330+struct ccs_envp {
1331+ const struct ccs_path_info *name;
1332+ const struct ccs_path_info *value;
1333+ bool is_not;
1334+};
1335+
1336+/*
1337+ * Structure for "task auto_execute_handler" and "task denied_execute_handler"
1338+ * directive.
1339+ *
1340+ * If "task auto_execute_handler" directive exists and the current process is
1341+ * not an execute handler, all execve() requests are replaced by execve()
1342+ * requests of a program specified by "task auto_execute_handler" directive.
1343+ * If the current process is an execute handler, "task auto_execute_handler"
1344+ * and "task denied_execute_handler" directives are ignored.
1345+ * The program specified by "task execute_handler" validates execve()
1346+ * parameters and executes the original execve() requests if appropriate.
1347+ *
1348+ * "task denied_execute_handler" directive is used only when execve() request
1349+ * was rejected in enforcing mode (i.e. CONFIG::file::execute={ mode=enforcing
1350+ * }). The program specified by "task denied_execute_handler" does whatever it
1351+ * wants to do (e.g. silently terminate, change firewall settings, redirect the
1352+ * user to honey pot etc.).
1353+ */
1354+struct ccs_handler_acl {
1355+ struct ccs_acl_info head; /* type = CCS_TYPE_*_EXECUTE_HANDLER */
1356+ const struct ccs_path_info *handler; /* Pointer to single pathname. */
1357+};
1358+
1359+/*
1360+ * Structure for "task auto_domain_transition" and
1361+ * "task manual_domain_transition" directive.
1362+ */
1363+struct ccs_task_acl {
1364+ struct ccs_acl_info head; /* type = CCS_TYPE_*_TASK_ACL */
1365+ /* Pointer to domainname. */
1366+ const struct ccs_path_info *domainname;
1367+};
1368+
1369+/*
1370+ * Structure for "file execute", "file read", "file write", "file append",
1371+ * "file unlink", "file getattr", "file rmdir", "file truncate",
1372+ * "file symlink", "file chroot" and "file unmount" directive.
1373+ */
1374+struct ccs_path_acl {
1375+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_ACL */
1376+ struct ccs_name_union name;
1377+};
1378+
1379+/*
1380+ * Structure for "file rename", "file link" and "file pivot_root" directive.
1381+ */
1382+struct ccs_path2_acl {
1383+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH2_ACL */
1384+ struct ccs_name_union name1;
1385+ struct ccs_name_union name2;
1386+};
1387+
1388+/*
1389+ * Structure for "file create", "file mkdir", "file mkfifo", "file mksock",
1390+ * "file ioctl", "file chmod", "file chown" and "file chgrp" directive.
1391+ */
1392+struct ccs_path_number_acl {
1393+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_NUMBER_ACL */
1394+ struct ccs_name_union name;
1395+ struct ccs_number_union number;
1396+};
1397+
1398+/* Structure for "file mkblock" and "file mkchar" directive. */
1399+struct ccs_mkdev_acl {
1400+ struct ccs_acl_info head; /* type = CCS_TYPE_MKDEV_ACL */
1401+ struct ccs_name_union name;
1402+ struct ccs_number_union mode;
1403+ struct ccs_number_union major;
1404+ struct ccs_number_union minor;
1405+};
1406+
1407+/* Structure for "file mount" directive. */
1408+struct ccs_mount_acl {
1409+ struct ccs_acl_info head; /* type = CCS_TYPE_MOUNT_ACL */
1410+ struct ccs_name_union dev_name;
1411+ struct ccs_name_union dir_name;
1412+ struct ccs_name_union fs_type;
1413+ struct ccs_number_union flags;
1414+};
1415+
1416+/* Structure for "misc env" directive in domain policy. */
1417+struct ccs_env_acl {
1418+ struct ccs_acl_info head; /* type = CCS_TYPE_ENV_ACL */
1419+ const struct ccs_path_info *env; /* environment variable */
1420+};
1421+
1422+/* Structure for "capability" directive. */
1423+struct ccs_capability_acl {
1424+ struct ccs_acl_info head; /* type = CCS_TYPE_CAPABILITY_ACL */
1425+ u8 operation; /* One of values in "enum ccs_capability_acl_index". */
1426+};
1427+
1428+/* Structure for "ipc signal" directive. */
1429+struct ccs_signal_acl {
1430+ struct ccs_acl_info head; /* type = CCS_TYPE_SIGNAL_ACL */
1431+ struct ccs_number_union sig;
1432+ /* Pointer to destination pattern. */
1433+ const struct ccs_path_info *domainname;
1434+};
1435+
1436+/* Structure for "network inet" directive. */
1437+struct ccs_inet_acl {
1438+ struct ccs_acl_info head; /* type = CCS_TYPE_INET_ACL */
1439+ u8 protocol;
1440+ struct ccs_ipaddr_union address;
1441+ struct ccs_number_union port;
1442+};
1443+
1444+/* Structure for "network unix" directive. */
1445+struct ccs_unix_acl {
1446+ struct ccs_acl_info head; /* type = CCS_TYPE_UNIX_ACL */
1447+ u8 protocol;
1448+ struct ccs_name_union name;
1449+};
1450+
1451+/* Structure for holding string data. */
1452+struct ccs_name {
1453+ struct ccs_shared_acl_head head;
1454+ int size; /* Memory size allocated for this entry. */
1455+ struct ccs_path_info entry;
1456+};
1457+
1458+/* Structure for holding a line from /proc/ccs/ interface. */
1459+struct ccs_acl_param {
1460+ char *data; /* Unprocessed data. */
1461+ struct list_head *list; /* List to add or remove. */
1462+ struct ccs_policy_namespace *ns; /* Namespace to use. */
1463+ bool is_delete; /* True if it is a delete request. */
1464+ union ccs_acl_union {
1465+ struct ccs_acl_info acl_info;
1466+ struct ccs_handler_acl handler_acl;
1467+ struct ccs_task_acl task_acl;
1468+ struct ccs_path_acl path_acl;
1469+ struct ccs_path2_acl path2_acl;
1470+ struct ccs_path_number_acl path_number_acl;
1471+ struct ccs_mkdev_acl mkdev_acl;
1472+ struct ccs_mount_acl mount_acl;
1473+ struct ccs_env_acl env_acl;
1474+ struct ccs_capability_acl capability_acl;
1475+ struct ccs_signal_acl signal_acl;
1476+ struct ccs_inet_acl inet_acl;
1477+ struct ccs_unix_acl unix_acl;
1478+ /**/
1479+ struct ccs_acl_head acl_head;
1480+ struct ccs_transition_control transition_control;
1481+ struct ccs_aggregator aggregator;
1482+ struct ccs_reserved reserved;
1483+ struct ccs_manager manager;
1484+ struct ccs_path_group path_group;
1485+ struct ccs_number_group number_group;
1486+ struct ccs_address_group address_group;
1487+ } e;
1488+};
1489+
1490+/* Structure for reading/writing policy via /proc/ccs/ interfaces. */
1491+struct ccs_io_buffer {
1492+ /* Exclusive lock for this structure. */
1493+ struct mutex io_sem;
1494+ char __user *read_user_buf;
1495+ size_t read_user_buf_avail;
1496+ struct {
1497+ struct list_head *ns;
1498+ struct list_head *domain;
1499+ struct list_head *group;
1500+ struct list_head *acl;
1501+ size_t avail;
1502+ unsigned int step;
1503+ unsigned int query_index;
1504+ u16 index;
1505+ u16 cond_index;
1506+ u8 acl_group_index;
1507+ u8 cond_step;
1508+ u8 bit;
1509+ u8 w_pos;
1510+ bool eof;
1511+ bool print_this_domain_only;
1512+ bool print_transition_related_only;
1513+ bool print_cond_part;
1514+ const char *w[CCS_MAX_IO_READ_QUEUE];
1515+ } r;
1516+ struct {
1517+ struct ccs_policy_namespace *ns;
1518+ struct ccs_domain_info *domain;
1519+ size_t avail;
1520+ bool is_delete;
1521+ } w;
1522+ /* Buffer for reading. */
1523+ char *read_buf;
1524+ /* Size of read buffer. */
1525+ size_t readbuf_size;
1526+ /* Buffer for writing. */
1527+ char *write_buf;
1528+ /* Size of write buffer. */
1529+ size_t writebuf_size;
1530+ /* Type of interface. */
1531+ enum ccs_proc_interface_index type;
1532+ /* Users counter protected by ccs_io_buffer_list_lock. */
1533+ u8 users;
1534+ /* List for telling GC not to kfree() elements. */
1535+ struct list_head list;
1536+};
1537+
1538+/* Structure for /proc/ccs/profile interface. */
1539+struct ccs_profile {
1540+ const struct ccs_path_info *comment;
1541+ u8 default_config;
1542+ u8 config[CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX];
1543+ unsigned int pref[CCS_MAX_PREF];
1544+};
1545+
1546+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
1547+struct ccs_time {
1548+ u16 year;
1549+ u8 month;
1550+ u8 day;
1551+ u8 hour;
1552+ u8 min;
1553+ u8 sec;
1554+};
1555+
1556+/* Structure for policy namespace. */
1557+struct ccs_policy_namespace {
1558+ /* Profile table. Memory is allocated as needed. */
1559+ struct ccs_profile *profile_ptr[CCS_MAX_PROFILES];
1560+ /* List of "struct ccs_group". */
1561+ struct list_head group_list[CCS_MAX_GROUP];
1562+ /* List of policy. */
1563+ struct list_head policy_list[CCS_MAX_POLICY];
1564+ /* The global ACL referred by "use_group" keyword. */
1565+ struct list_head acl_group[CCS_MAX_ACL_GROUPS];
1566+ /* List for connecting to ccs_namespace_list list. */
1567+ struct list_head namespace_list;
1568+ /* Profile version. Currently only 20100903 is defined. */
1569+ unsigned int profile_version;
1570+ /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
1571+ const char *name;
1572+};
1573+
1574+/* Prototype definition for "struct ccsecurity_operations". */
1575+
1576+void __init ccs_permission_init(void);
1577+void __init ccs_mm_init(void);
1578+
1579+/* Prototype definition for internal use. */
1580+
1581+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1582+ struct ccs_page_dump *dump);
1583+bool ccs_memory_ok(const void *ptr, const unsigned int size);
1584+char *ccs_encode(const char *str);
1585+char *ccs_encode2(const char *str, int str_len);
1586+char *ccs_realpath(struct path *path);
1587+const char *ccs_get_exe(void);
1588+const struct ccs_path_info *ccs_get_name(const char *name);
1589+int ccs_audit_log(struct ccs_request_info *r);
1590+int ccs_check_acl(struct ccs_request_info *r);
1591+int ccs_init_request_info(struct ccs_request_info *r, const u8 index);
1592+struct ccs_domain_info *ccs_assign_domain(const char *domainname,
1593+ const bool transit);
1594+u8 ccs_get_config(const u8 profile, const u8 index);
1595+void *ccs_commit_ok(void *data, const unsigned int size);
1596+void ccs_del_acl(struct list_head *element);
1597+void ccs_del_condition(struct list_head *element);
1598+void ccs_fill_path_info(struct ccs_path_info *ptr);
1599+void ccs_get_attributes(struct ccs_obj_info *obj);
1600+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
1601+void ccs_transition_failed(const char *domainname);
1602+void ccs_warn_oom(const char *function);
1603+void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...)
1604+ __printf(2, 3);
1605+
1606+/* Variable definition for internal use. */
1607+
1608+extern bool ccs_policy_loaded;
1609+extern const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS];
1610+extern const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX];
1611+extern const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION];
1612+extern const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION];
1613+extern const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION];
1614+extern struct ccs_domain_info ccs_kernel_domain;
1615+extern struct list_head ccs_condition_list;
1616+extern struct list_head ccs_domain_list;
1617+extern struct list_head ccs_name_list[CCS_MAX_HASH];
1618+extern struct list_head ccs_namespace_list;
1619+extern struct mutex ccs_policy_lock;
1620+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1621+extern struct srcu_struct ccs_ss;
1622+#endif
1623+extern unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
1624+extern unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
1625+
1626+/* Inlined functions for internal use. */
1627+
1628+/**
1629+ * ccs_pathcmp - strcmp() for "struct ccs_path_info" structure.
1630+ *
1631+ * @a: Pointer to "struct ccs_path_info".
1632+ * @b: Pointer to "struct ccs_path_info".
1633+ *
1634+ * Returns true if @a != @b, false otherwise.
1635+ */
1636+static inline bool ccs_pathcmp(const struct ccs_path_info *a,
1637+ const struct ccs_path_info *b)
1638+{
1639+ return a->hash != b->hash || strcmp(a->name, b->name);
1640+}
1641+
1642+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1643+
1644+/**
1645+ * ccs_read_lock - Take lock for protecting policy.
1646+ *
1647+ * Returns index number for ccs_read_unlock().
1648+ */
1649+static inline int ccs_read_lock(void)
1650+{
1651+ return srcu_read_lock(&ccs_ss);
1652+}
1653+
1654+/**
1655+ * ccs_read_unlock - Release lock for protecting policy.
1656+ *
1657+ * @idx: Index number returned by ccs_read_lock().
1658+ *
1659+ * Returns nothing.
1660+ */
1661+static inline void ccs_read_unlock(const int idx)
1662+{
1663+ srcu_read_unlock(&ccs_ss, idx);
1664+}
1665+
1666+#else
1667+
1668+int ccs_lock(void);
1669+void ccs_unlock(const int idx);
1670+
1671+/**
1672+ * ccs_read_lock - Take lock for protecting policy.
1673+ *
1674+ * Returns index number for ccs_read_unlock().
1675+ */
1676+static inline int ccs_read_lock(void)
1677+{
1678+ return ccs_lock();
1679+}
1680+
1681+/**
1682+ * ccs_read_unlock - Release lock for protecting policy.
1683+ *
1684+ * @idx: Index number returned by ccs_read_lock().
1685+ *
1686+ * Returns nothing.
1687+ */
1688+static inline void ccs_read_unlock(const int idx)
1689+{
1690+ ccs_unlock(idx);
1691+}
1692+
1693+#endif
1694+
1695+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
1696+
1697+/**
1698+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
1699+ *
1700+ * Returns nothing.
1701+ */
1702+static inline void ccs_tasklist_lock(void)
1703+{
1704+ rcu_read_lock();
1705+}
1706+
1707+/**
1708+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
1709+ *
1710+ * Returns nothing.
1711+ */
1712+static inline void ccs_tasklist_unlock(void)
1713+{
1714+ rcu_read_unlock();
1715+}
1716+
1717+#else
1718+
1719+/**
1720+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
1721+ *
1722+ * Returns nothing.
1723+ */
1724+static inline void ccs_tasklist_lock(void)
1725+{
1726+ read_lock(&tasklist_lock);
1727+}
1728+
1729+/**
1730+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
1731+ *
1732+ * Returns nothing.
1733+ */
1734+static inline void ccs_tasklist_unlock(void)
1735+{
1736+ read_unlock(&tasklist_lock);
1737+}
1738+
1739+#endif
1740+
1741+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1742+
1743+/**
1744+ * ccs_sys_getppid - Copy of getppid().
1745+ *
1746+ * Returns parent process's PID.
1747+ *
1748+ * Alpha does not have getppid() defined. To be able to build this module on
1749+ * Alpha, I have to copy getppid() from kernel/timer.c.
1750+ */
1751+static inline pid_t ccs_sys_getppid(void)
1752+{
1753+ pid_t pid;
1754+ rcu_read_lock();
1755+ pid = task_tgid_vnr(rcu_dereference(current->real_parent));
1756+ rcu_read_unlock();
1757+ return pid;
1758+}
1759+
1760+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1761+
1762+/**
1763+ * ccs_sys_getppid - Copy of getppid().
1764+ *
1765+ * Returns parent process's PID.
1766+ *
1767+ * This function was rewritten to use RCU in 2.6.16.34. However, distributors
1768+ * which use earlier kernels (e.g. 2.6.8/2.6.9) did not backport the bugfix.
1769+ * Therefore, I'm using code for 2.6.16.34 for earlier kernels.
1770+ */
1771+static inline pid_t ccs_sys_getppid(void)
1772+{
1773+ pid_t pid;
1774+ rcu_read_lock();
1775+#if (defined(RHEL_MAJOR) && RHEL_MAJOR == 5) || (defined(AX_MAJOR) && AX_MAJOR == 3)
1776+ pid = rcu_dereference(current->parent)->tgid;
1777+#elif defined(CONFIG_UTRACE)
1778+ /*
1779+ * RHEL 5.0 kernel does not have RHEL_MAJOR/RHEL_MINOR defined.
1780+ * Assume RHEL 5.0 if CONFIG_UTRACE is defined.
1781+ */
1782+ pid = rcu_dereference(current->parent)->tgid;
1783+#else
1784+ pid = rcu_dereference(current->real_parent)->tgid;
1785+#endif
1786+ rcu_read_unlock();
1787+ return pid;
1788+}
1789+
1790+#else
1791+
1792+/**
1793+ * ccs_sys_getppid - Copy of getppid().
1794+ *
1795+ * Returns parent process's PID.
1796+ *
1797+ * I can't use code for 2.6.16.34 for 2.4 kernels because 2.4 kernels does not
1798+ * have RCU. Therefore, I'm using pessimistic lock (i.e. tasklist_lock
1799+ * spinlock).
1800+ */
1801+static inline pid_t ccs_sys_getppid(void)
1802+{
1803+ pid_t pid;
1804+ read_lock(&tasklist_lock);
1805+#ifdef TASK_DEAD
1806+ pid = current->group_leader->real_parent->tgid;
1807+#else
1808+ pid = current->p_opptr->pid;
1809+#endif
1810+ read_unlock(&tasklist_lock);
1811+ return pid;
1812+}
1813+
1814+#endif
1815+
1816+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1817+
1818+/**
1819+ * ccs_sys_getpid - Copy of getpid().
1820+ *
1821+ * Returns current thread's PID.
1822+ *
1823+ * Alpha does not have getpid() defined. To be able to build this module on
1824+ * Alpha, I have to copy getpid() from kernel/timer.c.
1825+ */
1826+static inline pid_t ccs_sys_getpid(void)
1827+{
1828+ return task_tgid_vnr(current);
1829+}
1830+
1831+#else
1832+
1833+/**
1834+ * ccs_sys_getpid - Copy of getpid().
1835+ *
1836+ * Returns current thread's PID.
1837+ */
1838+static inline pid_t ccs_sys_getpid(void)
1839+{
1840+ return current->tgid;
1841+}
1842+
1843+#endif
1844+
1845+/**
1846+ * ccs_get_mode - Get mode for specified functionality.
1847+ *
1848+ * @profile: Profile number.
1849+ * @index: Functionality number.
1850+ *
1851+ * Returns mode.
1852+ */
1853+static inline u8 ccs_get_mode(const u8 profile, const u8 index)
1854+{
1855+ return ccs_get_config(profile, index) & (CCS_CONFIG_MAX_MODE - 1);
1856+}
1857+
1858+#if defined(CONFIG_SLOB)
1859+
1860+/**
1861+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
1862+ *
1863+ * @size: Size to be rounded up.
1864+ *
1865+ * Returns @size.
1866+ *
1867+ * Since SLOB does not round up, this function simply returns @size.
1868+ */
1869+static inline int ccs_round2(size_t size)
1870+{
1871+ return size;
1872+}
1873+
1874+#else
1875+
1876+/**
1877+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
1878+ *
1879+ * @size: Size to be rounded up.
1880+ *
1881+ * Returns rounded size.
1882+ *
1883+ * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
1884+ * (e.g.) 128 bytes.
1885+ */
1886+static inline int ccs_round2(size_t size)
1887+{
1888+#if PAGE_SIZE == 4096
1889+ size_t bsize = 32;
1890+#else
1891+ size_t bsize = 64;
1892+#endif
1893+ if (!size)
1894+ return 0;
1895+ while (size > bsize)
1896+ bsize <<= 1;
1897+ return bsize;
1898+}
1899+
1900+#endif
1901+
1902+/**
1903+ * ccs_put_condition - Drop reference on "struct ccs_condition".
1904+ *
1905+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
1906+ *
1907+ * Returns nothing.
1908+ */
1909+static inline void ccs_put_condition(struct ccs_condition *cond)
1910+{
1911+ if (cond)
1912+ atomic_dec(&cond->head.users);
1913+}
1914+
1915+/**
1916+ * ccs_put_group - Drop reference on "struct ccs_group".
1917+ *
1918+ * @group: Pointer to "struct ccs_group". Maybe NULL.
1919+ *
1920+ * Returns nothing.
1921+ */
1922+static inline void ccs_put_group(struct ccs_group *group)
1923+{
1924+ if (group)
1925+ atomic_dec(&group->head.users);
1926+}
1927+
1928+/**
1929+ * ccs_put_name - Drop reference on "struct ccs_name".
1930+ *
1931+ * @name: Pointer to "struct ccs_path_info". Maybe NULL.
1932+ *
1933+ * Returns nothing.
1934+ */
1935+static inline void ccs_put_name(const struct ccs_path_info *name)
1936+{
1937+ if (name)
1938+ atomic_dec(&container_of(name, struct ccs_name, entry)->
1939+ head.users);
1940+}
1941+
1942+/* For importing variables and functions. */
1943+extern struct ccsecurity_exports ccsecurity_exports;
1944+
1945+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
1946+
1947+/*
1948+ * Structure for holding "struct ccs_domain_info *" and "struct ccs_execve *"
1949+ * and "u32 ccs_flags" for each "struct task_struct".
1950+ *
1951+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
1952+ * are maintained outside that "struct task_struct". Therefore, ccs_security
1953+ * != task_struct . This keeps KABI for distributor's prebuilt kernels but
1954+ * entails slow access.
1955+ *
1956+ * Memory for this structure is allocated when current thread tries to access
1957+ * it. Therefore, if memory allocation failed, current thread will be killed by
1958+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
1959+ */
1960+struct ccs_security {
1961+ struct list_head list;
1962+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1963+ const struct task_struct *task;
1964+#else
1965+ struct pid *pid; /* Maybe NULL. */
1966+ const struct cred *cred; /* Maybe NULL. */
1967+#endif
1968+ struct ccs_domain_info *ccs_domain_info;
1969+ u32 ccs_flags;
1970+ struct ccs_execve *ee; /* Maybe NULL. */
1971+ struct rcu_head rcu;
1972+};
1973+
1974+void __init ccs_main_init(void);
1975+bool ccs_used_by_cred(const struct ccs_domain_info *domain);
1976+int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve **eep);
1977+void ccs_finish_execve(int retval, struct ccs_execve *ee);
1978+void ccs_load_policy(const char *filename);
1979+#ifndef CONFIG_AKARI_TRACE_EXECVE_COUNT
1980+#define ccs_audit_alloc_execve(ee) do { } while (0)
1981+#define ccs_audit_free_execve(ee, is_current) do { } while (0)
1982+#else
1983+void ccs_audit_alloc_execve(const struct ccs_execve * const ee);
1984+void ccs_audit_free_execve(const struct ccs_execve * const ee,
1985+ const bool is_current);
1986+#endif
1987+
1988+#define CCS_TASK_SECURITY_HASH_BITS 12
1989+#define CCS_MAX_TASK_SECURITY_HASH (1u << CCS_TASK_SECURITY_HASH_BITS)
1990+extern struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
1991+
1992+struct ccs_security *ccs_find_task_security(const struct task_struct *task);
1993+
1994+/**
1995+ * ccs_current_security - Get "struct ccs_security" for current thread.
1996+ *
1997+ * Returns pointer to "struct ccs_security" for current thread.
1998+ */
1999+static inline struct ccs_security *ccs_current_security(void)
2000+{
2001+ return ccs_find_task_security(current);
2002+}
2003+
2004+/**
2005+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
2006+ *
2007+ * @task: Pointer to "struct task_struct".
2008+ *
2009+ * Returns pointer to "struct ccs_security" for specified thread.
2010+ */
2011+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
2012+{
2013+ struct ccs_domain_info *domain;
2014+ rcu_read_lock();
2015+ domain = ccs_find_task_security(task)->ccs_domain_info;
2016+ rcu_read_unlock();
2017+ return domain;
2018+}
2019+
2020+/**
2021+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
2022+ *
2023+ * Returns pointer to "struct ccs_domain_info" for current thread.
2024+ */
2025+static inline struct ccs_domain_info *ccs_current_domain(void)
2026+{
2027+ return ccs_find_task_security(current)->ccs_domain_info;
2028+}
2029+
2030+/**
2031+ * ccs_task_flags - Get flags for specified thread.
2032+ *
2033+ * @task: Pointer to "struct task_struct".
2034+ *
2035+ * Returns flags for specified thread.
2036+ */
2037+static inline u32 ccs_task_flags(struct task_struct *task)
2038+{
2039+ u32 ccs_flags;
2040+ rcu_read_lock();
2041+ ccs_flags = ccs_find_task_security(task)->ccs_flags;
2042+ rcu_read_unlock();
2043+ return ccs_flags;
2044+}
2045+
2046+/**
2047+ * ccs_current_flags - Get flags for current thread.
2048+ *
2049+ * Returns flags for current thread.
2050+ */
2051+static inline u32 ccs_current_flags(void)
2052+{
2053+ return ccs_find_task_security(current)->ccs_flags;
2054+}
2055+
2056+#else
2057+
2058+/*
2059+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
2060+ * are maintained inside that "struct task_struct". Therefore, ccs_security ==
2061+ * task_struct . This allows fast access but breaks KABI checks for
2062+ * distributor's prebuilt kernels due to changes in "struct task_struct".
2063+ */
2064+#define ccs_security task_struct
2065+
2066+/**
2067+ * ccs_find_task_security - Find "struct ccs_security" for given task.
2068+ *
2069+ * @task: Pointer to "struct task_struct".
2070+ *
2071+ * Returns pointer to "struct ccs_security".
2072+ */
2073+static inline struct ccs_security *ccs_find_task_security(struct task_struct *
2074+ task)
2075+{
2076+ return task;
2077+}
2078+
2079+/**
2080+ * ccs_current_security - Get "struct ccs_security" for current thread.
2081+ *
2082+ * Returns pointer to "struct ccs_security" for current thread.
2083+ */
2084+static inline struct ccs_security *ccs_current_security(void)
2085+{
2086+ return ccs_find_task_security(current);
2087+}
2088+
2089+/**
2090+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
2091+ *
2092+ * @task: Pointer to "struct task_struct".
2093+ *
2094+ * Returns pointer to "struct ccs_security" for specified thread.
2095+ */
2096+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
2097+{
2098+ struct ccs_domain_info *domain = task->ccs_domain_info;
2099+ return domain ? domain : &ccs_kernel_domain;
2100+}
2101+
2102+/**
2103+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
2104+ *
2105+ * Returns pointer to "struct ccs_domain_info" for current thread.
2106+ *
2107+ * If current thread does not belong to a domain (which is true for initial
2108+ * init_task in order to hide ccs_kernel_domain from this module),
2109+ * current thread enters into ccs_kernel_domain.
2110+ */
2111+static inline struct ccs_domain_info *ccs_current_domain(void)
2112+{
2113+ struct task_struct *task = current;
2114+ if (!task->ccs_domain_info)
2115+ task->ccs_domain_info = &ccs_kernel_domain;
2116+ return task->ccs_domain_info;
2117+}
2118+
2119+/**
2120+ * ccs_task_flags - Get flags for specified thread.
2121+ *
2122+ * @task: Pointer to "struct task_struct".
2123+ *
2124+ * Returns flags for specified thread.
2125+ */
2126+static inline u32 ccs_task_flags(struct task_struct *task)
2127+{
2128+ return ccs_find_task_security(task)->ccs_flags;
2129+}
2130+
2131+/**
2132+ * ccs_current_flags - Get flags for current thread.
2133+ *
2134+ * Returns flags for current thread.
2135+ */
2136+static inline u32 ccs_current_flags(void)
2137+{
2138+ return ccs_find_task_security(current)->ccs_flags;
2139+}
2140+
2141+#endif
2142+
2143+/**
2144+ * ccs_current_namespace - Get "struct ccs_policy_namespace" for current thread.
2145+ *
2146+ * Returns pointer to "struct ccs_policy_namespace" for current thread.
2147+ */
2148+static inline struct ccs_policy_namespace *ccs_current_namespace(void)
2149+{
2150+ return ccs_current_domain()->ns;
2151+}
2152+
2153+#endif
--- tags/patches/1.0.29/permission.c (nonexistent)
+++ tags/patches/1.0.29/permission.c (revision 431)
@@ -0,0 +1,4969 @@
1+/*
2+ * security/ccsecurity/permission.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2012/05/05
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+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
296+ struct pt_regs *regs);
297+static int __ccs_symlink_permission(struct dentry *dentry,
298+ struct vfsmount *mnt, const char *from);
299+static int __ccs_truncate_permission(struct dentry *dentry,
300+ struct vfsmount *mnt);
301+static int __ccs_umount_permission(struct vfsmount *mnt, int flags);
302+static int __ccs_unlink_permission(struct dentry *dentry,
303+ struct vfsmount *mnt);
304+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
305+static int __ccs_uselib_permission(struct dentry *dentry,
306+ struct vfsmount *mnt);
307+#endif
308+static int ccs_execute_permission(struct ccs_request_info *r,
309+ const struct ccs_path_info *filename);
310+static int ccs_find_next_domain(struct ccs_execve *ee);
311+static int ccs_get_path(const char *pathname, struct path *path);
312+static int ccs_kern_path(const char *pathname, int flags, struct path *path);
313+static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
314+ struct vfsmount *mnt, const unsigned int mode,
315+ unsigned int dev);
316+static int ccs_mount_acl(struct ccs_request_info *r, const char *dev_name,
317+ struct path *dir, const char *type,
318+ unsigned long flags);
319+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
320+static int ccs_new_open_permission(struct file *filp);
321+#endif
322+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
323+static int ccs_old_chroot_permission(struct nameidata *nd);
324+static int ccs_old_mount_permission(const char *dev_name, struct nameidata *nd,
325+ const char *type, unsigned long flags,
326+ void *data_page);
327+static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
328+ struct nameidata *new_nd);
329+#endif
330+static int ccs_path2_perm(const u8 operation, struct dentry *dentry1,
331+ struct vfsmount *mnt1, struct dentry *dentry2,
332+ struct vfsmount *mnt2);
333+static int ccs_path_number_perm(const u8 type, struct dentry *dentry,
334+ struct vfsmount *vfsmnt, unsigned long number);
335+static int ccs_path_perm(const u8 operation, struct dentry *dentry,
336+ struct vfsmount *mnt, const char *target);
337+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) || !defined(CONFIG_SYSCTL_SYSCALL)
338+static
339+#endif
340+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
341+ const struct ccs_path_info *filename);
342+static int ccs_symlink_path(const char *pathname, struct ccs_path_info *name);
343+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
344+static void __ccs_clear_open_mode(void);
345+static void __ccs_save_open_mode(int mode);
346+#endif
347+static void ccs_add_slash(struct ccs_path_info *buf);
348+
349+#ifdef CONFIG_CCSECURITY_MISC
350+static bool ccs_check_env_acl(struct ccs_request_info *r,
351+ const struct ccs_acl_info *ptr);
352+static int ccs_env_perm(struct ccs_request_info *r, const char *env);
353+static int ccs_environ(struct ccs_execve *ee);
354+#endif
355+
356+#ifdef CONFIG_CCSECURITY_CAPABILITY
357+static bool __ccs_capable(const u8 operation);
358+static bool ccs_check_capability_acl(struct ccs_request_info *r,
359+ const struct ccs_acl_info *ptr);
360+static bool ccs_kernel_service(void);
361+static int __ccs_ptrace_permission(long request, long pid);
362+static int __ccs_socket_create_permission(int family, int type, int protocol);
363+#endif
364+
365+#ifdef CONFIG_CCSECURITY_NETWORK
366+static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
367+ const struct ccs_group *group);
368+static bool ccs_check_inet_acl(struct ccs_request_info *r,
369+ const struct ccs_acl_info *ptr);
370+static bool ccs_check_unix_acl(struct ccs_request_info *r,
371+ const struct ccs_acl_info *ptr);
372+static bool ccs_kernel_service(void);
373+static int __ccs_socket_bind_permission(struct socket *sock,
374+ struct sockaddr *addr, int addr_len);
375+static int __ccs_socket_connect_permission(struct socket *sock,
376+ struct sockaddr *addr,
377+ int addr_len);
378+static int __ccs_socket_listen_permission(struct socket *sock);
379+static int __ccs_socket_post_accept_permission(struct socket *sock,
380+ struct socket *newsock);
381+static int __ccs_socket_sendmsg_permission(struct socket *sock,
382+ struct msghdr *msg, int size);
383+static int ccs_check_inet_address(const struct sockaddr *addr,
384+ const unsigned int addr_len, const u16 port,
385+ struct ccs_addr_info *address);
386+static int ccs_check_unix_address(struct sockaddr *addr,
387+ const unsigned int addr_len,
388+ struct ccs_addr_info *address);
389+static int ccs_inet_entry(const struct ccs_addr_info *address);
390+static int ccs_unix_entry(const struct ccs_addr_info *address);
391+static u8 ccs_sock_family(struct sock *sk);
392+#endif
393+
394+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
395+static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
396+ struct sk_buff *skb,
397+ int flags);
398+#endif
399+
400+#ifdef CONFIG_CCSECURITY_IPC
401+static bool ccs_check_signal_acl(struct ccs_request_info *r,
402+ const struct ccs_acl_info *ptr);
403+static int ccs_signal_acl(const int pid, const int sig);
404+static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig);
405+static int ccs_signal_acl2(const int sig, const int pid);
406+#endif
407+
408+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
409+static int __ccs_getattr_permission(struct vfsmount *mnt,
410+ struct dentry *dentry);
411+#endif
412+
413+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
414+static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type);
415+static int ccs_try_alt_exec(struct ccs_execve *ee);
416+static void ccs_unescape(unsigned char *dest);
417+#endif
418+
419+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
420+static bool ccs_check_task_acl(struct ccs_request_info *r,
421+ const struct ccs_acl_info *ptr);
422+#endif
423+
424+/***** SECTION4: Standalone functions section *****/
425+
426+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
427+
428+/**
429+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
430+ *
431+ * @arg: String to copy.
432+ * @bprm: Pointer to "struct linux_binprm".
433+ *
434+ * Returns return value of copy_strings_kernel().
435+ */
436+static inline int ccs_copy_argv(const char *arg, struct linux_binprm *bprm)
437+{
438+ const int ret = copy_strings_kernel(1, &arg, bprm);
439+ if (ret >= 0)
440+ bprm->argc++;
441+ return ret;
442+}
443+
444+#else
445+
446+/**
447+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
448+ *
449+ * @arg: String to copy.
450+ * @bprm: Pointer to "struct linux_binprm".
451+ *
452+ * Returns return value of copy_strings_kernel().
453+ */
454+static inline int ccs_copy_argv(char *arg, struct linux_binprm *bprm)
455+{
456+ const int ret = copy_strings_kernel(1, &arg, bprm);
457+ if (ret >= 0)
458+ bprm->argc++;
459+ return ret;
460+}
461+
462+#endif
463+
464+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
465+
466+/**
467+ * get_fs_root - Get reference on root directory.
468+ *
469+ * @fs: Pointer to "struct fs_struct".
470+ * @root: Pointer to "struct path".
471+ *
472+ * Returns nothing.
473+ *
474+ * This is for compatibility with older kernels.
475+ */
476+static inline void get_fs_root(struct fs_struct *fs, struct path *root)
477+{
478+ read_lock(&fs->lock);
479+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
480+ *root = fs->root;
481+ path_get(root);
482+#else
483+ root->dentry = dget(fs->root);
484+ root->mnt = mntget(fs->rootmnt);
485+#endif
486+ read_unlock(&fs->lock);
487+}
488+
489+#endif
490+
491+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
492+
493+/**
494+ * module_put - Put a reference on module.
495+ *
496+ * @module: Pointer to "struct module". Maybe NULL.
497+ *
498+ * Returns nothing.
499+ *
500+ * This is for compatibility with older kernels.
501+ */
502+static inline void module_put(struct module *module)
503+{
504+ if (module)
505+ __MOD_DEC_USE_COUNT(module);
506+}
507+
508+#endif
509+
510+/**
511+ * ccs_put_filesystem - Wrapper for put_filesystem().
512+ *
513+ * @fstype: Pointer to "struct file_system_type".
514+ *
515+ * Returns nothing.
516+ *
517+ * Since put_filesystem() is not exported, I embed put_filesystem() here.
518+ */
519+static inline void ccs_put_filesystem(struct file_system_type *fstype)
520+{
521+ module_put(fstype->owner);
522+}
523+
524+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
525+
526+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
527+#if !defined(RHEL_MAJOR) || RHEL_MAJOR != 5
528+#if !defined(AX_MAJOR) || AX_MAJOR != 3
529+
530+/**
531+ * ip_hdr - Get "struct iphdr".
532+ *
533+ * @skb: Pointer to "struct sk_buff".
534+ *
535+ * Returns pointer to "struct iphdr".
536+ *
537+ * This is for compatibility with older kernels.
538+ */
539+static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
540+{
541+ return skb->nh.iph;
542+}
543+
544+/**
545+ * udp_hdr - Get "struct udphdr".
546+ *
547+ * @skb: Pointer to "struct sk_buff".
548+ *
549+ * Returns pointer to "struct udphdr".
550+ *
551+ * This is for compatibility with older kernels.
552+ */
553+static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
554+{
555+ return skb->h.uh;
556+}
557+
558+/**
559+ * ipv6_hdr - Get "struct ipv6hdr".
560+ *
561+ * @skb: Pointer to "struct sk_buff".
562+ *
563+ * Returns pointer to "struct ipv6hdr".
564+ *
565+ * This is for compatibility with older kernels.
566+ */
567+static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
568+{
569+ return skb->nh.ipv6h;
570+}
571+
572+#endif
573+#endif
574+#endif
575+
576+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
577+
578+/**
579+ * skb_kill_datagram - Kill a datagram forcibly.
580+ *
581+ * @sk: Pointer to "struct sock".
582+ * @skb: Pointer to "struct sk_buff".
583+ * @flags: Flags passed to skb_recv_datagram().
584+ *
585+ * Returns nothing.
586+ */
587+static inline void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
588+ int flags)
589+{
590+ /* Clear queue. */
591+ if (flags & MSG_PEEK) {
592+ int clear = 0;
593+ spin_lock_irq(&sk->receive_queue.lock);
594+ if (skb == skb_peek(&sk->receive_queue)) {
595+ __skb_unlink(skb, &sk->receive_queue);
596+ clear = 1;
597+ }
598+ spin_unlock_irq(&sk->receive_queue.lock);
599+ if (clear)
600+ kfree_skb(skb);
601+ }
602+ skb_free_datagram(sk, skb);
603+}
604+
605+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
606+
607+/**
608+ * skb_kill_datagram - Kill a datagram forcibly.
609+ *
610+ * @sk: Pointer to "struct sock".
611+ * @skb: Pointer to "struct sk_buff".
612+ * @flags: Flags passed to skb_recv_datagram().
613+ *
614+ * Returns nothing.
615+ */
616+static inline void skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
617+ int flags)
618+{
619+ /* Clear queue. */
620+ if (flags & MSG_PEEK) {
621+ int clear = 0;
622+ spin_lock_bh(&sk->sk_receive_queue.lock);
623+ if (skb == skb_peek(&sk->sk_receive_queue)) {
624+ __skb_unlink(skb, &sk->sk_receive_queue);
625+ clear = 1;
626+ }
627+ spin_unlock_bh(&sk->sk_receive_queue.lock);
628+ if (clear)
629+ kfree_skb(skb);
630+ }
631+ skb_free_datagram(sk, skb);
632+}
633+
634+#endif
635+
636+#endif
637+
638+/***** SECTION5: Variables definition section *****/
639+
640+/* The initial domain. */
641+struct ccs_domain_info ccs_kernel_domain;
642+
643+/* The list for "struct ccs_domain_info". */
644+LIST_HEAD(ccs_domain_list);
645+
646+/***** SECTION6: Dependent functions section *****/
647+
648+/**
649+ * ccs_path_matches_group - Check whether the given pathname matches members of the given pathname group.
650+ *
651+ * @pathname: The name of pathname.
652+ * @group: Pointer to "struct ccs_path_group".
653+ *
654+ * Returns matched member's pathname if @pathname matches pathnames in @group,
655+ * NULL otherwise.
656+ *
657+ * Caller holds ccs_read_lock().
658+ */
659+static const struct ccs_path_info *ccs_path_matches_group
660+(const struct ccs_path_info *pathname, const struct ccs_group *group)
661+{
662+ struct ccs_path_group *member;
663+ list_for_each_entry_srcu(member, &group->member_list, head.list,
664+ &ccs_ss) {
665+ if (member->head.is_deleted)
666+ continue;
667+ if (!ccs_path_matches_pattern(pathname, member->member_name))
668+ continue;
669+ return member->member_name;
670+ }
671+ return NULL;
672+}
673+
674+/**
675+ * ccs_number_matches_group - Check whether the given number matches members of the given number group.
676+ *
677+ * @min: Min number.
678+ * @max: Max number.
679+ * @group: Pointer to "struct ccs_number_group".
680+ *
681+ * Returns true if @min and @max partially overlaps @group, false otherwise.
682+ *
683+ * Caller holds ccs_read_lock().
684+ */
685+static bool ccs_number_matches_group(const unsigned long min,
686+ const unsigned long max,
687+ const struct ccs_group *group)
688+{
689+ struct ccs_number_group *member;
690+ bool matched = false;
691+ list_for_each_entry_srcu(member, &group->member_list, head.list,
692+ &ccs_ss) {
693+ if (member->head.is_deleted)
694+ continue;
695+ if (min > member->number.values[1] ||
696+ max < member->number.values[0])
697+ continue;
698+ matched = true;
699+ break;
700+ }
701+ return matched;
702+}
703+
704+/**
705+ * ccs_check_entry - Do permission check.
706+ *
707+ * @r: Pointer to "struct ccs_request_info".
708+ * @ptr: Pointer to "struct ccs_acl_info".
709+ *
710+ * Returns true on match, false otherwise.
711+ *
712+ * Caller holds ccs_read_lock().
713+ */
714+static bool ccs_check_entry(struct ccs_request_info *r,
715+ struct ccs_acl_info *ptr)
716+{
717+ if (ptr->is_deleted || ptr->type != r->param_type)
718+ return false;
719+ switch (r->param_type) {
720+ case CCS_TYPE_PATH_ACL:
721+ return ccs_check_path_acl(r, ptr);
722+ case CCS_TYPE_PATH2_ACL:
723+ return ccs_check_path2_acl(r, ptr);
724+ case CCS_TYPE_PATH_NUMBER_ACL:
725+ return ccs_check_path_number_acl(r, ptr);
726+ case CCS_TYPE_MKDEV_ACL:
727+ return ccs_check_mkdev_acl(r, ptr);
728+ case CCS_TYPE_MOUNT_ACL:
729+ return ccs_check_mount_acl(r, ptr);
730+#ifdef CONFIG_CCSECURITY_MISC
731+ case CCS_TYPE_ENV_ACL:
732+ return ccs_check_env_acl(r, ptr);
733+#endif
734+#ifdef CONFIG_CCSECURITY_CAPABILITY
735+ case CCS_TYPE_CAPABILITY_ACL:
736+ return ccs_check_capability_acl(r, ptr);
737+#endif
738+#ifdef CONFIG_CCSECURITY_NETWORK
739+ case CCS_TYPE_INET_ACL:
740+ return ccs_check_inet_acl(r, ptr);
741+ case CCS_TYPE_UNIX_ACL:
742+ return ccs_check_unix_acl(r, ptr);
743+#endif
744+#ifdef CONFIG_CCSECURITY_IPC
745+ case CCS_TYPE_SIGNAL_ACL:
746+ return ccs_check_signal_acl(r, ptr);
747+#endif
748+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
749+ case CCS_TYPE_MANUAL_TASK_ACL:
750+ return ccs_check_task_acl(r, ptr);
751+#endif
752+ }
753+ return true;
754+}
755+
756+/**
757+ * ccs_check_acl - Do permission check.
758+ *
759+ * @r: Pointer to "struct ccs_request_info".
760+ *
761+ * Returns 0 on success, negative value otherwise.
762+ *
763+ * Caller holds ccs_read_lock().
764+ */
765+int ccs_check_acl(struct ccs_request_info *r)
766+{
767+ const struct ccs_domain_info *domain = ccs_current_domain();
768+ int error;
769+ bool retried = false;
770+ do {
771+ struct ccs_acl_info *ptr;
772+ const struct list_head *list = &domain->acl_info_list;
773+retry:
774+ list_for_each_entry_srcu(ptr, list, list, &ccs_ss) {
775+ if (!ccs_check_entry(r, ptr))
776+ continue;
777+ if (!ccs_condition(r, ptr->cond))
778+ continue;
779+ r->matched_acl = ptr;
780+ r->granted = true;
781+ ccs_audit_log(r);
782+ return 0;
783+ }
784+ if (!retried) {
785+ retried = true;
786+ list = &domain->ns->acl_group[domain->group];
787+ goto retry;
788+ }
789+ r->granted = false;
790+ if (r->mode != CCS_CONFIG_DISABLED ||
791+ r->type != CCS_MAC_FILE_EXECUTE)
792+ error = ccs_audit_log(r);
793+ else
794+ error = 0;
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.validate_done = false;
1192+ allow_write_access(bprm->file);
1193+ fput(bprm->file);
1194+ bprm->file = NULL;
1195+
1196+ /* Invalidate page dump cache. */
1197+ ee->dump.page = NULL;
1198+
1199+ /* Move envp[] to argv[] */
1200+ bprm->argc += bprm->envc;
1201+ bprm->envc = 0;
1202+
1203+ /* Set argv[6] */
1204+ {
1205+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1206+ retval = ccs_copy_argv(ee->tmp, bprm);
1207+ if (retval < 0)
1208+ goto out;
1209+ }
1210+
1211+ /* Set argv[5] */
1212+ {
1213+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1214+ retval = ccs_copy_argv(ee->tmp, bprm);
1215+ if (retval < 0)
1216+ goto out;
1217+ }
1218+
1219+ /* Set argv[4] */
1220+ {
1221+ retval = ccs_copy_argv(bprm->filename, bprm);
1222+ if (retval < 0)
1223+ goto out;
1224+ }
1225+
1226+ /* Set argv[3] */
1227+ {
1228+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
1229+ /*
1230+ * Pass uid/gid seen from current user namespace, for these
1231+ * values are used by programs in current user namespace in
1232+ * order to decide whether to execve() or not (rather than by
1233+ * auditing daemon in init's user namespace).
1234+ */
1235+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1236+ "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1237+ "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
1238+ __kuid_val(current_uid()), __kgid_val(current_gid()),
1239+ __kuid_val(current_euid()),
1240+ __kgid_val(current_egid()),
1241+ __kuid_val(current_suid()),
1242+ __kgid_val(current_sgid()),
1243+ __kuid_val(current_fsuid()),
1244+ __kgid_val(current_fsgid()));
1245+#else
1246+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1247+ "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1248+ "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
1249+ current_uid(), current_gid(), current_euid(),
1250+ current_egid(), current_suid(), current_sgid(),
1251+ current_fsuid(), current_fsgid());
1252+#endif
1253+ retval = ccs_copy_argv(ee->tmp, bprm);
1254+ if (retval < 0)
1255+ goto out;
1256+ }
1257+
1258+ /* Set argv[2] */
1259+ {
1260+ char *exe = (char *) ccs_get_exe();
1261+ if (exe) {
1262+ retval = ccs_copy_argv(exe, bprm);
1263+ kfree(exe);
1264+ } else {
1265+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
1266+ retval = ccs_copy_argv("<unknown>", bprm);
1267+#else
1268+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
1269+ retval = ccs_copy_argv(ee->tmp, bprm);
1270+#endif
1271+ }
1272+ if (retval < 0)
1273+ goto out;
1274+ }
1275+
1276+ /* Set argv[1] */
1277+ {
1278+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
1279+ retval = ccs_copy_argv(ccs_current_domain()->domainname->name,
1280+ bprm);
1281+#else
1282+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1283+ ccs_current_domain()->domainname->name);
1284+ retval = ccs_copy_argv(ee->tmp, bprm);
1285+#endif
1286+ if (retval < 0)
1287+ goto out;
1288+ }
1289+
1290+ /* Set argv[0] */
1291+ {
1292+ struct path root;
1293+ char *cp;
1294+ int root_len;
1295+ int handler_len;
1296+ get_fs_root(current->fs, &root);
1297+ cp = ccs_realpath(&root);
1298+ path_put(&root);
1299+ if (!cp) {
1300+ retval = -ENOMEM;
1301+ goto out;
1302+ }
1303+ root_len = strlen(cp);
1304+ retval = strncmp(ee->handler->name, cp, root_len);
1305+ root_len--;
1306+ kfree(cp);
1307+ if (retval) {
1308+ retval = -ENOENT;
1309+ goto out;
1310+ }
1311+ handler_len = ee->handler->total_len + 1;
1312+ cp = kmalloc(handler_len, CCS_GFP_FLAGS);
1313+ if (!cp) {
1314+ retval = -ENOMEM;
1315+ goto out;
1316+ }
1317+ /* ee->handler_path is released by ccs_finish_execve(). */
1318+ ee->handler_path = cp;
1319+ /* Adjust root directory for open_exec(). */
1320+ memmove(cp, ee->handler->name + root_len,
1321+ handler_len - root_len);
1322+ ccs_unescape(cp);
1323+ retval = -ENOENT;
1324+ if (*cp != '/')
1325+ goto out;
1326+ retval = ccs_copy_argv(cp, bprm);
1327+ if (retval < 0)
1328+ goto out;
1329+ }
1330+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1331+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1332+ bprm->argv_len = bprm->exec - bprm->p;
1333+#endif
1334+#endif
1335+
1336+ /*
1337+ * OK, now restart the process with execute handler program's dentry.
1338+ */
1339+ filp = open_exec(ee->handler_path);
1340+ if (IS_ERR(filp)) {
1341+ retval = PTR_ERR(filp);
1342+ goto out;
1343+ }
1344+ ee->obj.path1.dentry = filp->f_dentry;
1345+ ee->obj.path1.mnt = filp->f_vfsmnt;
1346+ bprm->file = filp;
1347+ bprm->filename = ee->handler_path;
1348+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1349+ bprm->interp = bprm->filename;
1350+#endif
1351+ retval = prepare_binprm(bprm);
1352+ if (retval < 0)
1353+ goto out;
1354+ ee->r.dont_sleep_on_enforce_error = true;
1355+ retval = ccs_find_next_domain(ee);
1356+ ee->r.dont_sleep_on_enforce_error = false;
1357+out:
1358+ return retval;
1359+}
1360+
1361+/**
1362+ * ccs_find_execute_handler - Find an execute handler.
1363+ *
1364+ * @ee: Pointer to "struct ccs_execve".
1365+ * @type: Type of execute handler.
1366+ *
1367+ * Returns true if found, false otherwise.
1368+ *
1369+ * Caller holds ccs_read_lock().
1370+ */
1371+static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type)
1372+{
1373+ struct ccs_request_info *r = &ee->r;
1374+ /*
1375+ * To avoid infinite execute handler loop, don't use execute handler
1376+ * if the current process is marked as execute handler.
1377+ */
1378+ if (ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)
1379+ return false;
1380+ r->param_type = type;
1381+ ccs_check_acl(r);
1382+ if (!r->granted)
1383+ return false;
1384+ ee->handler = container_of(r->matched_acl, struct ccs_handler_acl,
1385+ head)->handler;
1386+ ee->transition = r->matched_acl && r->matched_acl->cond &&
1387+ r->matched_acl->cond->exec_transit ?
1388+ r->matched_acl->cond->transit : NULL;
1389+ return true;
1390+}
1391+
1392+#endif
1393+
1394+#ifdef CONFIG_MMU
1395+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1396+#define CCS_BPRM_MMU
1397+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3
1398+#define CCS_BPRM_MMU
1399+#elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2
1400+#define CCS_BPRM_MMU
1401+#endif
1402+#endif
1403+
1404+/**
1405+ * ccs_dump_page - Dump a page to buffer.
1406+ *
1407+ * @bprm: Pointer to "struct linux_binprm".
1408+ * @pos: Location to dump.
1409+ * @dump: Poiner to "struct ccs_page_dump".
1410+ *
1411+ * Returns true on success, false otherwise.
1412+ */
1413+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1414+ struct ccs_page_dump *dump)
1415+{
1416+ struct page *page;
1417+ /* dump->data is released by ccs_start_execve(). */
1418+ if (!dump->data) {
1419+ dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1420+ if (!dump->data)
1421+ return false;
1422+ }
1423+ /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1424+#ifdef CCS_BPRM_MMU
1425+ if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1426+ return false;
1427+#else
1428+ page = bprm->page[pos / PAGE_SIZE];
1429+#endif
1430+ if (page != dump->page) {
1431+ const unsigned int offset = pos % PAGE_SIZE;
1432+ /*
1433+ * Maybe kmap()/kunmap() should be used here.
1434+ * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1435+ * So do I.
1436+ */
1437+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
1438+ char *kaddr = kmap_atomic(page);
1439+#else
1440+ char *kaddr = kmap_atomic(page, KM_USER0);
1441+#endif
1442+ dump->page = page;
1443+ memcpy(dump->data + offset, kaddr + offset,
1444+ PAGE_SIZE - offset);
1445+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
1446+ kunmap_atomic(kaddr);
1447+#else
1448+ kunmap_atomic(kaddr, KM_USER0);
1449+#endif
1450+ }
1451+ /* Same with put_arg_page(page) in fs/exec.c */
1452+#ifdef CCS_BPRM_MMU
1453+ put_page(page);
1454+#endif
1455+ return true;
1456+}
1457+
1458+/**
1459+ * ccs_start_execve - Prepare for execve() operation.
1460+ *
1461+ * @bprm: Pointer to "struct linux_binprm".
1462+ * @eep: Pointer to "struct ccs_execve *".
1463+ *
1464+ * Returns 0 on success, negative value otherwise.
1465+ */
1466+int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve **eep)
1467+{
1468+ int retval;
1469+ struct ccs_security *task = ccs_current_security();
1470+ struct ccs_execve *ee;
1471+ int idx;
1472+ *eep = NULL;
1473+ ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1474+ if (!ee)
1475+ return -ENOMEM;
1476+ ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1477+ if (!ee->tmp) {
1478+ kfree(ee);
1479+ return -ENOMEM;
1480+ }
1481+ ccs_audit_alloc_execve(ee);
1482+ idx = ccs_read_lock();
1483+ /* ee->dump->data is allocated by ccs_dump_page(). */
1484+ ee->previous_domain = task->ccs_domain_info;
1485+ /* Clear manager flag. */
1486+ task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1487+ *eep = ee;
1488+ ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1489+ ee->r.ee = ee;
1490+ ee->bprm = bprm;
1491+ ee->r.obj = &ee->obj;
1492+ ee->obj.path1.dentry = bprm->file->f_dentry;
1493+ ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1494+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1495+ /*
1496+ * No need to call ccs_environ() for execute handler because envp[] is
1497+ * moved to argv[].
1498+ */
1499+ if (ccs_find_execute_handler(ee, CCS_TYPE_AUTO_EXECUTE_HANDLER)) {
1500+ retval = ccs_try_alt_exec(ee);
1501+ goto done;
1502+ }
1503+#endif
1504+ retval = ccs_find_next_domain(ee);
1505+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1506+ if (retval == -EPERM &&
1507+ ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1508+ retval = ccs_try_alt_exec(ee);
1509+ goto done;
1510+ }
1511+#endif
1512+#ifdef CONFIG_CCSECURITY_MISC
1513+ if (!retval)
1514+ retval = ccs_environ(ee);
1515+#endif
1516+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
1517+done:
1518+#endif
1519+ ccs_read_unlock(idx);
1520+ kfree(ee->tmp);
1521+ ee->tmp = NULL;
1522+ kfree(ee->dump.data);
1523+ ee->dump.data = NULL;
1524+ return retval;
1525+}
1526+
1527+/**
1528+ * ccs_finish_execve - Clean up execve() operation.
1529+ *
1530+ * @retval: Return code of an execve() operation.
1531+ * @ee: Pointer to "struct ccs_execve".
1532+ *
1533+ * Returns nothing.
1534+ */
1535+void ccs_finish_execve(int retval, struct ccs_execve *ee)
1536+{
1537+ struct ccs_security *task = ccs_current_security();
1538+ if (!ee)
1539+ return;
1540+ if (retval < 0) {
1541+ task->ccs_domain_info = ee->previous_domain;
1542+ /*
1543+ * Make task->ccs_domain_info visible to GC before changing
1544+ * task->ccs_flags.
1545+ */
1546+ smp_wmb();
1547+ } else {
1548+ /* Mark the current process as execute handler. */
1549+ if (ee->handler)
1550+ task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1551+ /* Mark the current process as normal process. */
1552+ else
1553+ task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1554+ }
1555+ /* Tell GC that I finished execve(). */
1556+ task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1557+ ccs_audit_free_execve(ee, true);
1558+ kfree(ee->handler_path);
1559+ kfree(ee);
1560+}
1561+
1562+/**
1563+ * __ccs_search_binary_handler - Main routine for do_execve().
1564+ *
1565+ * @bprm: Pointer to "struct linux_binprm".
1566+ * @regs: Pointer to "struct pt_regs".
1567+ *
1568+ * Returns 0 on success, negative value otherwise.
1569+ *
1570+ * Performs permission checks for do_execve() and domain transition.
1571+ * Domain transition by "struct ccs_domain_transition_control" and
1572+ * "auto_domain_transition=" parameter of "struct ccs_condition" are reverted
1573+ * if do_execve() failed.
1574+ * Garbage collector does not remove "struct ccs_domain_info" from
1575+ * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
1576+ * marked as CCS_TASK_IS_IN_EXECVE.
1577+ */
1578+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1579+ struct pt_regs *regs)
1580+{
1581+ struct ccs_execve *ee;
1582+ int retval;
1583+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1584+ if (!ccs_policy_loaded)
1585+ ccsecurity_exports.load_policy(bprm->filename);
1586+#endif
1587+ retval = ccs_start_execve(bprm, &ee);
1588+ if (!retval)
1589+ retval = search_binary_handler(bprm, regs);
1590+ ccs_finish_execve(retval, ee);
1591+ return retval;
1592+}
1593+
1594+/**
1595+ * ccs_permission_init - Register permission check hooks.
1596+ *
1597+ * Returns nothing.
1598+ */
1599+void __init ccs_permission_init(void)
1600+{
1601+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1602+ ccsecurity_ops.save_open_mode = __ccs_save_open_mode;
1603+ ccsecurity_ops.clear_open_mode = __ccs_clear_open_mode;
1604+ ccsecurity_ops.open_permission = __ccs_open_permission;
1605+#else
1606+ ccsecurity_ops.open_permission = ccs_new_open_permission;
1607+#endif
1608+ ccsecurity_ops.fcntl_permission = __ccs_fcntl_permission;
1609+ ccsecurity_ops.ioctl_permission = __ccs_ioctl_permission;
1610+ ccsecurity_ops.chmod_permission = __ccs_chmod_permission;
1611+ ccsecurity_ops.chown_permission = __ccs_chown_permission;
1612+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
1613+ ccsecurity_ops.getattr_permission = __ccs_getattr_permission;
1614+#endif
1615+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1616+ ccsecurity_ops.pivot_root_permission = __ccs_pivot_root_permission;
1617+ ccsecurity_ops.chroot_permission = __ccs_chroot_permission;
1618+#else
1619+ ccsecurity_ops.pivot_root_permission = ccs_old_pivot_root_permission;
1620+ ccsecurity_ops.chroot_permission = ccs_old_chroot_permission;
1621+#endif
1622+ ccsecurity_ops.umount_permission = __ccs_umount_permission;
1623+ ccsecurity_ops.mknod_permission = __ccs_mknod_permission;
1624+ ccsecurity_ops.mkdir_permission = __ccs_mkdir_permission;
1625+ ccsecurity_ops.rmdir_permission = __ccs_rmdir_permission;
1626+ ccsecurity_ops.unlink_permission = __ccs_unlink_permission;
1627+ ccsecurity_ops.symlink_permission = __ccs_symlink_permission;
1628+ ccsecurity_ops.truncate_permission = __ccs_truncate_permission;
1629+ ccsecurity_ops.rename_permission = __ccs_rename_permission;
1630+ ccsecurity_ops.link_permission = __ccs_link_permission;
1631+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1632+ ccsecurity_ops.open_exec_permission = __ccs_open_exec_permission;
1633+ ccsecurity_ops.uselib_permission = __ccs_uselib_permission;
1634+#endif
1635+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
1636+ ccsecurity_ops.parse_table = __ccs_parse_table;
1637+#endif
1638+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1639+ ccsecurity_ops.mount_permission = __ccs_mount_permission;
1640+#else
1641+ ccsecurity_ops.mount_permission = ccs_old_mount_permission;
1642+#endif
1643+#ifdef CONFIG_CCSECURITY_CAPABILITY
1644+ ccsecurity_ops.socket_create_permission =
1645+ __ccs_socket_create_permission;
1646+#endif
1647+#ifdef CONFIG_CCSECURITY_NETWORK
1648+ ccsecurity_ops.socket_listen_permission =
1649+ __ccs_socket_listen_permission;
1650+ ccsecurity_ops.socket_connect_permission =
1651+ __ccs_socket_connect_permission;
1652+ ccsecurity_ops.socket_bind_permission = __ccs_socket_bind_permission;
1653+ ccsecurity_ops.socket_post_accept_permission =
1654+ __ccs_socket_post_accept_permission;
1655+ ccsecurity_ops.socket_sendmsg_permission =
1656+ __ccs_socket_sendmsg_permission;
1657+#endif
1658+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
1659+ ccsecurity_ops.socket_post_recvmsg_permission =
1660+ __ccs_socket_post_recvmsg_permission;
1661+#endif
1662+#ifdef CONFIG_CCSECURITY_IPC
1663+ ccsecurity_ops.kill_permission = ccs_signal_acl;
1664+ ccsecurity_ops.tgkill_permission = ccs_signal_acl0;
1665+ ccsecurity_ops.tkill_permission = ccs_signal_acl;
1666+ ccsecurity_ops.sigqueue_permission = ccs_signal_acl;
1667+ ccsecurity_ops.tgsigqueue_permission = ccs_signal_acl0;
1668+#endif
1669+#ifdef CONFIG_CCSECURITY_CAPABILITY
1670+ ccsecurity_ops.capable = __ccs_capable;
1671+ ccsecurity_ops.ptrace_permission = __ccs_ptrace_permission;
1672+#endif
1673+ ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1674+}
1675+
1676+/**
1677+ * ccs_kern_path - Wrapper for kern_path().
1678+ *
1679+ * @pathname: Pathname to resolve. Maybe NULL.
1680+ * @flags: Lookup flags.
1681+ * @path: Pointer to "struct path".
1682+ *
1683+ * Returns 0 on success, negative value otherwise.
1684+ */
1685+static int ccs_kern_path(const char *pathname, int flags, struct path *path)
1686+{
1687+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
1688+ if (!pathname || kern_path(pathname, flags, path))
1689+ return -ENOENT;
1690+#else
1691+ struct nameidata nd;
1692+ if (!pathname || path_lookup(pathname, flags, &nd))
1693+ return -ENOENT;
1694+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1695+ *path = nd.path;
1696+#else
1697+ path->dentry = nd.dentry;
1698+ path->mnt = nd.mnt;
1699+#endif
1700+#endif
1701+ return 0;
1702+}
1703+
1704+/**
1705+ * ccs_get_path - Get dentry/vfsmmount of a pathname.
1706+ *
1707+ * @pathname: The pathname to solve. Maybe NULL.
1708+ * @path: Pointer to "struct path".
1709+ *
1710+ * Returns 0 on success, negative value otherwise.
1711+ */
1712+static int ccs_get_path(const char *pathname, struct path *path)
1713+{
1714+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1715+ return ccs_kern_path(pathname, LOOKUP_FOLLOW, path);
1716+#else
1717+ return ccs_kern_path(pathname, LOOKUP_FOLLOW | LOOKUP_POSITIVE, path);
1718+#endif
1719+}
1720+
1721+/**
1722+ * ccs_symlink_path - Get symlink's pathname.
1723+ *
1724+ * @pathname: The pathname to solve. Maybe NULL.
1725+ * @name: Pointer to "struct ccs_path_info".
1726+ *
1727+ * Returns 0 on success, negative value otherwise.
1728+ *
1729+ * This function uses kzalloc(), so caller must kfree() if this function
1730+ * didn't return NULL.
1731+ */
1732+static int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
1733+{
1734+ char *buf;
1735+ struct path path;
1736+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1737+ if (ccs_kern_path(pathname, 0, &path))
1738+ return -ENOENT;
1739+#else
1740+ if (ccs_kern_path(pathname, LOOKUP_POSITIVE, &path))
1741+ return -ENOENT;
1742+#endif
1743+ buf = ccs_realpath(&path);
1744+ path_put(&path);
1745+ if (buf) {
1746+ name->name = buf;
1747+ ccs_fill_path_info(name);
1748+ return 0;
1749+ }
1750+ return -ENOMEM;
1751+}
1752+
1753+/**
1754+ * ccs_check_mount_acl - Check permission for path path path number operation.
1755+ *
1756+ * @r: Pointer to "struct ccs_request_info".
1757+ * @ptr: Pointer to "struct ccs_acl_info".
1758+ *
1759+ * Returns true if granted, false otherwise.
1760+ */
1761+static bool ccs_check_mount_acl(struct ccs_request_info *r,
1762+ const struct ccs_acl_info *ptr)
1763+{
1764+ const struct ccs_mount_acl *acl =
1765+ container_of(ptr, typeof(*acl), head);
1766+ return ccs_compare_number_union(r->param.mount.flags, &acl->flags) &&
1767+ ccs_compare_name_union(r->param.mount.type, &acl->fs_type) &&
1768+ ccs_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
1769+ (!r->param.mount.need_dev ||
1770+ ccs_compare_name_union(r->param.mount.dev, &acl->dev_name));
1771+}
1772+
1773+/**
1774+ * ccs_mount_acl - Check permission for mount() operation.
1775+ *
1776+ * @r: Pointer to "struct ccs_request_info".
1777+ * @dev_name: Name of device file. Maybe NULL.
1778+ * @dir: Pointer to "struct path".
1779+ * @type: Name of filesystem type.
1780+ * @flags: Mount options.
1781+ *
1782+ * Returns 0 on success, negative value otherwise.
1783+ *
1784+ * Caller holds ccs_read_lock().
1785+ */
1786+static int ccs_mount_acl(struct ccs_request_info *r, const char *dev_name,
1787+ struct path *dir, const char *type,
1788+ unsigned long flags)
1789+{
1790+ struct ccs_obj_info obj = { };
1791+ struct file_system_type *fstype = NULL;
1792+ const char *requested_type = NULL;
1793+ const char *requested_dir_name = NULL;
1794+ const char *requested_dev_name = NULL;
1795+ struct ccs_path_info rtype;
1796+ struct ccs_path_info rdev;
1797+ struct ccs_path_info rdir;
1798+ int need_dev = 0;
1799+ int error = -ENOMEM;
1800+ r->obj = &obj;
1801+
1802+ /* Get fstype. */
1803+ requested_type = ccs_encode(type);
1804+ if (!requested_type)
1805+ goto out;
1806+ rtype.name = requested_type;
1807+ ccs_fill_path_info(&rtype);
1808+
1809+ /* Get mount point. */
1810+ obj.path2 = *dir;
1811+ requested_dir_name = ccs_realpath(dir);
1812+ if (!requested_dir_name) {
1813+ error = -ENOMEM;
1814+ goto out;
1815+ }
1816+ rdir.name = requested_dir_name;
1817+ ccs_fill_path_info(&rdir);
1818+
1819+ /* Compare fs name. */
1820+ if (type == ccs_mounts[CCS_MOUNT_REMOUNT]) {
1821+ /* dev_name is ignored. */
1822+ } else if (type == ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE] ||
1823+ type == ccs_mounts[CCS_MOUNT_MAKE_PRIVATE] ||
1824+ type == ccs_mounts[CCS_MOUNT_MAKE_SLAVE] ||
1825+ type == ccs_mounts[CCS_MOUNT_MAKE_SHARED]) {
1826+ /* dev_name is ignored. */
1827+ } else if (type == ccs_mounts[CCS_MOUNT_BIND] ||
1828+ type == ccs_mounts[CCS_MOUNT_MOVE]) {
1829+ need_dev = -1; /* dev_name is a directory */
1830+ } else {
1831+ fstype = get_fs_type(type);
1832+ if (!fstype) {
1833+ error = -ENODEV;
1834+ goto out;
1835+ }
1836+ if (fstype->fs_flags & FS_REQUIRES_DEV)
1837+ /* dev_name is a block device file. */
1838+ need_dev = 1;
1839+ }
1840+ if (need_dev) {
1841+ /* Get mount point or device file. */
1842+ if (ccs_get_path(dev_name, &obj.path1)) {
1843+ error = -ENOENT;
1844+ goto out;
1845+ }
1846+ requested_dev_name = ccs_realpath(&obj.path1);
1847+ if (!requested_dev_name) {
1848+ error = -ENOENT;
1849+ goto out;
1850+ }
1851+ } else {
1852+ /* Map dev_name to "<NULL>" if no dev_name given. */
1853+ if (!dev_name)
1854+ dev_name = "<NULL>";
1855+ requested_dev_name = ccs_encode(dev_name);
1856+ if (!requested_dev_name) {
1857+ error = -ENOMEM;
1858+ goto out;
1859+ }
1860+ }
1861+ rdev.name = requested_dev_name;
1862+ ccs_fill_path_info(&rdev);
1863+ r->param_type = CCS_TYPE_MOUNT_ACL;
1864+ r->param.mount.need_dev = need_dev;
1865+ r->param.mount.dev = &rdev;
1866+ r->param.mount.dir = &rdir;
1867+ r->param.mount.type = &rtype;
1868+ r->param.mount.flags = flags;
1869+ error = ccs_check_acl(r);
1870+out:
1871+ kfree(requested_dev_name);
1872+ kfree(requested_dir_name);
1873+ if (fstype)
1874+ ccs_put_filesystem(fstype);
1875+ kfree(requested_type);
1876+ /* Drop refcount obtained by ccs_get_path(). */
1877+ if (obj.path1.dentry)
1878+ path_put(&obj.path1);
1879+ return error;
1880+}
1881+
1882+/**
1883+ * __ccs_mount_permission - Check permission for mount() operation.
1884+ *
1885+ * @dev_name: Name of device file. Maybe NULL.
1886+ * @path: Pointer to "struct path".
1887+ * @type: Name of filesystem type. Maybe NULL.
1888+ * @flags: Mount options.
1889+ * @data_page: Optional data. Maybe NULL.
1890+ *
1891+ * Returns 0 on success, negative value otherwise.
1892+ */
1893+static int __ccs_mount_permission(const char *dev_name, struct path *path,
1894+ const char *type, unsigned long flags,
1895+ void *data_page)
1896+{
1897+ struct ccs_request_info r;
1898+ int error = 0;
1899+ int idx;
1900+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
1901+ flags &= ~MS_MGC_MSK;
1902+ if (flags & MS_REMOUNT) {
1903+ type = ccs_mounts[CCS_MOUNT_REMOUNT];
1904+ flags &= ~MS_REMOUNT;
1905+ } else if (flags & MS_BIND) {
1906+ type = ccs_mounts[CCS_MOUNT_BIND];
1907+ flags &= ~MS_BIND;
1908+ } else if (flags & MS_SHARED) {
1909+ if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1910+ return -EINVAL;
1911+ type = ccs_mounts[CCS_MOUNT_MAKE_SHARED];
1912+ flags &= ~MS_SHARED;
1913+ } else if (flags & MS_PRIVATE) {
1914+ if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
1915+ return -EINVAL;
1916+ type = ccs_mounts[CCS_MOUNT_MAKE_PRIVATE];
1917+ flags &= ~MS_PRIVATE;
1918+ } else if (flags & MS_SLAVE) {
1919+ if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
1920+ return -EINVAL;
1921+ type = ccs_mounts[CCS_MOUNT_MAKE_SLAVE];
1922+ flags &= ~MS_SLAVE;
1923+ } else if (flags & MS_UNBINDABLE) {
1924+ if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
1925+ return -EINVAL;
1926+ type = ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE];
1927+ flags &= ~MS_UNBINDABLE;
1928+ } else if (flags & MS_MOVE) {
1929+ type = ccs_mounts[CCS_MOUNT_MOVE];
1930+ flags &= ~MS_MOVE;
1931+ }
1932+ if (!type)
1933+ type = "<NULL>";
1934+ idx = ccs_read_lock();
1935+ if (ccs_init_request_info(&r, CCS_MAC_FILE_MOUNT)
1936+ != CCS_CONFIG_DISABLED)
1937+ error = ccs_mount_acl(&r, dev_name, path, type, flags);
1938+ ccs_read_unlock(idx);
1939+ return error;
1940+}
1941+
1942+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1943+
1944+/**
1945+ * ccs_old_mount_permission - Check permission for mount() operation.
1946+ *
1947+ * @dev_name: Name of device file.
1948+ * @nd: Pointer to "struct nameidata".
1949+ * @type: Name of filesystem type. Maybe NULL.
1950+ * @flags: Mount options.
1951+ * @data_page: Optional data. Maybe NULL.
1952+ *
1953+ * Returns 0 on success, negative value otherwise.
1954+ */
1955+static int ccs_old_mount_permission(const char *dev_name, struct nameidata *nd,
1956+ const char *type, unsigned long flags,
1957+ void *data_page)
1958+{
1959+ struct path path = { nd->mnt, nd->dentry };
1960+ return __ccs_mount_permission(dev_name, &path, type, flags, data_page);
1961+}
1962+
1963+#endif
1964+
1965+/**
1966+ * ccs_compare_number_union - Check whether a value matches "struct ccs_number_union" or not.
1967+ *
1968+ * @value: Number to check.
1969+ * @ptr: Pointer to "struct ccs_number_union".
1970+ *
1971+ * Returns true if @value matches @ptr, false otherwise.
1972+ */
1973+static bool ccs_compare_number_union(const unsigned long value,
1974+ const struct ccs_number_union *ptr)
1975+{
1976+ if (ptr->group)
1977+ return ccs_number_matches_group(value, value, ptr->group);
1978+ return value >= ptr->values[0] && value <= ptr->values[1];
1979+}
1980+
1981+/**
1982+ * ccs_compare_name_union - Check whether a name matches "struct ccs_name_union" or not.
1983+ *
1984+ * @name: Pointer to "struct ccs_path_info".
1985+ * @ptr: Pointer to "struct ccs_name_union".
1986+ *
1987+ * Returns "struct ccs_path_info" if @name matches @ptr, NULL otherwise.
1988+ */
1989+static const struct ccs_path_info *ccs_compare_name_union
1990+(const struct ccs_path_info *name, const struct ccs_name_union *ptr)
1991+{
1992+ if (ptr->group)
1993+ return ccs_path_matches_group(name, ptr->group);
1994+ if (ccs_path_matches_pattern(name, ptr->filename))
1995+ return ptr->filename;
1996+ return NULL;
1997+}
1998+
1999+/**
2000+ * ccs_add_slash - Add trailing '/' if needed.
2001+ *
2002+ * @buf: Pointer to "struct ccs_path_info".
2003+ *
2004+ * Returns nothing.
2005+ *
2006+ * @buf must be generated by ccs_encode() because this function does not
2007+ * allocate memory for adding '/'.
2008+ */
2009+static void ccs_add_slash(struct ccs_path_info *buf)
2010+{
2011+ if (buf->is_dir)
2012+ return;
2013+ /* This is OK because ccs_encode() reserves space for appending "/". */
2014+ strcat((char *) buf->name, "/");
2015+ ccs_fill_path_info(buf);
2016+}
2017+
2018+/**
2019+ * ccs_get_realpath - Get realpath.
2020+ *
2021+ * @buf: Pointer to "struct ccs_path_info".
2022+ * @path: Pointer to "struct path". @path->mnt may be NULL.
2023+ *
2024+ * Returns true on success, false otherwise.
2025+ */
2026+static bool ccs_get_realpath(struct ccs_path_info *buf, struct path *path)
2027+{
2028+ buf->name = ccs_realpath(path);
2029+ if (buf->name) {
2030+ ccs_fill_path_info(buf);
2031+ return true;
2032+ }
2033+ return false;
2034+}
2035+
2036+/**
2037+ * ccs_check_path_acl - Check permission for path operation.
2038+ *
2039+ * @r: Pointer to "struct ccs_request_info".
2040+ * @ptr: Pointer to "struct ccs_acl_info".
2041+ *
2042+ * Returns true if granted, false otherwise.
2043+ *
2044+ * To be able to use wildcard for domain transition, this function sets
2045+ * matching entry on success. Since the caller holds ccs_read_lock(),
2046+ * it is safe to set matching entry.
2047+ */
2048+static bool ccs_check_path_acl(struct ccs_request_info *r,
2049+ const struct ccs_acl_info *ptr)
2050+{
2051+ const struct ccs_path_acl *acl = container_of(ptr, typeof(*acl), head);
2052+ if (ptr->perm & (1 << r->param.path.operation)) {
2053+ r->param.path.matched_path =
2054+ ccs_compare_name_union(r->param.path.filename,
2055+ &acl->name);
2056+ return r->param.path.matched_path != NULL;
2057+ }
2058+ return false;
2059+}
2060+
2061+/**
2062+ * ccs_check_path_number_acl - Check permission for path number operation.
2063+ *
2064+ * @r: Pointer to "struct ccs_request_info".
2065+ * @ptr: Pointer to "struct ccs_acl_info".
2066+ *
2067+ * Returns true if granted, false otherwise.
2068+ */
2069+static bool ccs_check_path_number_acl(struct ccs_request_info *r,
2070+ const struct ccs_acl_info *ptr)
2071+{
2072+ const struct ccs_path_number_acl *acl =
2073+ container_of(ptr, typeof(*acl), head);
2074+ return (ptr->perm & (1 << r->param.path_number.operation)) &&
2075+ ccs_compare_number_union(r->param.path_number.number,
2076+ &acl->number) &&
2077+ ccs_compare_name_union(r->param.path_number.filename,
2078+ &acl->name);
2079+}
2080+
2081+/**
2082+ * ccs_check_path2_acl - Check permission for path path operation.
2083+ *
2084+ * @r: Pointer to "struct ccs_request_info".
2085+ * @ptr: Pointer to "struct ccs_acl_info".
2086+ *
2087+ * Returns true if granted, false otherwise.
2088+ */
2089+static bool ccs_check_path2_acl(struct ccs_request_info *r,
2090+ const struct ccs_acl_info *ptr)
2091+{
2092+ const struct ccs_path2_acl *acl =
2093+ container_of(ptr, typeof(*acl), head);
2094+ return (ptr->perm & (1 << r->param.path2.operation)) &&
2095+ ccs_compare_name_union(r->param.path2.filename1, &acl->name1)
2096+ && ccs_compare_name_union(r->param.path2.filename2,
2097+ &acl->name2);
2098+}
2099+
2100+/**
2101+ * ccs_check_mkdev_acl - Check permission for path number number number operation.
2102+ *
2103+ * @r: Pointer to "struct ccs_request_info".
2104+ * @ptr: Pointer to "struct ccs_acl_info".
2105+ *
2106+ * Returns true if granted, false otherwise.
2107+ */
2108+static bool ccs_check_mkdev_acl(struct ccs_request_info *r,
2109+ const struct ccs_acl_info *ptr)
2110+{
2111+ const struct ccs_mkdev_acl *acl =
2112+ container_of(ptr, typeof(*acl), head);
2113+ return (ptr->perm & (1 << r->param.mkdev.operation)) &&
2114+ ccs_compare_number_union(r->param.mkdev.mode, &acl->mode) &&
2115+ ccs_compare_number_union(r->param.mkdev.major, &acl->major) &&
2116+ ccs_compare_number_union(r->param.mkdev.minor, &acl->minor) &&
2117+ ccs_compare_name_union(r->param.mkdev.filename, &acl->name);
2118+}
2119+
2120+/**
2121+ * ccs_path_permission - Check permission for path operation.
2122+ *
2123+ * @r: Pointer to "struct ccs_request_info".
2124+ * @operation: Type of operation.
2125+ * @filename: Filename to check.
2126+ *
2127+ * Returns 0 on success, negative value otherwise.
2128+ *
2129+ * Caller holds ccs_read_lock().
2130+ */
2131+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) || !defined(CONFIG_SYSCTL_SYSCALL)
2132+static
2133+#endif
2134+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
2135+ const struct ccs_path_info *filename)
2136+{
2137+ r->type = ccs_p2mac[operation];
2138+ r->mode = ccs_get_mode(r->profile, r->type);
2139+ if (r->mode == CCS_CONFIG_DISABLED)
2140+ return 0;
2141+ r->param_type = CCS_TYPE_PATH_ACL;
2142+ r->param.path.filename = filename;
2143+ r->param.path.operation = operation;
2144+ return ccs_check_acl(r);
2145+}
2146+
2147+/**
2148+ * ccs_execute_permission - Check permission for execute operation.
2149+ *
2150+ * @r: Pointer to "struct ccs_request_info".
2151+ * @filename: Filename to check.
2152+ *
2153+ * Returns 0 on success, CCS_RETRY_REQUEST on retry, negative value otherwise.
2154+ *
2155+ * Caller holds ccs_read_lock().
2156+ */
2157+static int ccs_execute_permission(struct ccs_request_info *r,
2158+ const struct ccs_path_info *filename)
2159+{
2160+ int error;
2161+ /*
2162+ * Unlike other permission checks, this check is done regardless of
2163+ * profile mode settings in order to check for domain transition
2164+ * preference.
2165+ */
2166+ r->type = CCS_MAC_FILE_EXECUTE;
2167+ r->mode = ccs_get_mode(r->profile, r->type);
2168+ r->param_type = CCS_TYPE_PATH_ACL;
2169+ r->param.path.filename = filename;
2170+ r->param.path.operation = CCS_TYPE_EXECUTE;
2171+ error = ccs_check_acl(r);
2172+ r->ee->transition = r->matched_acl && r->matched_acl->cond &&
2173+ r->matched_acl->cond->exec_transit ?
2174+ r->matched_acl->cond->transit : NULL;
2175+ return error;
2176+}
2177+
2178+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
2179+
2180+/**
2181+ * __ccs_save_open_mode - Remember original flags passed to sys_open().
2182+ *
2183+ * @mode: Flags passed to sys_open().
2184+ *
2185+ * Returns nothing.
2186+ *
2187+ * TOMOYO does not check "file write" if open(path, O_TRUNC | O_RDONLY) was
2188+ * requested because write() is not permitted. Instead, TOMOYO checks
2189+ * "file truncate" if O_TRUNC is passed.
2190+ *
2191+ * TOMOYO does not check "file read" and "file write" if open(path, 3) was
2192+ * requested because read()/write() are not permitted. Instead, TOMOYO checks
2193+ * "file ioctl" when ioctl() is requested.
2194+ */
2195+static void __ccs_save_open_mode(int mode)
2196+{
2197+ if ((mode & 3) == 3)
2198+ ccs_current_security()->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
2199+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
2200+ /* O_TRUNC passes MAY_WRITE to ccs_open_permission(). */
2201+ else if (!(mode & 3) && (mode & O_TRUNC))
2202+ ccs_current_security()->ccs_flags |=
2203+ CCS_OPEN_FOR_READ_TRUNCATE;
2204+#endif
2205+}
2206+
2207+/**
2208+ * __ccs_clear_open_mode - Forget original flags passed to sys_open().
2209+ *
2210+ * Returns nothing.
2211+ */
2212+static void __ccs_clear_open_mode(void)
2213+{
2214+ ccs_current_security()->ccs_flags &= ~(CCS_OPEN_FOR_IOCTL_ONLY |
2215+ CCS_OPEN_FOR_READ_TRUNCATE);
2216+}
2217+
2218+#endif
2219+
2220+/**
2221+ * __ccs_open_permission - Check permission for "read" and "write".
2222+ *
2223+ * @dentry: Pointer to "struct dentry".
2224+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2225+ * @flag: Flags for open().
2226+ *
2227+ * Returns 0 on success, negative value otherwise.
2228+ */
2229+static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
2230+ const int flag)
2231+{
2232+ struct ccs_request_info r;
2233+ struct ccs_obj_info obj = {
2234+ .path1.dentry = dentry,
2235+ .path1.mnt = mnt,
2236+ };
2237+ const u32 ccs_flags = ccs_current_flags();
2238+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2239+ const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
2240+#else
2241+ const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
2242+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
2243+ (ccs_flags & CCS_OPEN_FOR_READ_TRUNCATE) ? 4 :
2244+#endif
2245+ ACC_MODE(flag);
2246+#endif
2247+ int error = 0;
2248+ struct ccs_path_info buf;
2249+ int idx;
2250+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
2251+ if (current->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
2252+ return 0;
2253+#endif
2254+#ifndef CONFIG_CCSECURITY_FILE_GETATTR
2255+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
2256+ return 0;
2257+#endif
2258+ buf.name = NULL;
2259+ r.mode = CCS_CONFIG_DISABLED;
2260+ idx = ccs_read_lock();
2261+ if (acc_mode && ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2262+ != CCS_CONFIG_DISABLED) {
2263+ if (!ccs_get_realpath(&buf, &obj.path1)) {
2264+ error = -ENOMEM;
2265+ goto out;
2266+ }
2267+ r.obj = &obj;
2268+ if (acc_mode & MAY_READ)
2269+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
2270+ if (!error && (acc_mode & MAY_WRITE))
2271+ error = ccs_path_permission(&r, (flag & O_APPEND) ?
2272+ CCS_TYPE_APPEND :
2273+ CCS_TYPE_WRITE, &buf);
2274+ }
2275+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
2276+ if (!error && (flag & O_TRUNC) &&
2277+ ccs_init_request_info(&r, CCS_MAC_FILE_TRUNCATE)
2278+ != CCS_CONFIG_DISABLED) {
2279+ if (!buf.name && !ccs_get_realpath(&buf, &obj.path1)) {
2280+ error = -ENOMEM;
2281+ goto out;
2282+ }
2283+ r.obj = &obj;
2284+ error = ccs_path_permission(&r, CCS_TYPE_TRUNCATE, &buf);
2285+ }
2286+#endif
2287+out:
2288+ kfree(buf.name);
2289+ ccs_read_unlock(idx);
2290+ if (r.mode != CCS_CONFIG_ENFORCING)
2291+ error = 0;
2292+ return error;
2293+}
2294+
2295+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2296+
2297+/**
2298+ * ccs_new_open_permission - Check permission for "read" and "write".
2299+ *
2300+ * @filp: Pointer to "struct file".
2301+ *
2302+ * Returns 0 on success, negative value otherwise.
2303+ */
2304+static int ccs_new_open_permission(struct file *filp)
2305+{
2306+ return __ccs_open_permission(filp->f_path.dentry, filp->f_path.mnt,
2307+ filp->f_flags);
2308+}
2309+
2310+#endif
2311+
2312+/**
2313+ * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "getattr", "chroot" and "unmount".
2314+ *
2315+ * @operation: Type of operation.
2316+ * @dentry: Pointer to "struct dentry".
2317+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2318+ * @target: Symlink's target if @operation is CCS_TYPE_SYMLINK,
2319+ * NULL otherwise.
2320+ *
2321+ * Returns 0 on success, negative value otherwise.
2322+ */
2323+static int ccs_path_perm(const u8 operation, struct dentry *dentry,
2324+ struct vfsmount *mnt, const char *target)
2325+{
2326+ struct ccs_request_info r;
2327+ struct ccs_obj_info obj = {
2328+ .path1.dentry = dentry,
2329+ .path1.mnt = mnt,
2330+ };
2331+ int error = 0;
2332+ struct ccs_path_info buf;
2333+ bool is_enforce = false;
2334+ struct ccs_path_info symlink_target;
2335+ int idx;
2336+ buf.name = NULL;
2337+ symlink_target.name = NULL;
2338+ idx = ccs_read_lock();
2339+ if (ccs_init_request_info(&r, ccs_p2mac[operation])
2340+ == CCS_CONFIG_DISABLED)
2341+ goto out;
2342+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2343+ error = -ENOMEM;
2344+ if (!ccs_get_realpath(&buf, &obj.path1))
2345+ goto out;
2346+ r.obj = &obj;
2347+ switch (operation) {
2348+ case CCS_TYPE_RMDIR:
2349+ case CCS_TYPE_CHROOT:
2350+ ccs_add_slash(&buf);
2351+ break;
2352+ case CCS_TYPE_SYMLINK:
2353+ symlink_target.name = ccs_encode(target);
2354+ if (!symlink_target.name)
2355+ goto out;
2356+ ccs_fill_path_info(&symlink_target);
2357+ obj.symlink_target = &symlink_target;
2358+ break;
2359+ }
2360+ error = ccs_path_permission(&r, operation, &buf);
2361+ if (operation == CCS_TYPE_SYMLINK)
2362+ kfree(symlink_target.name);
2363+out:
2364+ kfree(buf.name);
2365+ ccs_read_unlock(idx);
2366+ if (!is_enforce)
2367+ error = 0;
2368+ return error;
2369+}
2370+
2371+/**
2372+ * ccs_mkdev_perm - Check permission for "mkblock" and "mkchar".
2373+ *
2374+ * @operation: Type of operation. (CCS_TYPE_MKCHAR or CCS_TYPE_MKBLOCK)
2375+ * @dentry: Pointer to "struct dentry".
2376+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2377+ * @mode: Create mode.
2378+ * @dev: Device number.
2379+ *
2380+ * Returns 0 on success, negative value otherwise.
2381+ */
2382+static int ccs_mkdev_perm(const u8 operation, struct dentry *dentry,
2383+ struct vfsmount *mnt, const unsigned int mode,
2384+ unsigned int dev)
2385+{
2386+ struct ccs_request_info r;
2387+ struct ccs_obj_info obj = {
2388+ .path1.dentry = dentry,
2389+ .path1.mnt = mnt,
2390+ };
2391+ int error = 0;
2392+ struct ccs_path_info buf;
2393+ bool is_enforce = false;
2394+ int idx;
2395+ idx = ccs_read_lock();
2396+ if (ccs_init_request_info(&r, ccs_pnnn2mac[operation])
2397+ == CCS_CONFIG_DISABLED)
2398+ goto out;
2399+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2400+ error = -EPERM;
2401+ if (!capable(CAP_MKNOD))
2402+ goto out;
2403+ error = -ENOMEM;
2404+ if (!ccs_get_realpath(&buf, &obj.path1))
2405+ goto out;
2406+ r.obj = &obj;
2407+#ifdef CONFIG_SECURITY_PATH
2408+ dev = new_decode_dev(dev);
2409+#endif
2410+ r.param_type = CCS_TYPE_MKDEV_ACL;
2411+ r.param.mkdev.filename = &buf;
2412+ r.param.mkdev.operation = operation;
2413+ r.param.mkdev.mode = mode;
2414+ r.param.mkdev.major = MAJOR(dev);
2415+ r.param.mkdev.minor = MINOR(dev);
2416+ error = ccs_check_acl(&r);
2417+ kfree(buf.name);
2418+out:
2419+ ccs_read_unlock(idx);
2420+ if (!is_enforce)
2421+ error = 0;
2422+ return error;
2423+}
2424+
2425+/**
2426+ * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
2427+ *
2428+ * @operation: Type of operation.
2429+ * @dentry1: Pointer to "struct dentry".
2430+ * @mnt1: Pointer to "struct vfsmount". Maybe NULL.
2431+ * @dentry2: Pointer to "struct dentry".
2432+ * @mnt2: Pointer to "struct vfsmount". Maybe NULL.
2433+ *
2434+ * Returns 0 on success, negative value otherwise.
2435+ */
2436+static int ccs_path2_perm(const u8 operation, struct dentry *dentry1,
2437+ struct vfsmount *mnt1, struct dentry *dentry2,
2438+ struct vfsmount *mnt2)
2439+{
2440+ struct ccs_request_info r;
2441+ int error = 0;
2442+ struct ccs_path_info buf1;
2443+ struct ccs_path_info buf2;
2444+ bool is_enforce = false;
2445+ struct ccs_obj_info obj = {
2446+ .path1.dentry = dentry1,
2447+ .path1.mnt = mnt1,
2448+ .path2.dentry = dentry2,
2449+ .path2.mnt = mnt2,
2450+ };
2451+ int idx;
2452+ buf1.name = NULL;
2453+ buf2.name = NULL;
2454+ idx = ccs_read_lock();
2455+ if (ccs_init_request_info(&r, ccs_pp2mac[operation])
2456+ == CCS_CONFIG_DISABLED)
2457+ goto out;
2458+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
2459+ error = -ENOMEM;
2460+ if (!ccs_get_realpath(&buf1, &obj.path1) ||
2461+ !ccs_get_realpath(&buf2, &obj.path2))
2462+ goto out;
2463+ switch (operation) {
2464+ case CCS_TYPE_RENAME:
2465+ case CCS_TYPE_LINK:
2466+ if (!dentry1->d_inode || !S_ISDIR(dentry1->d_inode->i_mode))
2467+ break;
2468+ /* fall through */
2469+ case CCS_TYPE_PIVOT_ROOT:
2470+ ccs_add_slash(&buf1);
2471+ ccs_add_slash(&buf2);
2472+ break;
2473+ }
2474+ r.obj = &obj;
2475+ r.param_type = CCS_TYPE_PATH2_ACL;
2476+ r.param.path2.operation = operation;
2477+ r.param.path2.filename1 = &buf1;
2478+ r.param.path2.filename2 = &buf2;
2479+ error = ccs_check_acl(&r);
2480+out:
2481+ kfree(buf1.name);
2482+ kfree(buf2.name);
2483+ ccs_read_unlock(idx);
2484+ if (!is_enforce)
2485+ error = 0;
2486+ return error;
2487+}
2488+
2489+/**
2490+ * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
2491+ *
2492+ * @type: Type of operation.
2493+ * @dentry: Pointer to "struct dentry".
2494+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2495+ * @number: Number.
2496+ *
2497+ * Returns 0 on success, negative value otherwise.
2498+ */
2499+static int ccs_path_number_perm(const u8 type, struct dentry *dentry,
2500+ struct vfsmount *vfsmnt, unsigned long number)
2501+{
2502+ struct ccs_request_info r;
2503+ struct ccs_obj_info obj = {
2504+ .path1.dentry = dentry,
2505+ .path1.mnt = vfsmnt,
2506+ };
2507+ int error = 0;
2508+ struct ccs_path_info buf;
2509+ int idx;
2510+ if (!dentry)
2511+ return 0;
2512+ idx = ccs_read_lock();
2513+ if (ccs_init_request_info(&r, ccs_pn2mac[type]) == CCS_CONFIG_DISABLED)
2514+ goto out;
2515+ error = -ENOMEM;
2516+ if (!ccs_get_realpath(&buf, &obj.path1))
2517+ goto out;
2518+ r.obj = &obj;
2519+ if (type == CCS_TYPE_MKDIR)
2520+ ccs_add_slash(&buf);
2521+ r.param_type = CCS_TYPE_PATH_NUMBER_ACL;
2522+ r.param.path_number.operation = type;
2523+ r.param.path_number.filename = &buf;
2524+ r.param.path_number.number = number;
2525+ error = ccs_check_acl(&r);
2526+ kfree(buf.name);
2527+out:
2528+ ccs_read_unlock(idx);
2529+ if (r.mode != CCS_CONFIG_ENFORCING)
2530+ error = 0;
2531+ return error;
2532+}
2533+
2534+/**
2535+ * __ccs_ioctl_permission - Check permission for "ioctl".
2536+ *
2537+ * @filp: Pointer to "struct file".
2538+ * @cmd: Ioctl command number.
2539+ * @arg: Param for @cmd.
2540+ *
2541+ * Returns 0 on success, negative value otherwise.
2542+ */
2543+static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
2544+ unsigned long arg)
2545+{
2546+ return ccs_path_number_perm(CCS_TYPE_IOCTL, filp->f_dentry,
2547+ filp->f_vfsmnt, cmd);
2548+}
2549+
2550+/**
2551+ * __ccs_chmod_permission - Check permission for "chmod".
2552+ *
2553+ * @dentry: Pointer to "struct dentry".
2554+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2555+ * @mode: Mode.
2556+ *
2557+ * Returns 0 on success, negative value otherwise.
2558+ */
2559+static int __ccs_chmod_permission(struct dentry *dentry,
2560+ struct vfsmount *vfsmnt, mode_t mode)
2561+{
2562+ if (mode == (mode_t) -1)
2563+ return 0;
2564+ return ccs_path_number_perm(CCS_TYPE_CHMOD, dentry, vfsmnt,
2565+ mode & S_IALLUGO);
2566+}
2567+
2568+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
2569+
2570+/**
2571+ * __ccs_chown_permission - Check permission for "chown/chgrp".
2572+ *
2573+ * @dentry: Pointer to "struct dentry".
2574+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2575+ * @user: User ID.
2576+ * @group: Group ID.
2577+ *
2578+ * Returns 0 on success, negative value otherwise.
2579+ */
2580+static int __ccs_chown_permission(struct dentry *dentry,
2581+ struct vfsmount *vfsmnt, kuid_t user,
2582+ kgid_t group)
2583+{
2584+ int error = 0;
2585+ if (uid_valid(user))
2586+ error = ccs_path_number_perm(CCS_TYPE_CHOWN, dentry, vfsmnt,
2587+ from_kuid(&init_user_ns, user));
2588+ if (!error && gid_valid(group))
2589+ error = ccs_path_number_perm(CCS_TYPE_CHGRP, dentry, vfsmnt,
2590+ from_kgid(&init_user_ns, group));
2591+ return error;
2592+}
2593+
2594+#else
2595+
2596+/**
2597+ * __ccs_chown_permission - Check permission for "chown/chgrp".
2598+ *
2599+ * @dentry: Pointer to "struct dentry".
2600+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
2601+ * @user: User ID.
2602+ * @group: Group ID.
2603+ *
2604+ * Returns 0 on success, negative value otherwise.
2605+ */
2606+static int __ccs_chown_permission(struct dentry *dentry,
2607+ struct vfsmount *vfsmnt, uid_t user,
2608+ gid_t group)
2609+{
2610+ int error = 0;
2611+ if (user == (uid_t) -1 && group == (gid_t) -1)
2612+ return 0;
2613+ if (user != (uid_t) -1)
2614+ error = ccs_path_number_perm(CCS_TYPE_CHOWN, dentry, vfsmnt,
2615+ user);
2616+ if (!error && group != (gid_t) -1)
2617+ error = ccs_path_number_perm(CCS_TYPE_CHGRP, dentry, vfsmnt,
2618+ group);
2619+ return error;
2620+}
2621+
2622+#endif
2623+
2624+/**
2625+ * __ccs_fcntl_permission - Check permission for changing O_APPEND flag.
2626+ *
2627+ * @file: Pointer to "struct file".
2628+ * @cmd: Command number.
2629+ * @arg: Value for @cmd.
2630+ *
2631+ * Returns 0 on success, negative value otherwise.
2632+ */
2633+static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
2634+ unsigned long arg)
2635+{
2636+ if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
2637+ return 0;
2638+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2639+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2640+ O_WRONLY | (arg & O_APPEND));
2641+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
2642+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2643+ O_WRONLY | (arg & O_APPEND));
2644+#else
2645+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
2646+ (O_WRONLY + 1) | (arg & O_APPEND));
2647+#endif
2648+}
2649+
2650+/**
2651+ * __ccs_pivot_root_permission - Check permission for pivot_root().
2652+ *
2653+ * @old_path: Pointer to "struct path".
2654+ * @new_path: Pointer to "struct path".
2655+ *
2656+ * Returns 0 on success, negative value otherwise.
2657+ */
2658+static int __ccs_pivot_root_permission(struct path *old_path,
2659+ struct path *new_path)
2660+{
2661+ return ccs_path2_perm(CCS_TYPE_PIVOT_ROOT, new_path->dentry,
2662+ new_path->mnt, old_path->dentry, old_path->mnt);
2663+}
2664+
2665+/**
2666+ * __ccs_chroot_permission - Check permission for chroot().
2667+ *
2668+ * @path: Pointer to "struct path".
2669+ *
2670+ * Returns 0 on success, negative value otherwise.
2671+ */
2672+static int __ccs_chroot_permission(struct path *path)
2673+{
2674+ return ccs_path_perm(CCS_TYPE_CHROOT, path->dentry, path->mnt, NULL);
2675+}
2676+
2677+/**
2678+ * __ccs_umount_permission - Check permission for unmount.
2679+ *
2680+ * @mnt: Pointer to "struct vfsmount".
2681+ * @flags: Unused.
2682+ *
2683+ * Returns 0 on success, negative value otherwise.
2684+ */
2685+static int __ccs_umount_permission(struct vfsmount *mnt, int flags)
2686+{
2687+ return ccs_path_perm(CCS_TYPE_UMOUNT, mnt->mnt_root, mnt, NULL);
2688+}
2689+
2690+/**
2691+ * __ccs_mknod_permission - Check permission for vfs_mknod().
2692+ *
2693+ * @dentry: Pointer to "struct dentry".
2694+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2695+ * @mode: Device type and permission.
2696+ * @dev: Device number for block or character device.
2697+ *
2698+ * Returns 0 on success, negative value otherwise.
2699+ */
2700+static int __ccs_mknod_permission(struct dentry *dentry, struct vfsmount *mnt,
2701+ const unsigned int mode, unsigned int dev)
2702+{
2703+ int error = 0;
2704+ const unsigned int perm = mode & S_IALLUGO;
2705+ switch (mode & S_IFMT) {
2706+ case S_IFCHR:
2707+ error = ccs_mkdev_perm(CCS_TYPE_MKCHAR, dentry, mnt, perm,
2708+ dev);
2709+ break;
2710+ case S_IFBLK:
2711+ error = ccs_mkdev_perm(CCS_TYPE_MKBLOCK, dentry, mnt, perm,
2712+ dev);
2713+ break;
2714+ case S_IFIFO:
2715+ error = ccs_path_number_perm(CCS_TYPE_MKFIFO, dentry, mnt,
2716+ perm);
2717+ break;
2718+ case S_IFSOCK:
2719+ error = ccs_path_number_perm(CCS_TYPE_MKSOCK, dentry, mnt,
2720+ perm);
2721+ break;
2722+ case 0:
2723+ case S_IFREG:
2724+ error = ccs_path_number_perm(CCS_TYPE_CREATE, dentry, mnt,
2725+ perm);
2726+ break;
2727+ }
2728+ return error;
2729+}
2730+
2731+/**
2732+ * __ccs_mkdir_permission - Check permission for vfs_mkdir().
2733+ *
2734+ * @dentry: Pointer to "struct dentry".
2735+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2736+ * @mode: Create mode.
2737+ *
2738+ * Returns 0 on success, negative value otherwise.
2739+ */
2740+static int __ccs_mkdir_permission(struct dentry *dentry, struct vfsmount *mnt,
2741+ unsigned int mode)
2742+{
2743+ return ccs_path_number_perm(CCS_TYPE_MKDIR, dentry, mnt, mode);
2744+}
2745+
2746+/**
2747+ * __ccs_rmdir_permission - Check permission for vfs_rmdir().
2748+ *
2749+ * @dentry: Pointer to "struct dentry".
2750+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2751+ *
2752+ * Returns 0 on success, negative value otherwise.
2753+ */
2754+static int __ccs_rmdir_permission(struct dentry *dentry, struct vfsmount *mnt)
2755+{
2756+ return ccs_path_perm(CCS_TYPE_RMDIR, dentry, mnt, NULL);
2757+}
2758+
2759+/**
2760+ * __ccs_unlink_permission - Check permission for vfs_unlink().
2761+ *
2762+ * @dentry: Pointer to "struct dentry".
2763+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2764+ *
2765+ * Returns 0 on success, negative value otherwise.
2766+ */
2767+static int __ccs_unlink_permission(struct dentry *dentry, struct vfsmount *mnt)
2768+{
2769+ return ccs_path_perm(CCS_TYPE_UNLINK, dentry, mnt, NULL);
2770+}
2771+
2772+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
2773+
2774+/**
2775+ * __ccs_getattr_permission - Check permission for vfs_getattr().
2776+ *
2777+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2778+ * @dentry: Pointer to "struct dentry".
2779+ *
2780+ * Returns 0 on success, negative value otherwise.
2781+ */
2782+static int __ccs_getattr_permission(struct vfsmount *mnt,
2783+ struct dentry *dentry)
2784+{
2785+ return ccs_path_perm(CCS_TYPE_GETATTR, dentry, mnt, NULL);
2786+}
2787+
2788+#endif
2789+
2790+/**
2791+ * __ccs_symlink_permission - Check permission for vfs_symlink().
2792+ *
2793+ * @dentry: Pointer to "struct dentry".
2794+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2795+ * @from: Content of symlink.
2796+ *
2797+ * Returns 0 on success, negative value otherwise.
2798+ */
2799+static int __ccs_symlink_permission(struct dentry *dentry,
2800+ struct vfsmount *mnt, const char *from)
2801+{
2802+ return ccs_path_perm(CCS_TYPE_SYMLINK, dentry, mnt, from);
2803+}
2804+
2805+/**
2806+ * __ccs_truncate_permission - Check permission for notify_change().
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_truncate_permission(struct dentry *dentry,
2814+ struct vfsmount *mnt)
2815+{
2816+ return ccs_path_perm(CCS_TYPE_TRUNCATE, dentry, mnt, NULL);
2817+}
2818+
2819+/**
2820+ * __ccs_rename_permission - Check permission for vfs_rename().
2821+ *
2822+ * @old_dentry: Pointer to "struct dentry".
2823+ * @new_dentry: Pointer to "struct dentry".
2824+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2825+ *
2826+ * Returns 0 on success, negative value otherwise.
2827+ */
2828+static int __ccs_rename_permission(struct dentry *old_dentry,
2829+ struct dentry *new_dentry,
2830+ struct vfsmount *mnt)
2831+{
2832+ return ccs_path2_perm(CCS_TYPE_RENAME, old_dentry, mnt, new_dentry,
2833+ mnt);
2834+}
2835+
2836+/**
2837+ * __ccs_link_permission - Check permission for vfs_link().
2838+ *
2839+ * @old_dentry: Pointer to "struct dentry".
2840+ * @new_dentry: Pointer to "struct dentry".
2841+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
2842+ *
2843+ * Returns 0 on success, negative value otherwise.
2844+ */
2845+static int __ccs_link_permission(struct dentry *old_dentry,
2846+ struct dentry *new_dentry,
2847+ struct vfsmount *mnt)
2848+{
2849+ return ccs_path2_perm(CCS_TYPE_LINK, old_dentry, mnt, new_dentry, mnt);
2850+}
2851+
2852+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
2853+
2854+/**
2855+ * __ccs_open_exec_permission - Check permission for open_exec().
2856+ *
2857+ * @dentry: Pointer to "struct dentry".
2858+ * @mnt: Pointer to "struct vfsmount".
2859+ *
2860+ * Returns 0 on success, negative value otherwise.
2861+ */
2862+static int __ccs_open_exec_permission(struct dentry *dentry,
2863+ struct vfsmount *mnt)
2864+{
2865+ return (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE) ?
2866+ __ccs_open_permission(dentry, mnt, O_RDONLY + 1) : 0;
2867+}
2868+
2869+/**
2870+ * __ccs_uselib_permission - Check permission for sys_uselib().
2871+ *
2872+ * @dentry: Pointer to "struct dentry".
2873+ * @mnt: Pointer to "struct vfsmount".
2874+ *
2875+ * Returns 0 on success, negative value otherwise.
2876+ */
2877+static int __ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
2878+{
2879+ return __ccs_open_permission(dentry, mnt, O_RDONLY + 1);
2880+}
2881+
2882+#endif
2883+
2884+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
2885+
2886+/**
2887+ * __ccs_parse_table - Check permission for parse_table().
2888+ *
2889+ * @name: Pointer to "int __user".
2890+ * @nlen: Number of elements in @name.
2891+ * @oldval: Pointer to "void __user".
2892+ * @newval: Pointer to "void __user".
2893+ * @table: Pointer to "struct ctl_table".
2894+ *
2895+ * Returns 0 on success, negative value otherwise.
2896+ *
2897+ * Note that this function is racy because this function checks values in
2898+ * userspace memory which could be changed after permission check.
2899+ */
2900+static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
2901+ void __user *newval, struct ctl_table *table)
2902+{
2903+ int n;
2904+ int error = -ENOMEM;
2905+ int op = 0;
2906+ struct ccs_path_info buf;
2907+ char *buffer = NULL;
2908+ struct ccs_request_info r;
2909+ int idx;
2910+ if (oldval)
2911+ op |= 004;
2912+ if (newval)
2913+ op |= 002;
2914+ if (!op) /* Neither read nor write */
2915+ return 0;
2916+ idx = ccs_read_lock();
2917+ if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2918+ == CCS_CONFIG_DISABLED) {
2919+ error = 0;
2920+ goto out;
2921+ }
2922+ buffer = kmalloc(PAGE_SIZE, CCS_GFP_FLAGS);
2923+ if (!buffer)
2924+ goto out;
2925+ snprintf(buffer, PAGE_SIZE - 1, "proc:/sys");
2926+repeat:
2927+ if (!nlen) {
2928+ error = -ENOTDIR;
2929+ goto out;
2930+ }
2931+ if (get_user(n, name)) {
2932+ error = -EFAULT;
2933+ goto out;
2934+ }
2935+ for ( ; table->ctl_name
2936+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
2937+ || table->procname
2938+#endif
2939+ ; table++) {
2940+ int pos;
2941+ const char *cp;
2942+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2943+ if (n != table->ctl_name && table->ctl_name != CTL_ANY)
2944+ continue;
2945+#else
2946+ if (!n || n != table->ctl_name)
2947+ continue;
2948+#endif
2949+ pos = strlen(buffer);
2950+ cp = table->procname;
2951+ error = -ENOMEM;
2952+ if (cp) {
2953+ int len = strlen(cp);
2954+ if (len + 2 > PAGE_SIZE - 1)
2955+ goto out;
2956+ buffer[pos++] = '/';
2957+ memmove(buffer + pos, cp, len + 1);
2958+ } else {
2959+ /* Assume nobody assigns "=\$=" for procname. */
2960+ snprintf(buffer + pos, PAGE_SIZE - pos - 1,
2961+ "/=%d=", table->ctl_name);
2962+ if (!memchr(buffer, '\0', PAGE_SIZE - 2))
2963+ goto out;
2964+ }
2965+ if (!table->child)
2966+ goto no_child;
2967+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2968+ if (!table->strategy)
2969+ goto no_strategy;
2970+ /* printk("sysctl='%s'\n", buffer); */
2971+ buf.name = ccs_encode(buffer);
2972+ if (!buf.name)
2973+ goto out;
2974+ ccs_fill_path_info(&buf);
2975+ if (op & MAY_READ)
2976+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
2977+ else
2978+ error = 0;
2979+ if (!error && (op & MAY_WRITE))
2980+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
2981+ kfree(buf.name);
2982+ if (error)
2983+ goto out;
2984+no_strategy:
2985+#endif
2986+ name++;
2987+ nlen--;
2988+ table = table->child;
2989+ goto repeat;
2990+no_child:
2991+ /* printk("sysctl='%s'\n", buffer); */
2992+ buf.name = ccs_encode(buffer);
2993+ if (!buf.name)
2994+ goto out;
2995+ ccs_fill_path_info(&buf);
2996+ if (op & MAY_READ)
2997+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
2998+ else
2999+ error = 0;
3000+ if (!error && (op & MAY_WRITE))
3001+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
3002+ kfree(buf.name);
3003+ goto out;
3004+ }
3005+ error = -ENOTDIR;
3006+out:
3007+ ccs_read_unlock(idx);
3008+ kfree(buffer);
3009+ return error;
3010+}
3011+
3012+#endif
3013+
3014+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
3015+
3016+/**
3017+ * ccs_old_pivot_root_permission - Check permission for pivot_root().
3018+ *
3019+ * @old_nd: Pointer to "struct nameidata".
3020+ * @new_nd: Pointer to "struct nameidata".
3021+ *
3022+ * Returns 0 on success, negative value otherwise.
3023+ */
3024+static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
3025+ struct nameidata *new_nd)
3026+{
3027+ struct path old_path = { old_nd->mnt, old_nd->dentry };
3028+ struct path new_path = { new_nd->mnt, new_nd->dentry };
3029+ return __ccs_pivot_root_permission(&old_path, &new_path);
3030+}
3031+
3032+/**
3033+ * ccs_old_chroot_permission - Check permission for chroot().
3034+ *
3035+ * @nd: Pointer to "struct nameidata".
3036+ *
3037+ * Returns 0 on success, negative value otherwise.
3038+ */
3039+static int ccs_old_chroot_permission(struct nameidata *nd)
3040+{
3041+ struct path path = { nd->mnt, nd->dentry };
3042+ return __ccs_chroot_permission(&path);
3043+}
3044+
3045+#endif
3046+
3047+#ifdef CONFIG_CCSECURITY_NETWORK
3048+
3049+/**
3050+ * ccs_address_matches_group - Check whether the given address matches members of the given address group.
3051+ *
3052+ * @is_ipv6: True if @address is an IPv6 address.
3053+ * @address: An IPv4 or IPv6 address.
3054+ * @group: Pointer to "struct ccs_address_group".
3055+ *
3056+ * Returns true if @address matches addresses in @group group, false otherwise.
3057+ *
3058+ * Caller holds ccs_read_lock().
3059+ */
3060+static bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
3061+ const struct ccs_group *group)
3062+{
3063+ struct ccs_address_group *member;
3064+ bool matched = false;
3065+ const u8 size = is_ipv6 ? 16 : 4;
3066+ list_for_each_entry_srcu(member, &group->member_list, head.list,
3067+ &ccs_ss) {
3068+ if (member->head.is_deleted)
3069+ continue;
3070+ if (member->address.is_ipv6 != is_ipv6)
3071+ continue;
3072+ if (memcmp(&member->address.ip[0], address, size) > 0 ||
3073+ memcmp(address, &member->address.ip[1], size) > 0)
3074+ continue;
3075+ matched = true;
3076+ break;
3077+ }
3078+ return matched;
3079+}
3080+
3081+/**
3082+ * ccs_check_inet_acl - Check permission for inet domain socket operation.
3083+ *
3084+ * @r: Pointer to "struct ccs_request_info".
3085+ * @ptr: Pointer to "struct ccs_acl_info".
3086+ *
3087+ * Returns true if granted, false otherwise.
3088+ */
3089+static bool ccs_check_inet_acl(struct ccs_request_info *r,
3090+ const struct ccs_acl_info *ptr)
3091+{
3092+ const struct ccs_inet_acl *acl = container_of(ptr, typeof(*acl), head);
3093+ const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4;
3094+ if (!(ptr->perm & (1 << r->param.inet_network.operation)) ||
3095+ !ccs_compare_number_union(r->param.inet_network.port, &acl->port))
3096+ return false;
3097+ if (acl->address.group)
3098+ return ccs_address_matches_group(r->param.inet_network.is_ipv6,
3099+ r->param.inet_network.address,
3100+ acl->address.group);
3101+ return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 &&
3102+ memcmp(&acl->address.ip[0],
3103+ r->param.inet_network.address, size) <= 0 &&
3104+ memcmp(r->param.inet_network.address,
3105+ &acl->address.ip[1], size) <= 0;
3106+}
3107+
3108+/**
3109+ * ccs_check_unix_acl - Check permission for unix domain socket operation.
3110+ *
3111+ * @r: Pointer to "struct ccs_request_info".
3112+ * @ptr: Pointer to "struct ccs_acl_info".
3113+ *
3114+ * Returns true if granted, false otherwise.
3115+ */
3116+static bool ccs_check_unix_acl(struct ccs_request_info *r,
3117+ const struct ccs_acl_info *ptr)
3118+{
3119+ const struct ccs_unix_acl *acl = container_of(ptr, typeof(*acl), head);
3120+ return (ptr->perm & (1 << r->param.unix_network.operation)) &&
3121+ ccs_compare_name_union(r->param.unix_network.address,
3122+ &acl->name);
3123+}
3124+
3125+/**
3126+ * ccs_inet_entry - Check permission for INET network operation.
3127+ *
3128+ * @address: Pointer to "struct ccs_addr_info".
3129+ *
3130+ * Returns 0 on success, negative value otherwise.
3131+ */
3132+static int ccs_inet_entry(const struct ccs_addr_info *address)
3133+{
3134+ const int idx = ccs_read_lock();
3135+ struct ccs_request_info r;
3136+ int error = 0;
3137+ const u8 type = ccs_inet2mac[address->protocol][address->operation];
3138+ if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
3139+ r.param_type = CCS_TYPE_INET_ACL;
3140+ r.param.inet_network.protocol = address->protocol;
3141+ r.param.inet_network.operation = address->operation;
3142+ r.param.inet_network.is_ipv6 = address->inet.is_ipv6;
3143+ r.param.inet_network.address = address->inet.address;
3144+ r.param.inet_network.port = ntohs(address->inet.port);
3145+ r.dont_sleep_on_enforce_error =
3146+ address->operation == CCS_NETWORK_ACCEPT
3147+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3148+ || address->operation == CCS_NETWORK_RECV
3149+#endif
3150+ ;
3151+ error = ccs_check_acl(&r);
3152+ }
3153+ ccs_read_unlock(idx);
3154+ return error;
3155+}
3156+
3157+/**
3158+ * ccs_check_inet_address - Check permission for inet domain socket's operation.
3159+ *
3160+ * @addr: Pointer to "struct sockaddr".
3161+ * @addr_len: Size of @addr.
3162+ * @port: Port number.
3163+ * @address: Pointer to "struct ccs_addr_info".
3164+ *
3165+ * Returns 0 on success, negative value otherwise.
3166+ */
3167+static int ccs_check_inet_address(const struct sockaddr *addr,
3168+ const unsigned int addr_len, const u16 port,
3169+ struct ccs_addr_info *address)
3170+{
3171+ struct ccs_inet_addr_info *i = &address->inet;
3172+ switch (addr->sa_family) {
3173+ case AF_INET6:
3174+ if (addr_len < SIN6_LEN_RFC2133)
3175+ goto skip;
3176+ i->is_ipv6 = true;
3177+ i->address = (u32 *)
3178+ ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
3179+ i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
3180+ break;
3181+ case AF_INET:
3182+ if (addr_len < sizeof(struct sockaddr_in))
3183+ goto skip;
3184+ i->is_ipv6 = false;
3185+ i->address = (u32 *) &((struct sockaddr_in *) addr)->sin_addr;
3186+ i->port = ((struct sockaddr_in *) addr)->sin_port;
3187+ break;
3188+ default:
3189+ goto skip;
3190+ }
3191+ if (address->protocol == SOCK_RAW)
3192+ i->port = htons(port);
3193+ return ccs_inet_entry(address);
3194+skip:
3195+ return 0;
3196+}
3197+
3198+/**
3199+ * ccs_unix_entry - Check permission for UNIX network operation.
3200+ *
3201+ * @address: Pointer to "struct ccs_addr_info".
3202+ *
3203+ * Returns 0 on success, negative value otherwise.
3204+ */
3205+static int ccs_unix_entry(const struct ccs_addr_info *address)
3206+{
3207+ const int idx = ccs_read_lock();
3208+ struct ccs_request_info r;
3209+ int error = 0;
3210+ const u8 type = ccs_unix2mac[address->protocol][address->operation];
3211+ if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
3212+ char *buf = address->unix0.addr;
3213+ int len = address->unix0.addr_len - sizeof(sa_family_t);
3214+ if (len <= 0) {
3215+ buf = "anonymous";
3216+ len = 9;
3217+ } else if (buf[0]) {
3218+ len = strnlen(buf, len);
3219+ }
3220+ buf = ccs_encode2(buf, len);
3221+ if (buf) {
3222+ struct ccs_path_info addr;
3223+ addr.name = buf;
3224+ ccs_fill_path_info(&addr);
3225+ r.param_type = CCS_TYPE_UNIX_ACL;
3226+ r.param.unix_network.protocol = address->protocol;
3227+ r.param.unix_network.operation = address->operation;
3228+ r.param.unix_network.address = &addr;
3229+ r.dont_sleep_on_enforce_error =
3230+ address->operation == CCS_NETWORK_ACCEPT
3231+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3232+ || address->operation == CCS_NETWORK_RECV
3233+#endif
3234+ ;
3235+ error = ccs_check_acl(&r);
3236+ kfree(buf);
3237+ } else
3238+ error = -ENOMEM;
3239+ }
3240+ ccs_read_unlock(idx);
3241+ return error;
3242+}
3243+
3244+/**
3245+ * ccs_check_unix_address - Check permission for unix domain socket's operation.
3246+ *
3247+ * @addr: Pointer to "struct sockaddr".
3248+ * @addr_len: Size of @addr.
3249+ * @address: Pointer to "struct ccs_addr_info".
3250+ *
3251+ * Returns 0 on success, negative value otherwise.
3252+ */
3253+static int ccs_check_unix_address(struct sockaddr *addr,
3254+ const unsigned int addr_len,
3255+ struct ccs_addr_info *address)
3256+{
3257+ struct ccs_unix_addr_info *u = &address->unix0;
3258+ if (addr->sa_family != AF_UNIX)
3259+ return 0;
3260+ u->addr = ((struct sockaddr_un *) addr)->sun_path;
3261+ u->addr_len = addr_len;
3262+ return ccs_unix_entry(address);
3263+}
3264+
3265+/**
3266+ * ccs_sock_family - Get socket's family.
3267+ *
3268+ * @sk: Pointer to "struct sock".
3269+ *
3270+ * Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
3271+ */
3272+static u8 ccs_sock_family(struct sock *sk)
3273+{
3274+ u8 family;
3275+ if (ccs_kernel_service())
3276+ return 0;
3277+ family = sk->sk_family;
3278+ switch (family) {
3279+ case PF_INET:
3280+ case PF_INET6:
3281+ case PF_UNIX:
3282+ return family;
3283+ default:
3284+ return 0;
3285+ }
3286+}
3287+
3288+/**
3289+ * __ccs_socket_listen_permission - Check permission for listening a socket.
3290+ *
3291+ * @sock: Pointer to "struct socket".
3292+ *
3293+ * Returns 0 on success, negative value otherwise.
3294+ */
3295+static int __ccs_socket_listen_permission(struct socket *sock)
3296+{
3297+ struct ccs_addr_info address;
3298+ const u8 family = ccs_sock_family(sock->sk);
3299+ const unsigned int type = sock->type;
3300+ struct sockaddr_storage addr;
3301+ int addr_len;
3302+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
3303+ return 0;
3304+ {
3305+ const int error = sock->ops->getname(sock, (struct sockaddr *)
3306+ &addr, &addr_len, 0);
3307+ if (error)
3308+ return error;
3309+ }
3310+ address.protocol = type;
3311+ address.operation = CCS_NETWORK_LISTEN;
3312+ if (family == PF_UNIX)
3313+ return ccs_check_unix_address((struct sockaddr *) &addr,
3314+ addr_len, &address);
3315+ return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
3316+ &address);
3317+}
3318+
3319+/**
3320+ * __ccs_socket_connect_permission - Check permission for setting the remote address of a socket.
3321+ *
3322+ * @sock: Pointer to "struct socket".
3323+ * @addr: Pointer to "struct sockaddr".
3324+ * @addr_len: Size of @addr.
3325+ *
3326+ * Returns 0 on success, negative value otherwise.
3327+ */
3328+static int __ccs_socket_connect_permission(struct socket *sock,
3329+ struct sockaddr *addr, int addr_len)
3330+{
3331+ struct ccs_addr_info address;
3332+ const u8 family = ccs_sock_family(sock->sk);
3333+ const unsigned int type = sock->type;
3334+ if (!family)
3335+ return 0;
3336+ address.protocol = type;
3337+ switch (type) {
3338+ case SOCK_DGRAM:
3339+ case SOCK_RAW:
3340+ address.operation = CCS_NETWORK_SEND;
3341+ break;
3342+ case SOCK_STREAM:
3343+ case SOCK_SEQPACKET:
3344+ address.operation = CCS_NETWORK_CONNECT;
3345+ break;
3346+ default:
3347+ return 0;
3348+ }
3349+ if (family == PF_UNIX)
3350+ return ccs_check_unix_address(addr, addr_len, &address);
3351+ return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
3352+ &address);
3353+}
3354+
3355+/**
3356+ * __ccs_socket_bind_permission - Check permission for setting the local address of a socket.
3357+ *
3358+ * @sock: Pointer to "struct socket".
3359+ * @addr: Pointer to "struct sockaddr".
3360+ * @addr_len: Size of @addr.
3361+ *
3362+ * Returns 0 on success, negative value otherwise.
3363+ */
3364+static int __ccs_socket_bind_permission(struct socket *sock,
3365+ struct sockaddr *addr, int addr_len)
3366+{
3367+ struct ccs_addr_info address;
3368+ const u8 family = ccs_sock_family(sock->sk);
3369+ const unsigned int type = sock->type;
3370+ if (!family)
3371+ return 0;
3372+ switch (type) {
3373+ case SOCK_STREAM:
3374+ case SOCK_DGRAM:
3375+ case SOCK_RAW:
3376+ case SOCK_SEQPACKET:
3377+ address.protocol = type;
3378+ address.operation = CCS_NETWORK_BIND;
3379+ break;
3380+ default:
3381+ return 0;
3382+ }
3383+ if (family == PF_UNIX)
3384+ return ccs_check_unix_address(addr, addr_len, &address);
3385+ return ccs_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
3386+ &address);
3387+}
3388+
3389+/**
3390+ * __ccs_socket_sendmsg_permission - Check permission for sending a datagram.
3391+ *
3392+ * @sock: Pointer to "struct socket".
3393+ * @msg: Pointer to "struct msghdr".
3394+ * @size: Unused.
3395+ *
3396+ * Returns 0 on success, negative value otherwise.
3397+ */
3398+static int __ccs_socket_sendmsg_permission(struct socket *sock,
3399+ struct msghdr *msg, int size)
3400+{
3401+ struct ccs_addr_info address;
3402+ const u8 family = ccs_sock_family(sock->sk);
3403+ const unsigned int type = sock->type;
3404+ if (!msg->msg_name || !family ||
3405+ (type != SOCK_DGRAM && type != SOCK_RAW))
3406+ return 0;
3407+ address.protocol = type;
3408+ address.operation = CCS_NETWORK_SEND;
3409+ if (family == PF_UNIX)
3410+ return ccs_check_unix_address((struct sockaddr *)
3411+ msg->msg_name, msg->msg_namelen,
3412+ &address);
3413+ return ccs_check_inet_address((struct sockaddr *) msg->msg_name,
3414+ msg->msg_namelen, sock->sk->sk_protocol,
3415+ &address);
3416+}
3417+
3418+/**
3419+ * __ccs_socket_post_accept_permission - Check permission for accepting a socket.
3420+ *
3421+ * @sock: Pointer to "struct socket".
3422+ * @newsock: Pointer to "struct socket".
3423+ *
3424+ * Returns 0 on success, negative value otherwise.
3425+ */
3426+static int __ccs_socket_post_accept_permission(struct socket *sock,
3427+ struct socket *newsock)
3428+{
3429+ struct ccs_addr_info address;
3430+ const u8 family = ccs_sock_family(sock->sk);
3431+ const unsigned int type = sock->type;
3432+ struct sockaddr_storage addr;
3433+ int addr_len;
3434+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
3435+ return 0;
3436+ {
3437+ const int error = newsock->ops->getname(newsock,
3438+ (struct sockaddr *)
3439+ &addr, &addr_len, 2);
3440+ if (error)
3441+ return error;
3442+ }
3443+ address.protocol = type;
3444+ address.operation = CCS_NETWORK_ACCEPT;
3445+ if (family == PF_UNIX)
3446+ return ccs_check_unix_address((struct sockaddr *) &addr,
3447+ addr_len, &address);
3448+ return ccs_check_inet_address((struct sockaddr *) &addr, addr_len, 0,
3449+ &address);
3450+}
3451+
3452+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
3453+
3454+/**
3455+ * __ccs_socket_post_recvmsg_permission - Check permission for receiving a datagram.
3456+ *
3457+ * @sk: Pointer to "struct sock".
3458+ * @skb: Pointer to "struct sk_buff".
3459+ * @flags: Flags passed to skb_recv_datagram().
3460+ *
3461+ * Returns 0 on success, negative value otherwise.
3462+ */
3463+static int __ccs_socket_post_recvmsg_permission(struct sock *sk,
3464+ struct sk_buff *skb, int flags)
3465+{
3466+ struct ccs_addr_info address;
3467+ const u8 family = ccs_sock_family(sk);
3468+ const unsigned int type = sk->sk_type;
3469+ struct sockaddr_storage addr;
3470+ if (!family)
3471+ return 0;
3472+ switch (type) {
3473+ case SOCK_DGRAM:
3474+ case SOCK_RAW:
3475+ address.protocol = type;
3476+ break;
3477+ default:
3478+ return 0;
3479+ }
3480+ address.operation = CCS_NETWORK_RECV;
3481+ switch (family) {
3482+ case PF_INET6:
3483+ {
3484+ struct in6_addr *sin6 = (struct in6_addr *) &addr;
3485+ address.inet.is_ipv6 = true;
3486+ if (type == SOCK_DGRAM &&
3487+ skb->protocol == htons(ETH_P_IP))
3488+ ipv6_addr_set(sin6, 0, 0, htonl(0xffff),
3489+ ip_hdr(skb)->saddr);
3490+ else
3491+ *sin6 = ipv6_hdr(skb)->saddr;
3492+ break;
3493+ }
3494+ case PF_INET:
3495+ {
3496+ struct in_addr *sin4 = (struct in_addr *) &addr;
3497+ address.inet.is_ipv6 = false;
3498+ sin4->s_addr = ip_hdr(skb)->saddr;
3499+ break;
3500+ }
3501+ default: /* == PF_UNIX */
3502+ {
3503+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
3504+ struct unix_address *u = unix_sk(skb->sk)->addr;
3505+#else
3506+ struct unix_address *u =
3507+ skb->sk->protinfo.af_unix.addr;
3508+#endif
3509+ unsigned int addr_len;
3510+ if (u && u->len <= sizeof(addr)) {
3511+ addr_len = u->len;
3512+ memcpy(&addr, u->name, addr_len);
3513+ } else {
3514+ addr_len = 0;
3515+ addr.ss_family = AF_UNIX;
3516+ }
3517+ if (ccs_check_unix_address((struct sockaddr *) &addr,
3518+ addr_len, &address))
3519+ goto out;
3520+ return 0;
3521+ }
3522+ }
3523+ address.inet.address = (u32 *) &addr;
3524+ if (type == SOCK_DGRAM)
3525+ address.inet.port = udp_hdr(skb)->source;
3526+ else
3527+ address.inet.port = htons(sk->sk_protocol);
3528+ if (ccs_inet_entry(&address))
3529+ goto out;
3530+ return 0;
3531+out:
3532+ /*
3533+ * Remove from queue if MSG_PEEK is used so that
3534+ * the head message from unwanted source in receive queue will not
3535+ * prevent the caller from picking up next message from wanted source
3536+ * when the caller is using MSG_PEEK flag for picking up.
3537+ */
3538+ {
3539+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
3540+ bool slow = false;
3541+ if (type == SOCK_DGRAM && family != PF_UNIX)
3542+ slow = lock_sock_fast(sk);
3543+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
3544+ if (type == SOCK_DGRAM && family != PF_UNIX)
3545+ lock_sock(sk);
3546+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 2
3547+ if (type == SOCK_DGRAM && family != PF_UNIX)
3548+ lock_sock(sk);
3549+#endif
3550+ skb_kill_datagram(sk, skb, flags);
3551+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
3552+ if (type == SOCK_DGRAM && family != PF_UNIX)
3553+ unlock_sock_fast(sk, slow);
3554+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
3555+ if (type == SOCK_DGRAM && family != PF_UNIX)
3556+ release_sock(sk);
3557+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 2
3558+ if (type == SOCK_DGRAM && family != PF_UNIX)
3559+ release_sock(sk);
3560+#endif
3561+ }
3562+ return -EPERM;
3563+}
3564+
3565+#endif
3566+
3567+#endif
3568+
3569+#if defined(CONFIG_CCSECURITY_CAPABILITY) || defined(CONFIG_CCSECURITY_NETWORK)
3570+
3571+/**
3572+ * ccs_kernel_service - Check whether I'm kernel service or not.
3573+ *
3574+ * Returns true if I'm kernel service, false otherwise.
3575+ */
3576+static bool ccs_kernel_service(void)
3577+{
3578+ /* Nothing to do if I am a kernel service. */
3579+ return segment_eq(get_fs(), KERNEL_DS);
3580+}
3581+
3582+#endif
3583+
3584+#ifdef CONFIG_CCSECURITY_CAPABILITY
3585+
3586+/**
3587+ * ccs_check_capability_acl - Check permission for capability operation.
3588+ *
3589+ * @r: Pointer to "struct ccs_request_info".
3590+ * @ptr: Pointer to "struct ccs_acl_info".
3591+ *
3592+ * Returns true if granted, false otherwise.
3593+ */
3594+static bool ccs_check_capability_acl(struct ccs_request_info *r,
3595+ const struct ccs_acl_info *ptr)
3596+{
3597+ const struct ccs_capability_acl *acl =
3598+ container_of(ptr, typeof(*acl), head);
3599+ return acl->operation == r->param.capability.operation;
3600+}
3601+
3602+/**
3603+ * ccs_capable - Check permission for capability.
3604+ *
3605+ * @operation: Type of operation.
3606+ *
3607+ * Returns true on success, false otherwise.
3608+ */
3609+static bool __ccs_capable(const u8 operation)
3610+{
3611+ struct ccs_request_info r;
3612+ int error = 0;
3613+ const int idx = ccs_read_lock();
3614+ if (ccs_init_request_info(&r, ccs_c2mac[operation])
3615+ != CCS_CONFIG_DISABLED) {
3616+ r.param_type = CCS_TYPE_CAPABILITY_ACL;
3617+ r.param.capability.operation = operation;
3618+ error = ccs_check_acl(&r);
3619+ }
3620+ ccs_read_unlock(idx);
3621+ return !error;
3622+}
3623+
3624+/**
3625+ * __ccs_socket_create_permission - Check permission for creating a socket.
3626+ *
3627+ * @family: Protocol family.
3628+ * @type: Unused.
3629+ * @protocol: Unused.
3630+ *
3631+ * Returns 0 on success, negative value otherwise.
3632+ */
3633+static int __ccs_socket_create_permission(int family, int type, int protocol)
3634+{
3635+ if (ccs_kernel_service())
3636+ return 0;
3637+ if (family == PF_PACKET && !ccs_capable(CCS_USE_PACKET_SOCKET))
3638+ return -EPERM;
3639+ if (family == PF_ROUTE && !ccs_capable(CCS_USE_ROUTE_SOCKET))
3640+ return -EPERM;
3641+ return 0;
3642+}
3643+
3644+/**
3645+ * __ccs_ptrace_permission - Check permission for ptrace().
3646+ *
3647+ * @request: Unused.
3648+ * @pid: Unused.
3649+ *
3650+ * Returns 0 on success, negative value otherwise.
3651+ *
3652+ * Since this function is called from location where it is permitted to sleep,
3653+ * it is racy to check target process's domainname anyway. Therefore, we don't
3654+ * use target process's domainname.
3655+ */
3656+static int __ccs_ptrace_permission(long request, long pid)
3657+{
3658+ return __ccs_capable(CCS_SYS_PTRACE) ? 0 : -EPERM;
3659+}
3660+
3661+#endif
3662+
3663+#ifdef CONFIG_CCSECURITY_IPC
3664+
3665+/**
3666+ * ccs_check_signal_acl - Check permission for signal operation.
3667+ *
3668+ * @r: Pointer to "struct ccs_request_info".
3669+ * @ptr: Pointer to "struct ccs_acl_info".
3670+ *
3671+ * Returns true if granted, false otherwise.
3672+ */
3673+static bool ccs_check_signal_acl(struct ccs_request_info *r,
3674+ const struct ccs_acl_info *ptr)
3675+{
3676+ const struct ccs_signal_acl *acl =
3677+ container_of(ptr, typeof(*acl), head);
3678+ if (ccs_compare_number_union(r->param.signal.sig, &acl->sig)) {
3679+ const int len = acl->domainname->total_len;
3680+ if (!strncmp(acl->domainname->name,
3681+ r->param.signal.dest_pattern, len)) {
3682+ switch (r->param.signal.dest_pattern[len]) {
3683+ case ' ':
3684+ case '\0':
3685+ return true;
3686+ }
3687+ }
3688+ }
3689+ return false;
3690+}
3691+
3692+/**
3693+ * ccs_signal_acl2 - Check permission for signal.
3694+ *
3695+ * @sig: Signal number.
3696+ * @pid: Target's PID.
3697+ *
3698+ * Returns 0 on success, negative value otherwise.
3699+ *
3700+ * Caller holds ccs_read_lock().
3701+ */
3702+static int ccs_signal_acl2(const int sig, const int pid)
3703+{
3704+ struct ccs_request_info r;
3705+ struct ccs_domain_info *dest = NULL;
3706+ const struct ccs_domain_info * const domain = ccs_current_domain();
3707+ if (ccs_init_request_info(&r, CCS_MAC_SIGNAL) == CCS_CONFIG_DISABLED)
3708+ return 0;
3709+ if (!sig)
3710+ return 0; /* No check for NULL signal. */
3711+ r.param_type = CCS_TYPE_SIGNAL_ACL;
3712+ r.param.signal.sig = sig;
3713+ r.param.signal.dest_pattern = domain->domainname->name;
3714+ r.granted = true;
3715+ if (ccs_sys_getpid() == pid) {
3716+ ccs_audit_log(&r);
3717+ return 0; /* No check for self process. */
3718+ }
3719+ { /* Simplified checking. */
3720+ struct task_struct *p = NULL;
3721+ ccs_tasklist_lock();
3722+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3723+ if (pid > 0)
3724+ p = ccsecurity_exports.find_task_by_vpid((pid_t) pid);
3725+ else if (pid == 0)
3726+ p = current;
3727+ else if (pid == -1)
3728+ dest = &ccs_kernel_domain;
3729+ else
3730+ p = ccsecurity_exports.find_task_by_vpid((pid_t) -pid);
3731+#else
3732+ if (pid > 0)
3733+ p = find_task_by_pid((pid_t) pid);
3734+ else if (pid == 0)
3735+ p = current;
3736+ else if (pid == -1)
3737+ dest = &ccs_kernel_domain;
3738+ else
3739+ p = find_task_by_pid((pid_t) -pid);
3740+#endif
3741+ if (p)
3742+ dest = ccs_task_domain(p);
3743+ ccs_tasklist_unlock();
3744+ }
3745+ if (!dest)
3746+ return 0; /* I can't find destinatioin. */
3747+ if (domain == dest) {
3748+ ccs_audit_log(&r);
3749+ return 0; /* No check for self domain. */
3750+ }
3751+ r.param.signal.dest_pattern = dest->domainname->name;
3752+ return ccs_check_acl(&r);
3753+}
3754+
3755+/**
3756+ * ccs_signal_acl - Check permission for signal.
3757+ *
3758+ * @pid: Target's PID.
3759+ * @sig: Signal number.
3760+ *
3761+ * Returns 0 on success, negative value otherwise.
3762+ */
3763+static int ccs_signal_acl(const int pid, const int sig)
3764+{
3765+ int error;
3766+ if (!sig)
3767+ error = 0;
3768+ else {
3769+ const int idx = ccs_read_lock();
3770+ error = ccs_signal_acl2(sig, pid);
3771+ ccs_read_unlock(idx);
3772+ }
3773+ return error;
3774+}
3775+
3776+/**
3777+ * ccs_signal_acl0 - Permission check for signal().
3778+ *
3779+ * @tgid: Unused.
3780+ * @pid: Target's PID.
3781+ * @sig: Signal number.
3782+ *
3783+ * Returns 0 on success, negative value otherwise.
3784+ */
3785+static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig)
3786+{
3787+ return ccs_signal_acl(pid, sig);
3788+}
3789+
3790+#endif
3791+
3792+#ifdef CONFIG_CCSECURITY_MISC
3793+
3794+/**
3795+ * ccs_check_env_acl - Check permission for environment variable's name.
3796+ *
3797+ * @r: Pointer to "struct ccs_request_info".
3798+ * @ptr: Pointer to "struct ccs_acl_info".
3799+ *
3800+ * Returns true if granted, false otherwise.
3801+ */
3802+static bool ccs_check_env_acl(struct ccs_request_info *r,
3803+ const struct ccs_acl_info *ptr)
3804+{
3805+ const struct ccs_env_acl *acl = container_of(ptr, typeof(*acl), head);
3806+ return ccs_path_matches_pattern(r->param.environ.name, acl->env);
3807+}
3808+
3809+/**
3810+ * ccs_env_perm - Check permission for environment variable's name.
3811+ *
3812+ * @r: Pointer to "struct ccs_request_info".
3813+ * @env: The name of environment variable.
3814+ *
3815+ * Returns 0 on success, negative value otherwise.
3816+ *
3817+ * Caller holds ccs_read_lock().
3818+ */
3819+static int ccs_env_perm(struct ccs_request_info *r, const char *env)
3820+{
3821+ struct ccs_path_info environ;
3822+ if (!env || !*env)
3823+ return 0;
3824+ environ.name = env;
3825+ ccs_fill_path_info(&environ);
3826+ r->param_type = CCS_TYPE_ENV_ACL;
3827+ r->param.environ.name = &environ;
3828+ return ccs_check_acl(r);
3829+}
3830+
3831+/**
3832+ * ccs_environ - Check permission for environment variable names.
3833+ *
3834+ * @ee: Pointer to "struct ccs_execve".
3835+ *
3836+ * Returns 0 on success, negative value otherwise.
3837+ */
3838+static int ccs_environ(struct ccs_execve *ee)
3839+{
3840+ struct ccs_request_info *r = &ee->r;
3841+ struct linux_binprm *bprm = ee->bprm;
3842+ /* env_page.data is allocated by ccs_dump_page(). */
3843+ struct ccs_page_dump env_page = { };
3844+ char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
3845+ int arg_len = 0;
3846+ unsigned long pos = bprm->p;
3847+ int offset = pos % PAGE_SIZE;
3848+ int argv_count = bprm->argc;
3849+ int envp_count = bprm->envc;
3850+ /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
3851+ int error = -ENOMEM;
3852+ ee->r.type = CCS_MAC_ENVIRON;
3853+ ee->r.profile = ccs_current_domain()->profile;
3854+ ee->r.mode = ccs_get_mode(ee->r.profile, CCS_MAC_ENVIRON);
3855+ if (!r->mode || !envp_count)
3856+ return 0;
3857+ arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
3858+ if (!arg_ptr)
3859+ goto out;
3860+ while (error == -ENOMEM) {
3861+ if (!ccs_dump_page(bprm, pos, &env_page))
3862+ goto out;
3863+ pos += PAGE_SIZE - offset;
3864+ /* Read. */
3865+ while (argv_count && offset < PAGE_SIZE) {
3866+ if (!env_page.data[offset++])
3867+ argv_count--;
3868+ }
3869+ if (argv_count) {
3870+ offset = 0;
3871+ continue;
3872+ }
3873+ while (offset < PAGE_SIZE) {
3874+ const unsigned char c = env_page.data[offset++];
3875+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
3876+ if (c == '=') {
3877+ arg_ptr[arg_len++] = '\0';
3878+ } else if (c == '\\') {
3879+ arg_ptr[arg_len++] = '\\';
3880+ arg_ptr[arg_len++] = '\\';
3881+ } else if (c > ' ' && c < 127) {
3882+ arg_ptr[arg_len++] = c;
3883+ } else {
3884+ arg_ptr[arg_len++] = '\\';
3885+ arg_ptr[arg_len++] = (c >> 6) + '0';
3886+ arg_ptr[arg_len++]
3887+ = ((c >> 3) & 7) + '0';
3888+ arg_ptr[arg_len++] = (c & 7) + '0';
3889+ }
3890+ } else {
3891+ arg_ptr[arg_len] = '\0';
3892+ }
3893+ if (c)
3894+ continue;
3895+ if (ccs_env_perm(r, arg_ptr)) {
3896+ error = -EPERM;
3897+ break;
3898+ }
3899+ if (!--envp_count) {
3900+ error = 0;
3901+ break;
3902+ }
3903+ arg_len = 0;
3904+ }
3905+ offset = 0;
3906+ }
3907+out:
3908+ if (r->mode != CCS_CONFIG_ENFORCING)
3909+ error = 0;
3910+ kfree(env_page.data);
3911+ kfree(arg_ptr);
3912+ return error;
3913+}
3914+
3915+#endif
3916+
3917+/**
3918+ * ccs_argv - Check argv[] in "struct linux_binbrm".
3919+ *
3920+ * @index: Index number of @arg_ptr.
3921+ * @arg_ptr: Contents of argv[@index].
3922+ * @argc: Length of @argv.
3923+ * @argv: Pointer to "struct ccs_argv".
3924+ * @checked: Set to true if @argv[@index] was found.
3925+ *
3926+ * Returns true on success, false otherwise.
3927+ */
3928+static bool ccs_argv(const unsigned int index, const char *arg_ptr,
3929+ const int argc, const struct ccs_argv *argv,
3930+ u8 *checked)
3931+{
3932+ int i;
3933+ struct ccs_path_info arg;
3934+ arg.name = arg_ptr;
3935+ for (i = 0; i < argc; argv++, checked++, i++) {
3936+ bool result;
3937+ if (index != argv->index)
3938+ continue;
3939+ *checked = 1;
3940+ ccs_fill_path_info(&arg);
3941+ result = ccs_path_matches_pattern(&arg, argv->value);
3942+ if (argv->is_not)
3943+ result = !result;
3944+ if (!result)
3945+ return false;
3946+ }
3947+ return true;
3948+}
3949+
3950+/**
3951+ * ccs_envp - Check envp[] in "struct linux_binbrm".
3952+ *
3953+ * @env_name: The name of environment variable.
3954+ * @env_value: The value of environment variable.
3955+ * @envc: Length of @envp.
3956+ * @envp: Pointer to "struct ccs_envp".
3957+ * @checked: Set to true if @envp[@env_name] was found.
3958+ *
3959+ * Returns true on success, false otherwise.
3960+ */
3961+static bool ccs_envp(const char *env_name, const char *env_value,
3962+ const int envc, const struct ccs_envp *envp,
3963+ u8 *checked)
3964+{
3965+ int i;
3966+ struct ccs_path_info name;
3967+ struct ccs_path_info value;
3968+ name.name = env_name;
3969+ ccs_fill_path_info(&name);
3970+ value.name = env_value;
3971+ ccs_fill_path_info(&value);
3972+ for (i = 0; i < envc; envp++, checked++, i++) {
3973+ bool result;
3974+ if (!ccs_path_matches_pattern(&name, envp->name))
3975+ continue;
3976+ *checked = 1;
3977+ if (envp->value) {
3978+ result = ccs_path_matches_pattern(&value, envp->value);
3979+ if (envp->is_not)
3980+ result = !result;
3981+ } else {
3982+ result = true;
3983+ if (!envp->is_not)
3984+ result = !result;
3985+ }
3986+ if (!result)
3987+ return false;
3988+ }
3989+ return true;
3990+}
3991+
3992+/**
3993+ * ccs_scan_bprm - Scan "struct linux_binprm".
3994+ *
3995+ * @ee: Pointer to "struct ccs_execve".
3996+ * @argc: Length of @argc.
3997+ * @argv: Pointer to "struct ccs_argv".
3998+ * @envc: Length of @envp.
3999+ * @envp: Poiner to "struct ccs_envp".
4000+ *
4001+ * Returns true on success, false otherwise.
4002+ */
4003+static bool ccs_scan_bprm(struct ccs_execve *ee,
4004+ const u16 argc, const struct ccs_argv *argv,
4005+ const u16 envc, const struct ccs_envp *envp)
4006+{
4007+ struct linux_binprm *bprm = ee->bprm;
4008+ struct ccs_page_dump *dump = &ee->dump;
4009+ char *arg_ptr = ee->tmp;
4010+ int arg_len = 0;
4011+ unsigned long pos = bprm->p;
4012+ int offset = pos % PAGE_SIZE;
4013+ int argv_count = bprm->argc;
4014+ int envp_count = bprm->envc;
4015+ bool result = true;
4016+ u8 local_checked[32];
4017+ u8 *checked;
4018+ if (argc + envc <= sizeof(local_checked)) {
4019+ checked = local_checked;
4020+ memset(local_checked, 0, sizeof(local_checked));
4021+ } else {
4022+ checked = kzalloc(argc + envc, CCS_GFP_FLAGS);
4023+ if (!checked)
4024+ return false;
4025+ }
4026+ while (argv_count || envp_count) {
4027+ if (!ccs_dump_page(bprm, pos, dump)) {
4028+ result = false;
4029+ goto out;
4030+ }
4031+ pos += PAGE_SIZE - offset;
4032+ while (offset < PAGE_SIZE) {
4033+ /* Read. */
4034+ const char *kaddr = dump->data;
4035+ const unsigned char c = kaddr[offset++];
4036+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
4037+ if (c == '\\') {
4038+ arg_ptr[arg_len++] = '\\';
4039+ arg_ptr[arg_len++] = '\\';
4040+ } else if (c > ' ' && c < 127) {
4041+ arg_ptr[arg_len++] = c;
4042+ } else {
4043+ arg_ptr[arg_len++] = '\\';
4044+ arg_ptr[arg_len++] = (c >> 6) + '0';
4045+ arg_ptr[arg_len++] =
4046+ ((c >> 3) & 7) + '0';
4047+ arg_ptr[arg_len++] = (c & 7) + '0';
4048+ }
4049+ } else {
4050+ arg_ptr[arg_len] = '\0';
4051+ }
4052+ if (c)
4053+ continue;
4054+ /* Check. */
4055+ if (argv_count) {
4056+ if (!ccs_argv(bprm->argc - argv_count,
4057+ arg_ptr, argc, argv,
4058+ checked)) {
4059+ result = false;
4060+ break;
4061+ }
4062+ argv_count--;
4063+ } else if (envp_count) {
4064+ char *cp = strchr(arg_ptr, '=');
4065+ if (cp) {
4066+ *cp = '\0';
4067+ if (!ccs_envp(arg_ptr, cp + 1,
4068+ envc, envp,
4069+ checked + argc)) {
4070+ result = false;
4071+ break;
4072+ }
4073+ }
4074+ envp_count--;
4075+ } else {
4076+ break;
4077+ }
4078+ arg_len = 0;
4079+ }
4080+ offset = 0;
4081+ if (!result)
4082+ break;
4083+ }
4084+out:
4085+ if (result) {
4086+ int i;
4087+ /* Check not-yet-checked entries. */
4088+ for (i = 0; i < argc; i++) {
4089+ if (checked[i])
4090+ continue;
4091+ /*
4092+ * Return true only if all unchecked indexes in
4093+ * bprm->argv[] are not matched.
4094+ */
4095+ if (argv[i].is_not)
4096+ continue;
4097+ result = false;
4098+ break;
4099+ }
4100+ for (i = 0; i < envc; envp++, i++) {
4101+ if (checked[argc + i])
4102+ continue;
4103+ /*
4104+ * Return true only if all unchecked environ variables
4105+ * in bprm->envp[] are either undefined or not matched.
4106+ */
4107+ if ((!envp->value && !envp->is_not) ||
4108+ (envp->value && envp->is_not))
4109+ continue;
4110+ result = false;
4111+ break;
4112+ }
4113+ }
4114+ if (checked != local_checked)
4115+ kfree(checked);
4116+ return result;
4117+}
4118+
4119+/**
4120+ * ccs_scan_exec_realpath - Check "exec.realpath" parameter of "struct ccs_condition".
4121+ *
4122+ * @file: Pointer to "struct file".
4123+ * @ptr: Pointer to "struct ccs_name_union".
4124+ * @match: True if "exec.realpath=", false if "exec.realpath!=".
4125+ *
4126+ * Returns true on success, false otherwise.
4127+ */
4128+static bool ccs_scan_exec_realpath(struct file *file,
4129+ const struct ccs_name_union *ptr,
4130+ const bool match)
4131+{
4132+ bool result;
4133+ struct ccs_path_info exe;
4134+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
4135+ struct path path;
4136+#endif
4137+ if (!file)
4138+ return false;
4139+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
4140+ exe.name = ccs_realpath(&file->f_path);
4141+#else
4142+ path.mnt = file->f_vfsmnt;
4143+ path.dentry = file->f_dentry;
4144+ exe.name = ccs_realpath(&path);
4145+#endif
4146+ if (!exe.name)
4147+ return false;
4148+ ccs_fill_path_info(&exe);
4149+ result = ccs_compare_name_union(&exe, ptr);
4150+ kfree(exe.name);
4151+ return result == match;
4152+}
4153+
4154+/**
4155+ * ccs_get_attributes - Revalidate "struct inode".
4156+ *
4157+ * @obj: Pointer to "struct ccs_obj_info".
4158+ *
4159+ * Returns nothing.
4160+ */
4161+void ccs_get_attributes(struct ccs_obj_info *obj)
4162+{
4163+ u8 i;
4164+ struct dentry *dentry = NULL;
4165+
4166+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
4167+ struct inode *inode;
4168+ switch (i) {
4169+ case CCS_PATH1:
4170+ dentry = obj->path1.dentry;
4171+ if (!dentry)
4172+ continue;
4173+ break;
4174+ case CCS_PATH2:
4175+ dentry = obj->path2.dentry;
4176+ if (!dentry)
4177+ continue;
4178+ break;
4179+ default:
4180+ if (!dentry)
4181+ continue;
4182+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
4183+ spin_lock(&dcache_lock);
4184+ dentry = dget(dentry->d_parent);
4185+ spin_unlock(&dcache_lock);
4186+#else
4187+ dentry = dget_parent(dentry);
4188+#endif
4189+ break;
4190+ }
4191+ inode = dentry->d_inode;
4192+ if (inode) {
4193+ struct ccs_mini_stat *stat = &obj->stat[i];
4194+ stat->uid = inode->i_uid;
4195+ stat->gid = inode->i_gid;
4196+ stat->ino = inode->i_ino;
4197+ stat->mode = inode->i_mode;
4198+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
4199+ stat->dev = inode->i_dev;
4200+#else
4201+ stat->dev = inode->i_sb->s_dev;
4202+#endif
4203+ stat->rdev = inode->i_rdev;
4204+ obj->stat_valid[i] = true;
4205+ }
4206+ if (i & 1) /* i == CCS_PATH1_PARENT || i == CCS_PATH2_PARENT */
4207+ dput(dentry);
4208+ }
4209+}
4210+
4211+/**
4212+ * ccs_condition - Check condition part.
4213+ *
4214+ * @r: Pointer to "struct ccs_request_info".
4215+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
4216+ *
4217+ * Returns true on success, false otherwise.
4218+ *
4219+ * Caller holds ccs_read_lock().
4220+ */
4221+bool ccs_condition(struct ccs_request_info *r,
4222+ const struct ccs_condition *cond)
4223+{
4224+ const u32 ccs_flags = ccs_current_flags();
4225+ u32 i;
4226+ unsigned long min_v[2] = { 0, 0 };
4227+ unsigned long max_v[2] = { 0, 0 };
4228+ const struct ccs_condition_element *condp;
4229+ const struct ccs_number_union *numbers_p;
4230+ const struct ccs_name_union *names_p;
4231+ const struct ccs_argv *argv;
4232+ const struct ccs_envp *envp;
4233+ struct ccs_obj_info *obj;
4234+ u16 condc;
4235+ u16 argc;
4236+ u16 envc;
4237+ struct linux_binprm *bprm = NULL;
4238+ if (!cond)
4239+ return true;
4240+ condc = cond->condc;
4241+ argc = cond->argc;
4242+ envc = cond->envc;
4243+ obj = r->obj;
4244+ if (r->ee)
4245+ bprm = r->ee->bprm;
4246+ if (!bprm && (argc || envc))
4247+ return false;
4248+ condp = (struct ccs_condition_element *) (cond + 1);
4249+ numbers_p = (const struct ccs_number_union *) (condp + condc);
4250+ names_p = (const struct ccs_name_union *)
4251+ (numbers_p + cond->numbers_count);
4252+ argv = (const struct ccs_argv *) (names_p + cond->names_count);
4253+ envp = (const struct ccs_envp *) (argv + argc);
4254+ for (i = 0; i < condc; i++) {
4255+ const bool match = condp->equals;
4256+ const u8 left = condp->left;
4257+ const u8 right = condp->right;
4258+ bool is_bitop[2] = { false, false };
4259+ u8 j;
4260+ condp++;
4261+ /* Check argv[] and envp[] later. */
4262+ if (left == CCS_ARGV_ENTRY || left == CCS_ENVP_ENTRY)
4263+ continue;
4264+ /* Check string expressions. */
4265+ if (right == CCS_NAME_UNION) {
4266+ const struct ccs_name_union *ptr = names_p++;
4267+ switch (left) {
4268+ struct ccs_path_info *symlink;
4269+ struct ccs_execve *ee;
4270+ struct file *file;
4271+ case CCS_SYMLINK_TARGET:
4272+ symlink = obj ? obj->symlink_target : NULL;
4273+ if (!symlink ||
4274+ !ccs_compare_name_union(symlink, ptr)
4275+ == match)
4276+ goto out;
4277+ break;
4278+ case CCS_EXEC_REALPATH:
4279+ ee = r->ee;
4280+ file = ee ? ee->bprm->file : NULL;
4281+ if (!ccs_scan_exec_realpath(file, ptr, match))
4282+ goto out;
4283+ break;
4284+ }
4285+ continue;
4286+ }
4287+ /* Check numeric or bit-op expressions. */
4288+ for (j = 0; j < 2; j++) {
4289+ const u8 index = j ? right : left;
4290+ unsigned long value = 0;
4291+ switch (index) {
4292+ case CCS_TASK_UID:
4293+ value = from_kuid(&init_user_ns,
4294+ current_uid());
4295+ break;
4296+ case CCS_TASK_EUID:
4297+ value = from_kuid(&init_user_ns,
4298+ current_euid());
4299+ break;
4300+ case CCS_TASK_SUID:
4301+ value = from_kuid(&init_user_ns,
4302+ current_suid());
4303+ break;
4304+ case CCS_TASK_FSUID:
4305+ value = from_kuid(&init_user_ns,
4306+ current_fsuid());
4307+ break;
4308+ case CCS_TASK_GID:
4309+ value = from_kgid(&init_user_ns,
4310+ current_gid());
4311+ break;
4312+ case CCS_TASK_EGID:
4313+ value = from_kgid(&init_user_ns,
4314+ current_egid());
4315+ break;
4316+ case CCS_TASK_SGID:
4317+ value = from_kgid(&init_user_ns,
4318+ current_sgid());
4319+ break;
4320+ case CCS_TASK_FSGID:
4321+ value = from_kgid(&init_user_ns,
4322+ current_fsgid());
4323+ break;
4324+ case CCS_TASK_PID:
4325+ value = ccs_sys_getpid();
4326+ break;
4327+ case CCS_TASK_PPID:
4328+ value = ccs_sys_getppid();
4329+ break;
4330+ case CCS_TYPE_IS_SOCKET:
4331+ value = S_IFSOCK;
4332+ break;
4333+ case CCS_TYPE_IS_SYMLINK:
4334+ value = S_IFLNK;
4335+ break;
4336+ case CCS_TYPE_IS_FILE:
4337+ value = S_IFREG;
4338+ break;
4339+ case CCS_TYPE_IS_BLOCK_DEV:
4340+ value = S_IFBLK;
4341+ break;
4342+ case CCS_TYPE_IS_DIRECTORY:
4343+ value = S_IFDIR;
4344+ break;
4345+ case CCS_TYPE_IS_CHAR_DEV:
4346+ value = S_IFCHR;
4347+ break;
4348+ case CCS_TYPE_IS_FIFO:
4349+ value = S_IFIFO;
4350+ break;
4351+ case CCS_MODE_SETUID:
4352+ value = S_ISUID;
4353+ break;
4354+ case CCS_MODE_SETGID:
4355+ value = S_ISGID;
4356+ break;
4357+ case CCS_MODE_STICKY:
4358+ value = S_ISVTX;
4359+ break;
4360+ case CCS_MODE_OWNER_READ:
4361+ value = S_IRUSR;
4362+ break;
4363+ case CCS_MODE_OWNER_WRITE:
4364+ value = S_IWUSR;
4365+ break;
4366+ case CCS_MODE_OWNER_EXECUTE:
4367+ value = S_IXUSR;
4368+ break;
4369+ case CCS_MODE_GROUP_READ:
4370+ value = S_IRGRP;
4371+ break;
4372+ case CCS_MODE_GROUP_WRITE:
4373+ value = S_IWGRP;
4374+ break;
4375+ case CCS_MODE_GROUP_EXECUTE:
4376+ value = S_IXGRP;
4377+ break;
4378+ case CCS_MODE_OTHERS_READ:
4379+ value = S_IROTH;
4380+ break;
4381+ case CCS_MODE_OTHERS_WRITE:
4382+ value = S_IWOTH;
4383+ break;
4384+ case CCS_MODE_OTHERS_EXECUTE:
4385+ value = S_IXOTH;
4386+ break;
4387+ case CCS_EXEC_ARGC:
4388+ if (!bprm)
4389+ goto out;
4390+ value = bprm->argc;
4391+ break;
4392+ case CCS_EXEC_ENVC:
4393+ if (!bprm)
4394+ goto out;
4395+ value = bprm->envc;
4396+ break;
4397+ case CCS_TASK_TYPE:
4398+ value = ((u8) ccs_flags)
4399+ & CCS_TASK_IS_EXECUTE_HANDLER;
4400+ break;
4401+ case CCS_TASK_EXECUTE_HANDLER:
4402+ value = CCS_TASK_IS_EXECUTE_HANDLER;
4403+ break;
4404+ case CCS_NUMBER_UNION:
4405+ /* Fetch values later. */
4406+ break;
4407+ default:
4408+ if (!obj)
4409+ goto out;
4410+ if (!obj->validate_done) {
4411+ ccs_get_attributes(obj);
4412+ obj->validate_done = true;
4413+ }
4414+ {
4415+ u8 stat_index;
4416+ struct ccs_mini_stat *stat;
4417+ switch (index) {
4418+ case CCS_PATH1_UID:
4419+ case CCS_PATH1_GID:
4420+ case CCS_PATH1_INO:
4421+ case CCS_PATH1_MAJOR:
4422+ case CCS_PATH1_MINOR:
4423+ case CCS_PATH1_TYPE:
4424+ case CCS_PATH1_DEV_MAJOR:
4425+ case CCS_PATH1_DEV_MINOR:
4426+ case CCS_PATH1_PERM:
4427+ stat_index = CCS_PATH1;
4428+ break;
4429+ case CCS_PATH2_UID:
4430+ case CCS_PATH2_GID:
4431+ case CCS_PATH2_INO:
4432+ case CCS_PATH2_MAJOR:
4433+ case CCS_PATH2_MINOR:
4434+ case CCS_PATH2_TYPE:
4435+ case CCS_PATH2_DEV_MAJOR:
4436+ case CCS_PATH2_DEV_MINOR:
4437+ case CCS_PATH2_PERM:
4438+ stat_index = CCS_PATH2;
4439+ break;
4440+ case CCS_PATH1_PARENT_UID:
4441+ case CCS_PATH1_PARENT_GID:
4442+ case CCS_PATH1_PARENT_INO:
4443+ case CCS_PATH1_PARENT_PERM:
4444+ stat_index = CCS_PATH1_PARENT;
4445+ break;
4446+ case CCS_PATH2_PARENT_UID:
4447+ case CCS_PATH2_PARENT_GID:
4448+ case CCS_PATH2_PARENT_INO:
4449+ case CCS_PATH2_PARENT_PERM:
4450+ stat_index = CCS_PATH2_PARENT;
4451+ break;
4452+ default:
4453+ goto out;
4454+ }
4455+ if (!obj->stat_valid[stat_index])
4456+ goto out;
4457+ stat = &obj->stat[stat_index];
4458+ switch (index) {
4459+ case CCS_PATH1_UID:
4460+ case CCS_PATH2_UID:
4461+ case CCS_PATH1_PARENT_UID:
4462+ case CCS_PATH2_PARENT_UID:
4463+ value = from_kuid
4464+ (&init_user_ns,
4465+ stat->uid);
4466+ break;
4467+ case CCS_PATH1_GID:
4468+ case CCS_PATH2_GID:
4469+ case CCS_PATH1_PARENT_GID:
4470+ case CCS_PATH2_PARENT_GID:
4471+ value = from_kgid
4472+ (&init_user_ns,
4473+ stat->gid);
4474+ break;
4475+ case CCS_PATH1_INO:
4476+ case CCS_PATH2_INO:
4477+ case CCS_PATH1_PARENT_INO:
4478+ case CCS_PATH2_PARENT_INO:
4479+ value = stat->ino;
4480+ break;
4481+ case CCS_PATH1_MAJOR:
4482+ case CCS_PATH2_MAJOR:
4483+ value = MAJOR(stat->dev);
4484+ break;
4485+ case CCS_PATH1_MINOR:
4486+ case CCS_PATH2_MINOR:
4487+ value = MINOR(stat->dev);
4488+ break;
4489+ case CCS_PATH1_TYPE:
4490+ case CCS_PATH2_TYPE:
4491+ value = stat->mode & S_IFMT;
4492+ break;
4493+ case CCS_PATH1_DEV_MAJOR:
4494+ case CCS_PATH2_DEV_MAJOR:
4495+ value = MAJOR(stat->rdev);
4496+ break;
4497+ case CCS_PATH1_DEV_MINOR:
4498+ case CCS_PATH2_DEV_MINOR:
4499+ value = MINOR(stat->rdev);
4500+ break;
4501+ case CCS_PATH1_PERM:
4502+ case CCS_PATH2_PERM:
4503+ case CCS_PATH1_PARENT_PERM:
4504+ case CCS_PATH2_PARENT_PERM:
4505+ value = stat->mode & S_IALLUGO;
4506+ break;
4507+ }
4508+ }
4509+ break;
4510+ }
4511+ max_v[j] = value;
4512+ min_v[j] = value;
4513+ switch (index) {
4514+ case CCS_MODE_SETUID:
4515+ case CCS_MODE_SETGID:
4516+ case CCS_MODE_STICKY:
4517+ case CCS_MODE_OWNER_READ:
4518+ case CCS_MODE_OWNER_WRITE:
4519+ case CCS_MODE_OWNER_EXECUTE:
4520+ case CCS_MODE_GROUP_READ:
4521+ case CCS_MODE_GROUP_WRITE:
4522+ case CCS_MODE_GROUP_EXECUTE:
4523+ case CCS_MODE_OTHERS_READ:
4524+ case CCS_MODE_OTHERS_WRITE:
4525+ case CCS_MODE_OTHERS_EXECUTE:
4526+ is_bitop[j] = true;
4527+ }
4528+ }
4529+ if (left == CCS_NUMBER_UNION) {
4530+ /* Fetch values now. */
4531+ const struct ccs_number_union *ptr = numbers_p++;
4532+ min_v[0] = ptr->values[0];
4533+ max_v[0] = ptr->values[1];
4534+ }
4535+ if (right == CCS_NUMBER_UNION) {
4536+ /* Fetch values now. */
4537+ const struct ccs_number_union *ptr = numbers_p++;
4538+ if (ptr->group) {
4539+ if (ccs_number_matches_group(min_v[0],
4540+ max_v[0],
4541+ ptr->group)
4542+ == match)
4543+ continue;
4544+ } else {
4545+ if ((min_v[0] <= ptr->values[1] &&
4546+ max_v[0] >= ptr->values[0]) == match)
4547+ continue;
4548+ }
4549+ goto out;
4550+ }
4551+ /*
4552+ * Bit operation is valid only when counterpart value
4553+ * represents permission.
4554+ */
4555+ if (is_bitop[0] && is_bitop[1]) {
4556+ goto out;
4557+ } else if (is_bitop[0]) {
4558+ switch (right) {
4559+ case CCS_PATH1_PERM:
4560+ case CCS_PATH1_PARENT_PERM:
4561+ case CCS_PATH2_PERM:
4562+ case CCS_PATH2_PARENT_PERM:
4563+ if (!(max_v[0] & max_v[1]) == !match)
4564+ continue;
4565+ }
4566+ goto out;
4567+ } else if (is_bitop[1]) {
4568+ switch (left) {
4569+ case CCS_PATH1_PERM:
4570+ case CCS_PATH1_PARENT_PERM:
4571+ case CCS_PATH2_PERM:
4572+ case CCS_PATH2_PARENT_PERM:
4573+ if (!(max_v[0] & max_v[1]) == !match)
4574+ continue;
4575+ }
4576+ goto out;
4577+ }
4578+ /* Normal value range comparison. */
4579+ if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
4580+ continue;
4581+out:
4582+ return false;
4583+ }
4584+ /* Check argv[] and envp[] now. */
4585+ if (r->ee && (argc || envc))
4586+ return ccs_scan_bprm(r->ee, argc, argv, envc, envp);
4587+ return true;
4588+}
4589+
4590+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4591+
4592+/**
4593+ * ccs_check_task_acl - Check permission for task operation.
4594+ *
4595+ * @r: Pointer to "struct ccs_request_info".
4596+ * @ptr: Pointer to "struct ccs_acl_info".
4597+ *
4598+ * Returns true if granted, false otherwise.
4599+ */
4600+static bool ccs_check_task_acl(struct ccs_request_info *r,
4601+ const struct ccs_acl_info *ptr)
4602+{
4603+ const struct ccs_task_acl *acl = container_of(ptr, typeof(*acl), head);
4604+ return !ccs_pathcmp(r->param.task.domainname, acl->domainname);
4605+}
4606+
4607+#endif
4608+
4609+/**
4610+ * ccs_init_request_info - Initialize "struct ccs_request_info" members.
4611+ *
4612+ * @r: Pointer to "struct ccs_request_info" to initialize.
4613+ * @index: Index number of functionality.
4614+ *
4615+ * Returns mode.
4616+ *
4617+ * "task auto_domain_transition" keyword is evaluated before returning mode for
4618+ * @index. If "task auto_domain_transition" keyword was specified and
4619+ * transition to that domain failed, the current thread will be killed by
4620+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
4621+ */
4622+int ccs_init_request_info(struct ccs_request_info *r, const u8 index)
4623+{
4624+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4625+ u8 i;
4626+ const char *buf;
4627+ for (i = 0; i < 255; i++) {
4628+ const u8 profile = ccs_current_domain()->profile;
4629+ memset(r, 0, sizeof(*r));
4630+ r->profile = profile;
4631+ r->type = index;
4632+ r->mode = ccs_get_mode(profile, index);
4633+ r->param_type = CCS_TYPE_AUTO_TASK_ACL;
4634+ ccs_check_acl(r);
4635+ if (!r->granted)
4636+ return r->mode;
4637+ buf = container_of(r->matched_acl, typeof(struct ccs_task_acl),
4638+ head)->domainname->name;
4639+ if (!ccs_assign_domain(buf, true))
4640+ break;
4641+ }
4642+ ccs_transition_failed(buf);
4643+ return CCS_CONFIG_DISABLED;
4644+#else
4645+ const u8 profile = ccs_current_domain()->profile;
4646+ memset(r, 0, sizeof(*r));
4647+ r->profile = profile;
4648+ r->type = index;
4649+ r->mode = ccs_get_mode(profile, index);
4650+ return r->mode;
4651+#endif
4652+}
4653+
4654+/**
4655+ * ccs_byte_range - Check whether the string is a \ooo style octal value.
4656+ *
4657+ * @str: Pointer to the string.
4658+ *
4659+ * Returns true if @str is a \ooo style octal value, false otherwise.
4660+ */
4661+static bool ccs_byte_range(const char *str)
4662+{
4663+ return *str >= '0' && *str++ <= '3' &&
4664+ *str >= '0' && *str++ <= '7' &&
4665+ *str >= '0' && *str <= '7';
4666+}
4667+
4668+/**
4669+ * ccs_decimal - Check whether the character is a decimal character.
4670+ *
4671+ * @c: The character to check.
4672+ *
4673+ * Returns true if @c is a decimal character, false otherwise.
4674+ */
4675+static bool ccs_decimal(const char c)
4676+{
4677+ return c >= '0' && c <= '9';
4678+}
4679+
4680+/**
4681+ * ccs_hexadecimal - Check whether the character is a hexadecimal character.
4682+ *
4683+ * @c: The character to check.
4684+ *
4685+ * Returns true if @c is a hexadecimal character, false otherwise.
4686+ */
4687+static bool ccs_hexadecimal(const char c)
4688+{
4689+ return (c >= '0' && c <= '9') ||
4690+ (c >= 'A' && c <= 'F') ||
4691+ (c >= 'a' && c <= 'f');
4692+}
4693+
4694+/**
4695+ * ccs_alphabet_char - Check whether the character is an alphabet.
4696+ *
4697+ * @c: The character to check.
4698+ *
4699+ * Returns true if @c is an alphabet character, false otherwise.
4700+ */
4701+static bool ccs_alphabet_char(const char c)
4702+{
4703+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
4704+}
4705+
4706+/**
4707+ * ccs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
4708+ *
4709+ * @filename: The start of string to check.
4710+ * @filename_end: The end of string to check.
4711+ * @pattern: The start of pattern to compare.
4712+ * @pattern_end: The end of pattern to compare.
4713+ *
4714+ * Returns true if @filename matches @pattern, false otherwise.
4715+ */
4716+static bool ccs_file_matches_pattern2(const char *filename,
4717+ const char *filename_end,
4718+ const char *pattern,
4719+ const char *pattern_end)
4720+{
4721+ while (filename < filename_end && pattern < pattern_end) {
4722+ char c;
4723+ if (*pattern != '\\') {
4724+ if (*filename++ != *pattern++)
4725+ return false;
4726+ continue;
4727+ }
4728+ c = *filename;
4729+ pattern++;
4730+ switch (*pattern) {
4731+ int i;
4732+ int j;
4733+ case '?':
4734+ if (c == '/') {
4735+ return false;
4736+ } else if (c == '\\') {
4737+ if (filename[1] == '\\')
4738+ filename++;
4739+ else if (ccs_byte_range(filename + 1))
4740+ filename += 3;
4741+ else
4742+ return false;
4743+ }
4744+ break;
4745+ case '\\':
4746+ if (c != '\\')
4747+ return false;
4748+ if (*++filename != '\\')
4749+ return false;
4750+ break;
4751+ case '+':
4752+ if (!ccs_decimal(c))
4753+ return false;
4754+ break;
4755+ case 'x':
4756+ if (!ccs_hexadecimal(c))
4757+ return false;
4758+ break;
4759+ case 'a':
4760+ if (!ccs_alphabet_char(c))
4761+ return false;
4762+ break;
4763+ case '0':
4764+ case '1':
4765+ case '2':
4766+ case '3':
4767+ if (c == '\\' && ccs_byte_range(filename + 1)
4768+ && !strncmp(filename + 1, pattern, 3)) {
4769+ filename += 3;
4770+ pattern += 2;
4771+ break;
4772+ }
4773+ return false; /* Not matched. */
4774+ case '*':
4775+ case '@':
4776+ for (i = 0; i <= filename_end - filename; i++) {
4777+ if (ccs_file_matches_pattern2(filename + i,
4778+ filename_end,
4779+ pattern + 1,
4780+ pattern_end))
4781+ return true;
4782+ c = filename[i];
4783+ if (c == '.' && *pattern == '@')
4784+ break;
4785+ if (c != '\\')
4786+ continue;
4787+ if (filename[i + 1] == '\\')
4788+ i++;
4789+ else if (ccs_byte_range(filename + i + 1))
4790+ i += 3;
4791+ else
4792+ break; /* Bad pattern. */
4793+ }
4794+ return false; /* Not matched. */
4795+ default:
4796+ j = 0;
4797+ c = *pattern;
4798+ if (c == '$') {
4799+ while (ccs_decimal(filename[j]))
4800+ j++;
4801+ } else if (c == 'X') {
4802+ while (ccs_hexadecimal(filename[j]))
4803+ j++;
4804+ } else if (c == 'A') {
4805+ while (ccs_alphabet_char(filename[j]))
4806+ j++;
4807+ }
4808+ for (i = 1; i <= j; i++) {
4809+ if (ccs_file_matches_pattern2(filename + i,
4810+ filename_end,
4811+ pattern + 1,
4812+ pattern_end))
4813+ return true;
4814+ }
4815+ return false; /* Not matched or bad pattern. */
4816+ }
4817+ filename++;
4818+ pattern++;
4819+ }
4820+ while (*pattern == '\\' &&
4821+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
4822+ pattern += 2;
4823+ return filename == filename_end && pattern == pattern_end;
4824+}
4825+
4826+/**
4827+ * ccs_file_matches_pattern - Pattern matching without '/' character.
4828+ *
4829+ * @filename: The start of string to check.
4830+ * @filename_end: The end of string to check.
4831+ * @pattern: The start of pattern to compare.
4832+ * @pattern_end: The end of pattern to compare.
4833+ *
4834+ * Returns true if @filename matches @pattern, false otherwise.
4835+ */
4836+static bool ccs_file_matches_pattern(const char *filename,
4837+ const char *filename_end,
4838+ const char *pattern,
4839+ const char *pattern_end)
4840+{
4841+ const char *pattern_start = pattern;
4842+ bool first = true;
4843+ bool result;
4844+ while (pattern < pattern_end - 1) {
4845+ /* Split at "\-" pattern. */
4846+ if (*pattern++ != '\\' || *pattern++ != '-')
4847+ continue;
4848+ result = ccs_file_matches_pattern2(filename, filename_end,
4849+ pattern_start, pattern - 2);
4850+ if (first)
4851+ result = !result;
4852+ if (result)
4853+ return false;
4854+ first = false;
4855+ pattern_start = pattern;
4856+ }
4857+ result = ccs_file_matches_pattern2(filename, filename_end,
4858+ pattern_start, pattern_end);
4859+ return first ? result : !result;
4860+}
4861+
4862+/**
4863+ * ccs_path_matches_pattern2 - Do pathname pattern matching.
4864+ *
4865+ * @f: The start of string to check.
4866+ * @p: The start of pattern to compare.
4867+ *
4868+ * Returns true if @f matches @p, false otherwise.
4869+ */
4870+static bool ccs_path_matches_pattern2(const char *f, const char *p)
4871+{
4872+ const char *f_delimiter;
4873+ const char *p_delimiter;
4874+ while (*f && *p) {
4875+ f_delimiter = strchr(f, '/');
4876+ if (!f_delimiter)
4877+ f_delimiter = f + strlen(f);
4878+ p_delimiter = strchr(p, '/');
4879+ if (!p_delimiter)
4880+ p_delimiter = p + strlen(p);
4881+ if (*p == '\\' && *(p + 1) == '{')
4882+ goto recursive;
4883+ if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
4884+ return false;
4885+ f = f_delimiter;
4886+ if (*f)
4887+ f++;
4888+ p = p_delimiter;
4889+ if (*p)
4890+ p++;
4891+ }
4892+ /* Ignore trailing "\*" and "\@" in @pattern. */
4893+ while (*p == '\\' &&
4894+ (*(p + 1) == '*' || *(p + 1) == '@'))
4895+ p += 2;
4896+ return !*f && !*p;
4897+recursive:
4898+ /*
4899+ * The "\{" pattern is permitted only after '/' character.
4900+ * This guarantees that below "*(p - 1)" is safe.
4901+ * Also, the "\}" pattern is permitted only before '/' character
4902+ * so that "\{" + "\}" pair will not break the "\-" operator.
4903+ */
4904+ if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
4905+ *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
4906+ return false; /* Bad pattern. */
4907+ do {
4908+ /* Compare current component with pattern. */
4909+ if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
4910+ p_delimiter - 2))
4911+ break;
4912+ /* Proceed to next component. */
4913+ f = f_delimiter;
4914+ if (!*f)
4915+ break;
4916+ f++;
4917+ /* Continue comparison. */
4918+ if (ccs_path_matches_pattern2(f, p_delimiter + 1))
4919+ return true;
4920+ f_delimiter = strchr(f, '/');
4921+ } while (f_delimiter);
4922+ return false; /* Not matched. */
4923+}
4924+
4925+/**
4926+ * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
4927+ *
4928+ * @filename: The filename to check.
4929+ * @pattern: The pattern to compare.
4930+ *
4931+ * Returns true if matches, false otherwise.
4932+ *
4933+ * The following patterns are available.
4934+ * \\ \ itself.
4935+ * \ooo Octal representation of a byte.
4936+ * \* Zero or more repetitions of characters other than '/'.
4937+ * \@ Zero or more repetitions of characters other than '/' or '.'.
4938+ * \? 1 byte character other than '/'.
4939+ * \$ One or more repetitions of decimal digits.
4940+ * \+ 1 decimal digit.
4941+ * \X One or more repetitions of hexadecimal digits.
4942+ * \x 1 hexadecimal digit.
4943+ * \A One or more repetitions of alphabet characters.
4944+ * \a 1 alphabet character.
4945+ *
4946+ * \- Subtraction operator.
4947+ *
4948+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
4949+ * /dir/dir/dir/ ).
4950+ */
4951+static bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
4952+ const struct ccs_path_info *pattern)
4953+{
4954+ const char *f = filename->name;
4955+ const char *p = pattern->name;
4956+ const int len = pattern->const_len;
4957+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
4958+ if (!pattern->is_patterned)
4959+ return !ccs_pathcmp(filename, pattern);
4960+ /* Don't compare directory and non-directory. */
4961+ if (filename->is_dir != pattern->is_dir)
4962+ return false;
4963+ /* Compare the initial length without patterns. */
4964+ if (strncmp(f, p, len))
4965+ return false;
4966+ f += len;
4967+ p += len;
4968+ return ccs_path_matches_pattern2(f, p);
4969+}
--- tags/patches/1.0.29/config.h (nonexistent)
+++ tags/patches/1.0.29/config.h (revision 431)
@@ -0,0 +1,15 @@
1+#define CONFIG_CCSECURITY_MAX_AUDIT_LOG 1024
2+#define CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY 2048
3+//#define CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
4+#define CONFIG_CCSECURITY_POLICY_LOADER "/sbin/ccs-init"
5+#define CONFIG_CCSECURITY_ACTIVATION_TRIGGER "/sbin/init"
6+//#define CONFIG_AKARI_DEBUG
7+//#define CONFIG_AKARI_TRACE_EXECVE_COUNT
8+#define CONFIG_CCSECURITY_FILE_READDIR
9+#define CONFIG_CCSECURITY_FILE_GETATTR
10+#ifdef CONFIG_SECURITY_NETWORK
11+#define CONFIG_CCSECURITY_NETWORK
12+#endif
13+#define CONFIG_CCSECURITY_MISC
14+#define CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
15+#define CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
--- tags/patches/1.0.29/ccsecurity.h (nonexistent)
+++ tags/patches/1.0.29/ccsecurity.h (revision 431)
@@ -0,0 +1,889 @@
1+/*
2+ * include/linux/ccsecurity.h
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2012/05/05
7+ */
8+
9+#ifndef _LINUX_CCSECURITY_H
10+#define _LINUX_CCSECURITY_H
11+
12+#include <linux/version.h>
13+
14+#ifndef __user
15+#define __user
16+#endif
17+
18+struct nameidata;
19+struct path;
20+struct dentry;
21+struct vfsmount;
22+struct linux_binprm;
23+struct pt_regs;
24+struct file;
25+struct ctl_table;
26+struct socket;
27+struct sockaddr;
28+struct sock;
29+struct sk_buff;
30+struct msghdr;
31+struct pid_namespace;
32+int search_binary_handler(struct linux_binprm *bprm, struct pt_regs *regs);
33+
34+#ifdef CONFIG_CCSECURITY
35+
36+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
37+/* Obtain prototype of __d_path(). */
38+#include <linux/dcache.h>
39+#endif
40+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
41+/* Obtain definition of kuid_t and kgid_t. */
42+#include <linux/uidgid.h>
43+#endif
44+
45+/* For exporting variables and functions. */
46+struct ccsecurity_exports {
47+ void (*load_policy) (const char *filename);
48+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
49+ char * (*d_absolute_path) (const struct path *, char *, int);
50+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
51+ typeof(__d_path) (*__d_path);
52+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
53+ spinlock_t *vfsmount_lock;
54+#endif
55+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
56+ struct task_struct * (*find_task_by_vpid) (pid_t nr);
57+ struct task_struct * (*find_task_by_pid_ns) (pid_t nr,
58+ struct pid_namespace *ns);
59+#endif
60+};
61+
62+/* For doing access control. */
63+struct ccsecurity_operations {
64+ void (*check_profile) (void);
65+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
66+ int (*chroot_permission) (struct path *path);
67+ int (*pivot_root_permission) (struct path *old_path,
68+ struct path *new_path);
69+ int (*mount_permission) (const char *dev_name, struct path *path,
70+ const char *type, unsigned long flags,
71+ void *data_page);
72+#else
73+ int (*chroot_permission) (struct nameidata *nd);
74+ int (*pivot_root_permission) (struct nameidata *old_nd,
75+ struct nameidata *new_nd);
76+ int (*mount_permission) (const char *dev_name, struct nameidata *nd,
77+ const char *type, unsigned long flags,
78+ void *data_page);
79+#endif
80+ int (*umount_permission) (struct vfsmount *mnt, int flags);
81+ _Bool (*lport_reserved) (const u16 port);
82+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
83+ void (*save_open_mode) (int mode);
84+ void (*clear_open_mode) (void);
85+ int (*open_permission) (struct dentry *dentry, struct vfsmount *mnt,
86+ const int flag);
87+#else
88+ int (*open_permission) (struct file *file);
89+#endif
90+ int (*ptrace_permission) (long request, long pid);
91+ int (*ioctl_permission) (struct file *filp, unsigned int cmd,
92+ unsigned long arg);
93+ int (*parse_table) (int __user *name, int nlen, void __user *oldval,
94+ void __user *newval, struct ctl_table *table);
95+ _Bool (*capable) (const u8 operation);
96+ int (*mknod_permission) (struct dentry *dentry, struct vfsmount *mnt,
97+ unsigned int mode, unsigned int dev);
98+ int (*mkdir_permission) (struct dentry *dentry, struct vfsmount *mnt,
99+ unsigned int mode);
100+ int (*rmdir_permission) (struct dentry *dentry, struct vfsmount *mnt);
101+ int (*unlink_permission) (struct dentry *dentry, struct vfsmount *mnt);
102+ int (*symlink_permission) (struct dentry *dentry, struct vfsmount *mnt,
103+ const char *from);
104+ int (*truncate_permission) (struct dentry *dentry,
105+ struct vfsmount *mnt);
106+ int (*rename_permission) (struct dentry *old_dentry,
107+ struct dentry *new_dentry,
108+ struct vfsmount *mnt);
109+ int (*link_permission) (struct dentry *old_dentry,
110+ struct dentry *new_dentry,
111+ struct vfsmount *mnt);
112+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
113+ int (*open_exec_permission) (struct dentry *dentry,
114+ struct vfsmount *mnt);
115+ int (*uselib_permission) (struct dentry *dentry, struct vfsmount *mnt);
116+#endif
117+ int (*fcntl_permission) (struct file *file, unsigned int cmd,
118+ unsigned long arg);
119+ int (*kill_permission) (pid_t pid, int sig);
120+ int (*tgkill_permission) (pid_t tgid, pid_t pid, int sig);
121+ int (*tkill_permission) (pid_t pid, int sig);
122+ int (*socket_create_permission) (int family, int type, int protocol);
123+ int (*socket_listen_permission) (struct socket *sock);
124+ int (*socket_connect_permission) (struct socket *sock,
125+ struct sockaddr *addr, int addr_len);
126+ int (*socket_bind_permission) (struct socket *sock,
127+ struct sockaddr *addr, int addr_len);
128+ int (*socket_post_accept_permission) (struct socket *sock,
129+ struct socket *newsock);
130+ int (*socket_sendmsg_permission) (struct socket *sock,
131+ struct msghdr *msg, int size);
132+ int (*socket_post_recvmsg_permission) (struct sock *sk,
133+ struct sk_buff *skb, int flags);
134+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
135+ int (*chown_permission) (struct dentry *dentry, struct vfsmount *mnt,
136+ kuid_t user, kgid_t group);
137+#else
138+ int (*chown_permission) (struct dentry *dentry, struct vfsmount *mnt,
139+ uid_t user, gid_t group);
140+#endif
141+ int (*chmod_permission) (struct dentry *dentry, struct vfsmount *mnt,
142+ mode_t mode);
143+ int (*getattr_permission) (struct vfsmount *mnt,
144+ struct dentry *dentry);
145+ int (*sigqueue_permission) (pid_t pid, int sig);
146+ int (*tgsigqueue_permission) (pid_t tgid, pid_t pid, int sig);
147+ int (*search_binary_handler) (struct linux_binprm *bprm,
148+ struct pt_regs *regs);
149+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
150+ int (*alloc_task_security) (const struct task_struct *task);
151+ void (*free_task_security) (const struct task_struct *task);
152+#endif
153+ _Bool disabled;
154+};
155+
156+extern struct ccsecurity_operations ccsecurity_ops;
157+
158+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
159+
160+static inline int ccs_chroot_permission(struct path *path)
161+{
162+ int (*func) (struct path *) = ccsecurity_ops.chroot_permission;
163+ return func ? func(path) : 0;
164+}
165+
166+static inline int ccs_pivot_root_permission(struct path *old_path,
167+ struct path *new_path)
168+{
169+ int (*func) (struct path *, struct path *)
170+ = ccsecurity_ops.pivot_root_permission;
171+ return func ? func(old_path, new_path) : 0;
172+}
173+
174+static inline int ccs_mount_permission(const char *dev_name, struct path *path,
175+ const char *type, unsigned long flags,
176+ void *data_page)
177+{
178+ int (*func) (const char *, struct path *, const char *, unsigned long,
179+ void *) = ccsecurity_ops.mount_permission;
180+ return func ? func(dev_name, path, type, flags, data_page) : 0;
181+}
182+
183+#else
184+
185+static inline int ccs_chroot_permission(struct nameidata *nd)
186+{
187+ int (*func) (struct nameidata *) = ccsecurity_ops.chroot_permission;
188+ return func ? func(nd) : 0;
189+}
190+
191+static inline int ccs_pivot_root_permission(struct nameidata *old_nd,
192+ struct nameidata *new_nd)
193+{
194+ int (*func) (struct nameidata *, struct nameidata *)
195+ = ccsecurity_ops.pivot_root_permission;
196+ return func ? func(old_nd, new_nd) : 0;
197+}
198+
199+static inline int ccs_mount_permission(const char *dev_name,
200+ struct nameidata *nd, const char *type,
201+ unsigned long flags, void *data_page)
202+{
203+ int (*func) (const char *, struct nameidata *, const char *,
204+ unsigned long, void *) = ccsecurity_ops.mount_permission;
205+ return func ? func(dev_name, nd, type, flags, data_page) : 0;
206+}
207+
208+#endif
209+
210+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
211+{
212+ int (*func) (struct vfsmount *, int)
213+ = ccsecurity_ops.umount_permission;
214+ return func ? func(mnt, flags) : 0;
215+}
216+
217+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
218+
219+static inline void ccs_save_open_mode(int mode)
220+{
221+ void (*func) (int) = ccsecurity_ops.save_open_mode;
222+ if (func)
223+ func(mode);
224+}
225+
226+static inline void ccs_clear_open_mode(void)
227+{
228+ void (*func) (void) = ccsecurity_ops.clear_open_mode;
229+ if (func)
230+ func();
231+}
232+
233+static inline int ccs_open_permission(struct dentry *dentry,
234+ struct vfsmount *mnt, const int flag)
235+{
236+ int (*func) (struct dentry *, struct vfsmount *, const int)
237+ = ccsecurity_ops.open_permission;
238+ return func ? func(dentry, mnt, flag) : 0;
239+}
240+
241+#else
242+
243+static inline int ccs_open_permission(struct file *filp)
244+{
245+ int (*func) (struct file *) = ccsecurity_ops.open_permission;
246+ return func ? func(filp) : 0;
247+}
248+
249+#endif
250+
251+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
252+ unsigned long arg)
253+{
254+ int (*func) (struct file *, unsigned int, unsigned long)
255+ = ccsecurity_ops.fcntl_permission;
256+ return func ? func(file, cmd, arg) : 0;
257+}
258+
259+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
260+ unsigned long arg)
261+{
262+ int (*func) (struct file *, unsigned int, unsigned long)
263+ = ccsecurity_ops.ioctl_permission;
264+ return func ? func(filp, cmd, arg) : 0;
265+}
266+
267+static inline int ccs_parse_table(int __user *name, int nlen,
268+ void __user *oldval, void __user *newval,
269+ struct ctl_table *table)
270+{
271+ int (*func) (int __user *, int, void __user *, void __user *,
272+ struct ctl_table *) = ccsecurity_ops.parse_table;
273+ return func ? func(name, nlen, oldval, newval, table) : 0;
274+}
275+
276+static inline int ccs_mknod_permission(struct dentry *dentry,
277+ struct vfsmount *mnt, unsigned int mode,
278+ unsigned int dev)
279+{
280+ int (*func) (struct dentry *, struct vfsmount *, unsigned int,
281+ unsigned int) = ccsecurity_ops.mknod_permission;
282+ return func ? func(dentry, mnt, mode, dev) : 0;
283+}
284+
285+static inline int ccs_mkdir_permission(struct dentry *dentry,
286+ struct vfsmount *mnt, unsigned int mode)
287+{
288+ int (*func) (struct dentry *, struct vfsmount *, unsigned int)
289+ = ccsecurity_ops.mkdir_permission;
290+ return func ? func(dentry, mnt, mode) : 0;
291+}
292+
293+static inline int ccs_rmdir_permission(struct dentry *dentry,
294+ struct vfsmount *mnt)
295+{
296+ int (*func) (struct dentry *, struct vfsmount *)
297+ = ccsecurity_ops.rmdir_permission;
298+ return func ? func(dentry, mnt) : 0;
299+}
300+
301+static inline int ccs_unlink_permission(struct dentry *dentry,
302+ struct vfsmount *mnt)
303+{
304+ int (*func) (struct dentry *, struct vfsmount *)
305+ = ccsecurity_ops.unlink_permission;
306+ return func ? func(dentry, mnt) : 0;
307+}
308+
309+static inline int ccs_symlink_permission(struct dentry *dentry,
310+ struct vfsmount *mnt,
311+ const char *from)
312+{
313+ int (*func) (struct dentry *, struct vfsmount *, const char *)
314+ = ccsecurity_ops.symlink_permission;
315+ return func ? func(dentry, mnt, from) : 0;
316+}
317+
318+static inline int ccs_truncate_permission(struct dentry *dentry,
319+ struct vfsmount *mnt)
320+{
321+ int (*func) (struct dentry *, struct vfsmount *)
322+ = ccsecurity_ops.truncate_permission;
323+ return func ? func(dentry, mnt) : 0;
324+}
325+
326+static inline int ccs_rename_permission(struct dentry *old_dentry,
327+ struct dentry *new_dentry,
328+ struct vfsmount *mnt)
329+{
330+ int (*func) (struct dentry *, struct dentry *, struct vfsmount *)
331+ = ccsecurity_ops.rename_permission;
332+ return func ? func(old_dentry, new_dentry, mnt) : 0;
333+}
334+
335+static inline int ccs_link_permission(struct dentry *old_dentry,
336+ struct dentry *new_dentry,
337+ struct vfsmount *mnt)
338+{
339+ int (*func) (struct dentry *, struct dentry *, struct vfsmount *)
340+ = ccsecurity_ops.link_permission;
341+ return func ? func(old_dentry, new_dentry, mnt) : 0;
342+}
343+
344+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
345+
346+static inline int ccs_open_exec_permission(struct dentry *dentry,
347+ struct vfsmount *mnt)
348+{
349+ int (*func) (struct dentry *, struct vfsmount *)
350+ = ccsecurity_ops.open_exec_permission;
351+ return func ? func(dentry, mnt) : 0;
352+}
353+
354+static inline int ccs_uselib_permission(struct dentry *dentry,
355+ struct vfsmount *mnt)
356+{
357+ int (*func) (struct dentry *, struct vfsmount *)
358+ = ccsecurity_ops.uselib_permission;
359+ return func ? func(dentry, mnt) : 0;
360+}
361+
362+#endif
363+
364+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
365+
366+static inline int ccs_chown_permission(struct dentry *dentry,
367+ struct vfsmount *mnt, kuid_t user,
368+ kgid_t group)
369+{
370+ int (*func) (struct dentry *, struct vfsmount *, kuid_t, kgid_t)
371+ = ccsecurity_ops.chown_permission;
372+ return func ? func(dentry, mnt, user, group) : 0;
373+}
374+
375+#else
376+
377+static inline int ccs_chown_permission(struct dentry *dentry,
378+ struct vfsmount *mnt, uid_t user,
379+ gid_t group)
380+{
381+ int (*func) (struct dentry *, struct vfsmount *, uid_t, gid_t)
382+ = ccsecurity_ops.chown_permission;
383+ return func ? func(dentry, mnt, user, group) : 0;
384+}
385+
386+#endif
387+
388+static inline int ccs_chmod_permission(struct dentry *dentry,
389+ struct vfsmount *mnt, mode_t mode)
390+{
391+ int (*func) (struct dentry *, struct vfsmount *, mode_t)
392+ = ccsecurity_ops.chmod_permission;
393+ return func ? func(dentry, mnt, mode) : 0;
394+}
395+
396+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
397+ struct pt_regs *regs)
398+{
399+ return ccsecurity_ops.search_binary_handler(bprm, regs);
400+}
401+
402+#else
403+
404+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
405+
406+static inline int ccs_chroot_permission(struct path *path)
407+{
408+ return 0;
409+}
410+
411+static inline int ccs_pivot_root_permission(struct path *old_path,
412+ struct path *new_path)
413+{
414+ return 0;
415+}
416+
417+static inline int ccs_mount_permission(const char *dev_name, struct path *path,
418+ const char *type, unsigned long flags,
419+ void *data_page)
420+{
421+ return 0;
422+}
423+
424+#else
425+
426+static inline int ccs_chroot_permission(struct nameidata *nd)
427+{
428+ return 0;
429+}
430+
431+static inline int ccs_pivot_root_permission(struct nameidata *old_nd,
432+ struct nameidata *new_nd)
433+{
434+ return 0;
435+}
436+
437+static inline int ccs_mount_permission(const char *dev_name,
438+ struct nameidata *nd, const char *type,
439+ unsigned long flags, void *data_page)
440+{
441+ return 0;
442+}
443+
444+#endif
445+
446+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
447+{
448+ return 0;
449+}
450+
451+static inline void ccs_save_open_mode(int mode)
452+{
453+}
454+
455+static inline void ccs_clear_open_mode(void)
456+{
457+}
458+
459+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
460+
461+static inline int ccs_open_permission(struct dentry *dentry,
462+ struct vfsmount *mnt, const int flag)
463+{
464+ return 0;
465+}
466+
467+#else
468+
469+static inline int ccs_open_permission(struct file *filp)
470+{
471+ return 0;
472+}
473+
474+#endif
475+
476+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
477+ unsigned long arg)
478+{
479+ return 0;
480+}
481+
482+static inline int ccs_parse_table(int __user *name, int nlen,
483+ void __user *oldval, void __user *newval,
484+ struct ctl_table *table)
485+{
486+ return 0;
487+}
488+
489+static inline int ccs_mknod_permission(struct dentry *dentry,
490+ struct vfsmount *mnt, unsigned int mode,
491+ unsigned int dev)
492+{
493+ return 0;
494+}
495+
496+static inline int ccs_mkdir_permission(struct dentry *dentry,
497+ struct vfsmount *mnt, unsigned int mode)
498+{
499+ return 0;
500+}
501+
502+static inline int ccs_rmdir_permission(struct dentry *dentry,
503+ struct vfsmount *mnt)
504+{
505+ return 0;
506+}
507+
508+static inline int ccs_unlink_permission(struct dentry *dentry,
509+ struct vfsmount *mnt)
510+{
511+ return 0;
512+}
513+
514+static inline int ccs_symlink_permission(struct dentry *dentry,
515+ struct vfsmount *mnt,
516+ const char *from)
517+{
518+ return 0;
519+}
520+
521+static inline int ccs_truncate_permission(struct dentry *dentry,
522+ struct vfsmount *mnt)
523+{
524+ return 0;
525+}
526+
527+static inline int ccs_rename_permission(struct dentry *old_dentry,
528+ struct dentry *new_dentry,
529+ struct vfsmount *mnt)
530+{
531+ return 0;
532+}
533+
534+static inline int ccs_link_permission(struct dentry *old_dentry,
535+ struct dentry *new_dentry,
536+ struct vfsmount *mnt)
537+{
538+ return 0;
539+}
540+
541+static inline int ccs_open_exec_permission(struct dentry *dentry,
542+ struct vfsmount *mnt)
543+{
544+ return 0;
545+}
546+
547+static inline int ccs_uselib_permission(struct dentry *dentry,
548+ struct vfsmount *mnt)
549+{
550+ return 0;
551+}
552+
553+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
554+ unsigned long arg)
555+{
556+ return 0;
557+}
558+
559+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
560+
561+static inline int ccs_chown_permission(struct dentry *dentry,
562+ struct vfsmount *mnt, kuid_t user,
563+ kgid_t group)
564+{
565+ return 0;
566+}
567+
568+#else
569+
570+static inline int ccs_chown_permission(struct dentry *dentry,
571+ struct vfsmount *mnt, uid_t user,
572+ gid_t group)
573+{
574+ return 0;
575+}
576+
577+#endif
578+
579+static inline int ccs_chmod_permission(struct dentry *dentry,
580+ struct vfsmount *mnt, mode_t mode)
581+{
582+ return 0;
583+}
584+
585+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
586+ struct pt_regs *regs)
587+{
588+ return search_binary_handler(bprm, regs);
589+}
590+
591+#endif
592+
593+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
594+
595+static inline int ccs_alloc_task_security(const struct task_struct *task)
596+{
597+ int (*func) (const struct task_struct *)
598+ = ccsecurity_ops.alloc_task_security;
599+ return func ? func(task) : 0;
600+}
601+
602+static inline void ccs_free_task_security(const struct task_struct *task)
603+{
604+ void (*func) (const struct task_struct *)
605+ = ccsecurity_ops.free_task_security;
606+ if (func)
607+ func(task);
608+}
609+
610+#else
611+
612+static inline int ccs_alloc_task_security(const struct task_struct *task)
613+{
614+ return 0;
615+}
616+
617+static inline void ccs_free_task_security(const struct task_struct *task)
618+{
619+}
620+
621+#endif
622+
623+#ifdef CONFIG_CCSECURITY_FILE_GETATTR
624+
625+static inline int ccs_getattr_permission(struct vfsmount *mnt,
626+ struct dentry *dentry)
627+{
628+ int (*func) (struct vfsmount *, struct dentry *)
629+ = ccsecurity_ops.getattr_permission;
630+ return func ? func(mnt, dentry) : 0;
631+}
632+
633+#else
634+
635+static inline int ccs_getattr_permission(struct vfsmount *mnt,
636+ struct dentry *dentry)
637+{
638+ return 0;
639+}
640+
641+#endif
642+
643+#ifdef CONFIG_CCSECURITY_NETWORK
644+
645+static inline int ccs_socket_listen_permission(struct socket *sock)
646+{
647+ int (*func) (struct socket *)
648+ = ccsecurity_ops.socket_listen_permission;
649+ return func ? func(sock) : 0;
650+}
651+
652+static inline int ccs_socket_connect_permission(struct socket *sock,
653+ struct sockaddr *addr,
654+ int addr_len)
655+{
656+ int (*func) (struct socket *, struct sockaddr *, int)
657+ = ccsecurity_ops.socket_connect_permission;
658+ return func ? func(sock, addr, addr_len) : 0;
659+}
660+
661+static inline int ccs_socket_bind_permission(struct socket *sock,
662+ struct sockaddr *addr,
663+ int addr_len)
664+{
665+ int (*func) (struct socket *, struct sockaddr *, int)
666+ = ccsecurity_ops.socket_bind_permission;
667+ return func ? func(sock, addr, addr_len) : 0;
668+}
669+
670+static inline int ccs_socket_post_accept_permission(struct socket *sock,
671+ struct socket *newsock)
672+{
673+ int (*func) (struct socket *, struct socket *)
674+ = ccsecurity_ops.socket_post_accept_permission;
675+ return func ? func(sock, newsock) : 0;
676+}
677+
678+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
679+ struct msghdr *msg,
680+ int size)
681+{
682+ int (*func) (struct socket *, struct msghdr *, int)
683+ = ccsecurity_ops.socket_sendmsg_permission;
684+ return func ? func(sock, msg, size) : 0;
685+}
686+
687+#else
688+
689+static inline int ccs_socket_listen_permission(struct socket *sock)
690+{
691+ return 0;
692+}
693+
694+static inline int ccs_socket_connect_permission(struct socket *sock,
695+ struct sockaddr *addr,
696+ int addr_len)
697+{
698+ return 0;
699+}
700+
701+static inline int ccs_socket_bind_permission(struct socket *sock,
702+ struct sockaddr *addr,
703+ int addr_len)
704+{
705+ return 0;
706+}
707+
708+static inline int ccs_socket_post_accept_permission(struct socket *sock,
709+ struct socket *newsock)
710+{
711+ return 0;
712+}
713+
714+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
715+ struct msghdr *msg,
716+ int size)
717+{
718+ return 0;
719+}
720+
721+#endif
722+
723+#ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
724+
725+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
726+ struct sk_buff *skb,
727+ int flags)
728+{
729+ int (*func) (struct sock *, struct sk_buff *, int)
730+ = ccsecurity_ops.socket_post_recvmsg_permission;
731+ return func ? func(sk, skb, flags) : 0;
732+}
733+
734+#else
735+
736+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
737+ struct sk_buff *skb,
738+ int flags)
739+{
740+ return 0;
741+}
742+
743+#endif
744+
745+#ifdef CONFIG_CCSECURITY_PORTRESERVE
746+
747+static inline _Bool ccs_lport_reserved(const u16 port)
748+{
749+ _Bool (*func) (const u16) = ccsecurity_ops.lport_reserved;
750+ return func ? func(port) : 0;
751+}
752+
753+#else
754+
755+static inline _Bool ccs_lport_reserved(const u16 port)
756+{
757+ return 0;
758+}
759+
760+#endif
761+
762+#ifdef CONFIG_CCSECURITY_CAPABILITY
763+
764+static inline _Bool ccs_capable(const u8 operation)
765+{
766+ _Bool (*func) (const u8) = ccsecurity_ops.capable;
767+ return func ? func(operation) : 1;
768+}
769+
770+static inline int ccs_socket_create_permission(int family, int type,
771+ int protocol)
772+{
773+ int (*func) (int, int, int) = ccsecurity_ops.socket_create_permission;
774+ return func ? func(family, type, protocol) : 0;
775+}
776+
777+static inline int ccs_ptrace_permission(long request, long pid)
778+{
779+ int (*func) (long, long) = ccsecurity_ops.ptrace_permission;
780+ return func ? func(request, pid) : 0;
781+}
782+
783+#else
784+
785+static inline _Bool ccs_capable(const u8 operation)
786+{
787+ return 1;
788+}
789+
790+static inline int ccs_socket_create_permission(int family, int type,
791+ int protocol)
792+{
793+ return 0;
794+}
795+
796+static inline int ccs_ptrace_permission(long request, long pid)
797+{
798+ return 0;
799+}
800+
801+#endif
802+
803+#ifdef CONFIG_CCSECURITY_IPC
804+
805+static inline int ccs_kill_permission(pid_t pid, int sig)
806+{
807+ int (*func) (pid_t, int) = ccsecurity_ops.kill_permission;
808+ return func ? func(pid, sig) : 0;
809+}
810+
811+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
812+{
813+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgkill_permission;
814+ return func ? func(tgid, pid, sig) : 0;
815+}
816+
817+static inline int ccs_tkill_permission(pid_t pid, int sig)
818+{
819+ int (*func) (pid_t, int) = ccsecurity_ops.tkill_permission;
820+ return func ? func(pid, sig) : 0;
821+}
822+
823+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
824+{
825+ int (*func) (pid_t, int) = ccsecurity_ops.sigqueue_permission;
826+ return func ? func(pid, sig) : 0;
827+}
828+
829+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
830+{
831+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgsigqueue_permission;
832+ return func ? func(tgid, pid, sig) : 0;
833+}
834+
835+#else
836+
837+static inline int ccs_kill_permission(pid_t pid, int sig)
838+{
839+ return 0;
840+}
841+
842+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
843+{
844+ return 0;
845+}
846+
847+static inline int ccs_tkill_permission(pid_t pid, int sig)
848+{
849+ return 0;
850+}
851+
852+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
853+{
854+ return 0;
855+}
856+
857+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
858+{
859+ return 0;
860+}
861+
862+#endif
863+
864+/* Index numbers for Capability Controls. */
865+enum ccs_capability_acl_index {
866+ /* socket(PF_ROUTE, *, *) */
867+ CCS_USE_ROUTE_SOCKET,
868+ /* socket(PF_PACKET, *, *) */
869+ CCS_USE_PACKET_SOCKET,
870+ /* sys_reboot() */
871+ CCS_SYS_REBOOT,
872+ /* sys_vhangup() */
873+ CCS_SYS_VHANGUP,
874+ /* do_settimeofday(), sys_adjtimex() */
875+ CCS_SYS_SETTIME,
876+ /* sys_nice(), sys_setpriority() */
877+ CCS_SYS_NICE,
878+ /* sys_sethostname(), sys_setdomainname() */
879+ CCS_SYS_SETHOSTNAME,
880+ /* sys_create_module(), sys_init_module(), sys_delete_module() */
881+ CCS_USE_KERNEL_MODULE,
882+ /* sys_kexec_load() */
883+ CCS_SYS_KEXEC_LOAD,
884+ /* sys_ptrace() */
885+ CCS_SYS_PTRACE,
886+ CCS_MAX_CAPABILITY_INDEX
887+};
888+
889+#endif
--- tags/patches/1.0.29/realpath.c (nonexistent)
+++ tags/patches/1.0.29/realpath.c (revision 431)
@@ -0,0 +1,732 @@
1+/*
2+ * security/ccsecurity/realpath.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2012/05/05
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(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(struct path *path, char * const buffer,
35+ 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(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(struct path *path, char * const buffer,
217+ 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(2, 6, 38)
347+ char *pos = ERR_PTR(-ENOMEM);
348+ if (buflen >= 256) {
349+ /* rename_lock is locked/unlocked by dentry_path_raw(). */
350+ pos = dentry_path_raw(dentry, buffer, buflen - 1);
351+ if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
352+ struct inode *inode = dentry->d_inode;
353+ if (inode && S_ISDIR(inode->i_mode)) {
354+ buffer[buflen - 2] = '/';
355+ buffer[buflen - 1] = '\0';
356+ }
357+ }
358+ }
359+ return pos;
360+#else
361+ char *pos = buffer + buflen - 1;
362+ if (buflen < 256)
363+ return ERR_PTR(-ENOMEM);
364+ *pos = '\0';
365+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
366+ *--pos = '/';
367+ spin_lock(&dcache_lock);
368+ while (!IS_ROOT(dentry)) {
369+ struct dentry *parent = dentry->d_parent;
370+ const char *name = dentry->d_name.name;
371+ const int len = dentry->d_name.len;
372+ pos -= len;
373+ if (pos <= buffer) {
374+ pos = ERR_PTR(-ENOMEM);
375+ break;
376+ }
377+ memmove(pos, name, len);
378+ *--pos = '/';
379+ dentry = parent;
380+ }
381+ spin_unlock(&dcache_lock);
382+ return pos;
383+#endif
384+}
385+
386+/**
387+ * ccs_get_local_path - Get the path of a dentry.
388+ *
389+ * @dentry: Pointer to "struct dentry".
390+ * @buffer: Pointer to buffer to return value in.
391+ * @buflen: Sizeof @buffer.
392+ *
393+ * Returns the buffer on success, an error code otherwise.
394+ */
395+static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
396+ const int buflen)
397+{
398+ struct super_block *sb = dentry->d_sb;
399+ char *pos = ccs_get_dentry_path(dentry, buffer, buflen);
400+ if (IS_ERR(pos))
401+ return pos;
402+ /* Convert from $PID to self if $PID is current thread. */
403+ if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
404+ char *ep;
405+ const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
406+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
407+ if (*ep == '/' && pid && pid ==
408+ task_tgid_nr_ns(current, sb->s_fs_info)) {
409+ pos = ep - 5;
410+ if (pos < buffer)
411+ goto out;
412+ memmove(pos, "/self", 5);
413+ }
414+#else
415+ if (*ep == '/' && pid == ccs_sys_getpid()) {
416+ pos = ep - 5;
417+ if (pos < buffer)
418+ goto out;
419+ memmove(pos, "/self", 5);
420+ }
421+#endif
422+ goto prepend_filesystem_name;
423+ }
424+ /* Use filesystem name for unnamed devices. */
425+ if (!MAJOR(sb->s_dev))
426+ goto prepend_filesystem_name;
427+ {
428+ struct inode *inode = sb->s_root->d_inode;
429+ /*
430+ * Use filesystem name if filesystems does not support rename()
431+ * operation.
432+ */
433+ if (inode->i_op && !inode->i_op->rename)
434+ goto prepend_filesystem_name;
435+ }
436+ /* Prepend device name. */
437+ {
438+ char name[64];
439+ int name_len;
440+ const dev_t dev = sb->s_dev;
441+ name[sizeof(name) - 1] = '\0';
442+ snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
443+ MINOR(dev));
444+ name_len = strlen(name);
445+ pos -= name_len;
446+ if (pos < buffer)
447+ goto out;
448+ memmove(pos, name, name_len);
449+ return pos;
450+ }
451+ /* Prepend filesystem name. */
452+prepend_filesystem_name:
453+ {
454+ const char *name = sb->s_type->name;
455+ const int name_len = strlen(name);
456+ pos -= name_len + 1;
457+ if (pos < buffer)
458+ goto out;
459+ memmove(pos, name, name_len);
460+ pos[name_len] = ':';
461+ }
462+ return pos;
463+out:
464+ return ERR_PTR(-ENOMEM);
465+}
466+
467+/**
468+ * ccs_get_socket_name - Get the name of a socket.
469+ *
470+ * @path: Pointer to "struct path".
471+ * @buffer: Pointer to buffer to return value in.
472+ * @buflen: Sizeof @buffer.
473+ *
474+ * Returns the buffer.
475+ */
476+static char *ccs_get_socket_name(struct path *path, char * const buffer,
477+ const int buflen)
478+{
479+ struct inode *inode = path->dentry->d_inode;
480+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
481+ struct sock *sk = sock ? sock->sk : NULL;
482+ if (sk) {
483+ snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
484+ "protocol=%u]", sk->sk_family, sk->sk_type,
485+ sk->sk_protocol);
486+ } else {
487+ snprintf(buffer, buflen, "socket:[unknown]");
488+ }
489+ return buffer;
490+}
491+
492+#define SOCKFS_MAGIC 0x534F434B
493+
494+/**
495+ * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root.
496+ *
497+ * @path: Pointer to "struct path".
498+ *
499+ * Returns the realpath of the given @path on success, NULL otherwise.
500+ *
501+ * This function uses kzalloc(), so caller must kfree() if this function
502+ * didn't return NULL.
503+ */
504+char *ccs_realpath(struct path *path)
505+{
506+ char *buf = NULL;
507+ char *name = NULL;
508+ unsigned int buf_len = PAGE_SIZE / 2;
509+ struct dentry *dentry = path->dentry;
510+ struct super_block *sb;
511+ if (!dentry)
512+ return NULL;
513+ sb = dentry->d_sb;
514+ while (1) {
515+ char *pos;
516+ struct inode *inode;
517+ buf_len <<= 1;
518+ kfree(buf);
519+ buf = kmalloc(buf_len, CCS_GFP_FLAGS);
520+ if (!buf)
521+ break;
522+ /* To make sure that pos is '\0' terminated. */
523+ buf[buf_len - 1] = '\0';
524+ /* Get better name for socket. */
525+ if (sb->s_magic == SOCKFS_MAGIC) {
526+ pos = ccs_get_socket_name(path, buf, buf_len - 1);
527+ goto encode;
528+ }
529+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
530+ /* For "pipe:[\$]". */
531+ if (dentry->d_op && dentry->d_op->d_dname) {
532+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
533+ goto encode;
534+ }
535+#endif
536+ inode = sb->s_root->d_inode;
537+ /*
538+ * Use local name for "filesystems without rename() operation"
539+ * or "path without vfsmount" or "absolute name is unavailable"
540+ * cases.
541+ */
542+ if (!path->mnt || (inode->i_op && !inode->i_op->rename))
543+ pos = ERR_PTR(-EINVAL);
544+ else {
545+ /* Get absolute name for the rest. */
546+ ccs_realpath_lock();
547+ pos = ccs_get_absolute_path(path, buf, buf_len - 1);
548+ ccs_realpath_unlock();
549+ }
550+ if (pos == ERR_PTR(-EINVAL))
551+ pos = ccs_get_local_path(path->dentry, buf,
552+ buf_len - 1);
553+encode:
554+ if (IS_ERR(pos))
555+ continue;
556+ name = ccs_encode(pos);
557+ break;
558+ }
559+ kfree(buf);
560+ if (!name)
561+ ccs_warn_oom(__func__);
562+ return name;
563+}
564+
565+/**
566+ * ccs_encode2 - Encode binary string to ascii string.
567+ *
568+ * @str: String in binary format.
569+ * @str_len: Size of @str in byte.
570+ *
571+ * Returns pointer to @str in ascii format on success, NULL otherwise.
572+ *
573+ * This function uses kzalloc(), so caller must kfree() if this function
574+ * didn't return NULL.
575+ */
576+char *ccs_encode2(const char *str, int str_len)
577+{
578+ int i;
579+ int len = 0;
580+ const char *p = str;
581+ char *cp;
582+ char *cp0;
583+ if (!p)
584+ return NULL;
585+ for (i = 0; i < str_len; i++) {
586+ const unsigned char c = p[i];
587+ if (c == '\\')
588+ len += 2;
589+ else if (c > ' ' && c < 127)
590+ len++;
591+ else
592+ len += 4;
593+ }
594+ len++;
595+ /* Reserve space for appending "/". */
596+ cp = kzalloc(len + 10, CCS_GFP_FLAGS);
597+ if (!cp)
598+ return NULL;
599+ cp0 = cp;
600+ p = str;
601+ for (i = 0; i < str_len; i++) {
602+ const unsigned char c = p[i];
603+ if (c == '\\') {
604+ *cp++ = '\\';
605+ *cp++ = '\\';
606+ } else if (c > ' ' && c < 127) {
607+ *cp++ = c;
608+ } else {
609+ *cp++ = '\\';
610+ *cp++ = (c >> 6) + '0';
611+ *cp++ = ((c >> 3) & 7) + '0';
612+ *cp++ = (c & 7) + '0';
613+ }
614+ }
615+ return cp0;
616+}
617+
618+/**
619+ * ccs_encode - Encode binary string to ascii string.
620+ *
621+ * @str: String in binary format.
622+ *
623+ * Returns pointer to @str in ascii format on success, NULL otherwise.
624+ *
625+ * This function uses kzalloc(), so caller must kfree() if this function
626+ * didn't return NULL.
627+ */
628+char *ccs_encode(const char *str)
629+{
630+ return str ? ccs_encode2(str, strlen(str)) : NULL;
631+}
632+
633+/**
634+ * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
635+ *
636+ * @filename: The string to evaluate.
637+ *
638+ * Returns the initial length without a pattern in @filename.
639+ */
640+static int ccs_const_part_length(const char *filename)
641+{
642+ char c;
643+ int len = 0;
644+ if (!filename)
645+ return 0;
646+ while (1) {
647+ c = *filename++;
648+ if (!c)
649+ break;
650+ if (c != '\\') {
651+ len++;
652+ continue;
653+ }
654+ c = *filename++;
655+ switch (c) {
656+ case '\\': /* "\\" */
657+ len += 2;
658+ continue;
659+ case '0': /* "\ooo" */
660+ case '1':
661+ case '2':
662+ case '3':
663+ c = *filename++;
664+ if (c < '0' || c > '7')
665+ break;
666+ c = *filename++;
667+ if (c < '0' || c > '7')
668+ break;
669+ len += 4;
670+ continue;
671+ }
672+ break;
673+ }
674+ return len;
675+}
676+
677+/**
678+ * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
679+ *
680+ * @ptr: Pointer to "struct ccs_path_info" to fill in.
681+ *
682+ * The caller sets "struct ccs_path_info"->name.
683+ */
684+void ccs_fill_path_info(struct ccs_path_info *ptr)
685+{
686+ const char *name = ptr->name;
687+ const int len = strlen(name);
688+ ptr->total_len = len;
689+ ptr->const_len = ccs_const_part_length(name);
690+ ptr->is_dir = len && (name[len - 1] == '/');
691+ ptr->is_patterned = (ptr->const_len < len);
692+ ptr->hash = full_name_hash(name, len);
693+}
694+
695+/**
696+ * ccs_get_exe - Get ccs_realpath() of current process.
697+ *
698+ * Returns the ccs_realpath() of current process on success, NULL otherwise.
699+ *
700+ * This function uses kzalloc(), so the caller must kfree()
701+ * if this function didn't return NULL.
702+ */
703+const char *ccs_get_exe(void)
704+{
705+ struct mm_struct *mm = current->mm;
706+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
707+ struct vm_area_struct *vma;
708+#endif
709+ const char *cp = NULL;
710+ if (!mm)
711+ return NULL;
712+ down_read(&mm->mmap_sem);
713+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
714+ if (mm->exe_file)
715+ cp = ccs_realpath(&mm->exe_file->f_path);
716+#else
717+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
718+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
719+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
720+ struct path path = { vma->vm_file->f_vfsmnt,
721+ vma->vm_file->f_dentry };
722+ cp = ccs_realpath(&path);
723+#else
724+ cp = ccs_realpath(&vma->vm_file->f_path);
725+#endif
726+ break;
727+ }
728+ }
729+#endif
730+ up_read(&mm->mmap_sem);
731+ return cp;
732+}
--- tags/patches/1.0.29/akari_test.c (nonexistent)
+++ tags/patches/1.0.29/akari_test.c (revision 431)
@@ -0,0 +1,670 @@
1+/*
2+ * akari-test.c
3+ *
4+ * Copyright (C) 2010-2012 Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
5+ */
6+#include <linux/version.h>
7+#include <linux/module.h>
8+#include <linux/init.h>
9+#include <linux/slab.h>
10+#include <linux/security.h>
11+#include <linux/namei.h>
12+#include <linux/mount.h>
13+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
14+#include <linux/fs.h>
15+#include <linux/sched.h>
16+#endif
17+
18+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
19+#error This module supports only 2.6.0 and later kernels.
20+#endif
21+#ifndef CONFIG_SECURITY
22+#error You must choose CONFIG_SECURITY=y for building this module.
23+#endif
24+#ifndef CONFIG_KALLSYMS
25+#error You must choose CONFIG_KALLSYMS=y for building this module.
26+#endif
27+#ifndef CONFIG_PROC_FS
28+#error You must choose CONFIG_PROC_FS=y for building this module.
29+#endif
30+#ifndef CONFIG_MODULES
31+#error You must choose CONFIG_MODULES=y for building this module.
32+#endif
33+
34+#ifndef bool
35+#define bool _Bool
36+#endif
37+#ifndef false
38+#define false 0
39+#endif
40+#ifndef true
41+#define true 1
42+#endif
43+
44+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
45+
46+#include <linux/mount.h>
47+#include <linux/fs_struct.h>
48+
49+/**
50+ * ccs_kernel_read - Wrapper for kernel_read().
51+ *
52+ * @file: Pointer to "struct file".
53+ * @offset: Starting position.
54+ * @addr: Buffer.
55+ * @count: Size of @addr.
56+ *
57+ * Returns return value from kernel_read().
58+ */
59+static int __init ccs_kernel_read(struct file *file, unsigned long offset,
60+ char *addr, unsigned long count)
61+{
62+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
63+ /*
64+ * I can't use kernel_read() because seq_read() returns -EPIPE
65+ * if &pos != &file->f_pos .
66+ */
67+ mm_segment_t old_fs;
68+ unsigned long pos = file->f_pos;
69+ int result;
70+ file->f_pos = offset;
71+ old_fs = get_fs();
72+ set_fs(get_ds());
73+ result = vfs_read(file, (void __user *)addr, count, &file->f_pos);
74+ set_fs(old_fs);
75+ file->f_pos = pos;
76+ return result;
77+#else
78+ return kernel_read(file, offset, addr, count);
79+#endif
80+}
81+
82+/**
83+ * ccs_find_symbol - Find function's address from /proc/kallsyms .
84+ *
85+ * @keyline: Function to find.
86+ *
87+ * Returns address of specified function on success, NULL otherwise.
88+ */
89+static void *__init ccs_find_symbol(const char *keyline)
90+{
91+ struct file *file = NULL;
92+ char *buf;
93+ unsigned long entry = 0;
94+ {
95+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
96+ struct file_system_type *fstype = get_fs_type("proc");
97+ struct vfsmount *mnt = vfs_kern_mount(fstype, 0, "proc", NULL);
98+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
99+ struct file_system_type *fstype = NULL;
100+ struct vfsmount *mnt = do_kern_mount("proc", 0, "proc", NULL);
101+#else
102+ struct file_system_type *fstype = get_fs_type("proc");
103+ struct vfsmount *mnt = kern_mount(fstype);
104+#endif
105+ struct dentry *root;
106+ struct dentry *dentry;
107+ /*
108+ * We embed put_filesystem() here because it is not exported.
109+ */
110+ if (fstype)
111+ module_put(fstype->owner);
112+ if (IS_ERR(mnt))
113+ goto out;
114+ root = dget(mnt->mnt_root);
115+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
116+ mutex_lock(&root->d_inode->i_mutex);
117+ dentry = lookup_one_len("kallsyms", root, 8);
118+ mutex_unlock(&root->d_inode->i_mutex);
119+#else
120+ down(&root->d_inode->i_sem);
121+ dentry = lookup_one_len("kallsyms", root, 8);
122+ up(&root->d_inode->i_sem);
123+#endif
124+ dput(root);
125+ if (IS_ERR(dentry))
126+ mntput(mnt);
127+ else {
128+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
129+ struct path path = { mnt, dentry };
130+ file = dentry_open(&path, O_RDONLY, current_cred());
131+#else
132+ file = dentry_open(dentry, mnt, O_RDONLY
133+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
134+ , current_cred()
135+#endif
136+ );
137+#endif
138+ }
139+ }
140+ if (IS_ERR(file) || !file)
141+ goto out;
142+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
143+ if (buf) {
144+ int len;
145+ int offset = 0;
146+ while ((len = ccs_kernel_read(file, offset, buf,
147+ PAGE_SIZE - 1)) > 0) {
148+ char *cp;
149+ buf[len] = '\0';
150+ cp = strrchr(buf, '\n');
151+ if (!cp)
152+ break;
153+ *(cp + 1) = '\0';
154+ offset += strlen(buf);
155+ cp = strstr(buf, keyline);
156+ if (!cp)
157+ continue;
158+ *cp = '\0';
159+ while (cp > buf && *(cp - 1) != '\n')
160+ cp--;
161+ entry = simple_strtoul(cp, NULL, 16);
162+ break;
163+ }
164+ kfree(buf);
165+ }
166+ filp_close(file, NULL);
167+out:
168+ return (void *) entry;
169+}
170+
171+#endif
172+
173+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
174+static int lsm_addr_calculator(struct file *file);
175+static void * __init ccs_find_security_ops_on_arm(unsigned int *base);
176+#endif
177+
178+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
179+/**
180+ * ccs_find_vfsmount_lock_on_arm - Find vfsmount_lock spinlock on ARM.
181+ *
182+ * @ip: Address of dummy function's entry point.
183+ * @addr: Address of the variable which is used within @function.
184+ * @base: Address of function's entry point.
185+ *
186+ * Returns address of vfsmount_lock on success, NULL otherwise.
187+ */
188+static void * __init ccs_find_vfsmount_lock_on_arm(unsigned int *ip,
189+ unsigned long addr,
190+ unsigned int *base)
191+{
192+ int i;
193+ for (i = 0; i < 32; ip++, i++) {
194+ static unsigned int *ip4ret;
195+ if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr)
196+ continue;
197+ ip = base + i;
198+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
199+ return &ip4ret;
200+ }
201+ return NULL;
202+}
203+#endif
204+
205+/**
206+ * ccs_find_variable - Find variable's address using dummy.
207+ *
208+ * @function: Pointer to dummy function's entry point.
209+ * @addr: Address of the variable which is used within @function.
210+ * @symbol: Name of symbol to resolve.
211+ *
212+ * This trick depends on below assumptions.
213+ *
214+ * (1) @addr is found within 128 bytes from @function, even if additional
215+ * code (e.g. debug symbols) is added.
216+ * (2) It is safe to read 128 bytes from @function.
217+ * (3) @addr != Byte code except @addr.
218+ */
219+static void * __init ccs_find_variable(void *function, unsigned long addr,
220+ const char *symbol)
221+{
222+ int i;
223+ u8 *base;
224+ u8 *cp = function;
225+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
226+ if (*symbol == ' ')
227+ base = ccs_find_symbol(symbol);
228+ else
229+#endif
230+ base = __symbol_get(symbol);
231+ if (!base)
232+ return NULL;
233+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
234+ if (function == lsm_addr_calculator)
235+ return ccs_find_security_ops_on_arm((unsigned int *) base);
236+#endif
237+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
238+ return ccs_find_vfsmount_lock_on_arm(function, addr,
239+ (unsigned int *) base);
240+#endif
241+ /* First, assume absolute adressing mode is used. */
242+ for (i = 0; i < 128; i++) {
243+ if (*(unsigned long *) cp == addr)
244+ return base + i;
245+ cp++;
246+ }
247+ /* Next, assume PC-relative addressing mode is used. */
248+ cp = function;
249+ for (i = 0; i < 128; i++) {
250+ if ((unsigned long) (cp + sizeof(int) + *(int *) cp) == addr) {
251+ static void *cp4ret;
252+ cp = base + i;
253+ cp += sizeof(int) + *(int *) cp;
254+ cp4ret = cp;
255+ return &cp4ret;
256+ }
257+ cp++;
258+ }
259+ cp = function;
260+ for (i = 0; i < 128; i++) {
261+ if ((unsigned long) (long) (*(int *) cp) == addr) {
262+ static void *cp4ret;
263+ cp = base + i;
264+ cp = (void *) (long) (*(int *) cp);
265+ cp4ret = cp;
266+ return &cp4ret;
267+ }
268+ cp++;
269+ }
270+ return NULL;
271+}
272+
273+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
274+
275+/* Never mark this variable as __initdata . */
276+static struct security_operations *ccs_security_ops;
277+
278+/**
279+ * lsm_addr_calculator - Dummy function which does identical to security_file_alloc() in security/security.c.
280+ *
281+ * @file: Pointer to "struct file".
282+ *
283+ * Returns return value from security_file_alloc().
284+ *
285+ * Never mark this function as __init in order to make sure that compiler
286+ * generates identical code for security_file_alloc() and this function.
287+ */
288+static int lsm_addr_calculator(struct file *file)
289+{
290+ return ccs_security_ops->file_alloc_security(file);
291+}
292+
293+#ifdef CONFIG_ARM
294+/**
295+ * ccs_find_security_ops_on_arm - Find security_ops on ARM.
296+ *
297+ * @base: Address of security_file_alloc().
298+ *
299+ * Returns address of security_ops on success, NULL otherwise.
300+ */
301+static void * __init ccs_find_security_ops_on_arm(unsigned int *base)
302+{
303+ static unsigned int *ip4ret;
304+ int i;
305+ const unsigned long addr = (unsigned long) &ccs_security_ops;
306+ unsigned int *ip = (unsigned int *) lsm_addr_calculator;
307+ for (i = 0; i < 32; ip++, i++) {
308+ if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr)
309+ continue;
310+ ip = base + i;
311+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
312+ return &ip4ret;
313+ }
314+ ip = (unsigned int *) lsm_addr_calculator;
315+ for (i = 0; i < 32; ip++, i++) {
316+ /*
317+ * Find
318+ * ldr r3, [pc, #offset1]
319+ * ldr r3, [r3, #offset2]
320+ * sequence.
321+ */
322+ if ((*ip & 0xFFFFF000) != 0xE59F3000 ||
323+ (*(ip + 1) & 0xFFFFF000) != 0xE5933000)
324+ continue;
325+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
326+ ip4ret += (*(ip + 1) & 0xFFF) >> 2;
327+ if ((unsigned long) ip4ret != addr)
328+ continue;
329+ ip = base + i;
330+ ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2)));
331+ ip4ret += (*(ip + 1) & 0xFFF) >> 2;
332+ return &ip4ret;
333+ }
334+ return NULL;
335+}
336+#endif
337+#endif
338+
339+/**
340+ * ccs_find_find_security_ops - Find address of "struct security_operations *security_ops".
341+ *
342+ * Returns pointer to "struct security_operations" on success, NULL otherwise.
343+ */
344+static struct security_operations * __init ccs_find_security_ops(void)
345+{
346+ struct security_operations **ptr;
347+ struct security_operations *ops;
348+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
349+ void *cp;
350+ /* Guess "struct security_operations *security_ops;". */
351+ cp = ccs_find_variable(lsm_addr_calculator, (unsigned long)
352+ &ccs_security_ops, " security_file_alloc\n");
353+ if (!cp) {
354+ printk(KERN_ERR "Can't resolve security_file_alloc().\n");
355+ goto out;
356+ }
357+ /* This should be "struct security_operations *security_ops;". */
358+ ptr = *(struct security_operations ***) cp;
359+#else
360+ /* This is "struct security_operations *security_ops;". */
361+ ptr = (struct security_operations **) __symbol_get("security_ops");
362+#endif
363+ if (!ptr) {
364+ printk(KERN_ERR "Can't resolve security_ops structure.\n");
365+ goto out;
366+ }
367+ printk(KERN_INFO "security_ops=%p\n", ptr);
368+ ops = *ptr;
369+ if (!ops) {
370+ printk(KERN_ERR "No security_operations registered.\n");
371+ goto out;
372+ }
373+ return ops;
374+out:
375+ return NULL;
376+}
377+
378+/**
379+ * ccs_find_find_task_by_pid - Find address of find_task_by_pid().
380+ *
381+ * Returns true on success, false otherwise.
382+ */
383+static bool __init ccs_find_find_task_by_pid(void)
384+{
385+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
386+ void *ptr;
387+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
388+ ptr = ccs_find_symbol(" find_task_by_vpid\n");
389+#else
390+ ptr = __symbol_get("find_task_by_vpid");
391+#endif
392+ if (!ptr) {
393+ printk(KERN_ERR "Can't resolve find_task_by_vpid().\n");
394+ goto out;
395+ }
396+ printk(KERN_INFO "find_task_by_vpid=%p\n", ptr);
397+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
398+ ptr = ccs_find_symbol(" find_task_by_pid_ns\n");
399+#else
400+ ptr = __symbol_get("find_task_by_pid_ns");
401+#endif
402+ if (!ptr) {
403+ printk(KERN_ERR "Can't resolve find_task_by_pid_ns().\n");
404+ goto out;
405+ }
406+ printk(KERN_INFO "find_task_by_pid_ns=%p\n", ptr);
407+ return true;
408+out:
409+ return false;
410+#else
411+ return true;
412+#endif
413+}
414+
415+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
416+
417+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
418+
419+/* Never mark this variable as __initdata . */
420+static spinlock_t ccs_vfsmount_lock __cacheline_aligned_in_smp =
421+SPIN_LOCK_UNLOCKED;
422+
423+static struct list_head *mount_hashtable;
424+static int hash_mask, hash_bits;
425+
426+/**
427+ * hash - Copy of hash() in fs/namespace.c.
428+ *
429+ * @mnt: Pointer to "struct vfsmount".
430+ * @dentry: Pointer to "struct dentry".
431+ *
432+ * Returns hash value.
433+ */
434+static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
435+{
436+ unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
437+ tmp += ((unsigned long) dentry / L1_CACHE_BYTES);
438+ tmp = tmp + (tmp >> hash_bits);
439+ return tmp & hash_mask;
440+}
441+
442+/**
443+ * lsm_lu_mnt - Dummy function which does identical to lookup_mnt() in fs/namespace.c.
444+ *
445+ * @mnt: Pointer to "struct vfsmount".
446+ * @dentry: Pointer to "struct dentry".
447+ *
448+ * Returns pointer to "struct vfsmount".
449+ *
450+ * Never mark this function as __init in order to make sure that compiler
451+ * generates identical code for lookup_mnt() and this function.
452+ */
453+static struct vfsmount *lsm_lu_mnt(struct vfsmount *mnt, struct dentry *dentry)
454+{
455+ struct list_head *head = mount_hashtable + hash(mnt, dentry);
456+ struct list_head *tmp = head;
457+ struct vfsmount *p, *found = NULL;
458+
459+ spin_lock(&ccs_vfsmount_lock);
460+ for (;;) {
461+ tmp = tmp->next;
462+ p = NULL;
463+ if (tmp == head)
464+ break;
465+ p = list_entry(tmp, struct vfsmount, mnt_hash);
466+ if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
467+ found = mntget(p);
468+ break;
469+ }
470+ }
471+ spin_unlock(&ccs_vfsmount_lock);
472+ return found;
473+}
474+
475+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
476+
477+/* Never mark this variable as __initdata . */
478+static spinlock_t ccs_vfsmount_lock;
479+
480+/**
481+ * lsm_flwup - Dummy function which does identical to follow_up() in fs/namei.c.
482+ *
483+ * @mnt: Pointer to "struct vfsmount *".
484+ * @dentry: Pointer to "struct dentry *".
485+ *
486+ * Returns 1 if followed up, 0 otehrwise.
487+ *
488+ * Never mark this function as __init in order to make sure that compiler
489+ * generates identical code for follow_up() and this function.
490+ */
491+static int lsm_flwup(struct vfsmount **mnt, struct dentry **dentry)
492+{
493+ struct vfsmount *parent;
494+ struct dentry *mountpoint;
495+ spin_lock(&ccs_vfsmount_lock);
496+ parent = (*mnt)->mnt_parent;
497+ if (parent == *mnt) {
498+ spin_unlock(&ccs_vfsmount_lock);
499+ return 0;
500+ }
501+ mntget(parent);
502+ mountpoint = dget((*mnt)->mnt_mountpoint);
503+ spin_unlock(&ccs_vfsmount_lock);
504+ dput(*dentry);
505+ *dentry = mountpoint;
506+ mntput(*mnt);
507+ *mnt = parent;
508+ return 1;
509+}
510+
511+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
512+
513+/* Never mark this variable as __initdata . */
514+static spinlock_t ccs_vfsmount_lock;
515+
516+/**
517+ * lsm_pin - Dummy function which does identical to mnt_pin() in fs/namespace.c.
518+ *
519+ * @mnt: Pointer to "struct vfsmount".
520+ *
521+ * Returns nothing.
522+ *
523+ * Never mark this function as __init in order to make sure that compiler
524+ * generates identical code for mnt_pin() and this function.
525+ */
526+static void lsm_pin(struct vfsmount *mnt)
527+{
528+ spin_lock(&ccs_vfsmount_lock);
529+ mnt->mnt_pinned++;
530+ spin_unlock(&ccs_vfsmount_lock);
531+}
532+
533+#endif
534+
535+/**
536+ * ccs_find_vfsmount_lock - Find address of "spinlock_t vfsmount_lock".
537+ *
538+ * Returns true on success, false otherwise.
539+ */
540+static bool __init ccs_find_vfsmount_lock(void)
541+{
542+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
543+ void *cp;
544+ spinlock_t *ptr;
545+ /* Guess "spinlock_t vfsmount_lock;". */
546+ cp = ccs_find_variable(lsm_lu_mnt, (unsigned long) &ccs_vfsmount_lock,
547+ " lookup_mnt\n");
548+ if (!cp) {
549+ printk(KERN_ERR "Can't resolve lookup_mnt().\n");
550+ goto out;
551+ }
552+ /* This should be "spinlock_t *vfsmount_lock;". */
553+ ptr = *(spinlock_t **) cp;
554+ if (!ptr) {
555+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
556+ goto out;
557+ }
558+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
559+ return true;
560+out:
561+ return false;
562+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
563+ void *cp;
564+ spinlock_t *ptr;
565+ /* Guess "spinlock_t vfsmount_lock;". */
566+ cp = ccs_find_variable(lsm_flwup, (unsigned long) &ccs_vfsmount_lock,
567+ "follow_up");
568+ if (!cp) {
569+ printk(KERN_ERR "Can't resolve follow_up().\n");
570+ goto out;
571+ }
572+ /* This should be "spinlock_t *vfsmount_lock;". */
573+ ptr = *(spinlock_t **) cp;
574+ if (!ptr) {
575+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
576+ goto out;
577+ }
578+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
579+ return true;
580+out:
581+ return false;
582+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
583+ void *cp;
584+ spinlock_t *ptr;
585+ /* Guess "spinlock_t vfsmount_lock;". */
586+ cp = ccs_find_variable(lsm_pin, (unsigned long) &ccs_vfsmount_lock,
587+ "mnt_pin");
588+ if (!cp) {
589+ printk(KERN_ERR "Can't resolve mnt_pin().\n");
590+ goto out;
591+ }
592+ /* This should be "spinlock_t *vfsmount_lock;". */
593+ ptr = *(spinlock_t **) cp;
594+ if (!ptr) {
595+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
596+ goto out;
597+ }
598+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
599+ return true;
600+out:
601+ return false;
602+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
603+ void *ptr = ccs_find_symbol(" __d_path\n");
604+ if (!ptr) {
605+ printk(KERN_ERR "Can't resolve __d_path().\n");
606+ return false;
607+ }
608+ printk(KERN_INFO "__d_path=%p\n", ptr);
609+ return true;
610+#else
611+ void *ptr = ccs_find_symbol(" d_absolute_path\n");
612+ if (!ptr) {
613+ printk(KERN_ERR "Can't resolve d_absolute_path().\n");
614+ return false;
615+ }
616+ printk(KERN_INFO "d_absolute_path=%p\n", ptr);
617+ return true;
618+#endif
619+}
620+
621+#else
622+
623+/**
624+ * ccs_find_vfsmount_lock - Find address of "spinlock_t vfsmount_lock".
625+ *
626+ * Returns true on success, false otherwise.
627+ */
628+static bool __init ccs_find_vfsmount_lock(void)
629+{
630+ return true;
631+}
632+
633+#endif
634+
635+/**
636+ * ccs_init - Initialize this module.
637+ *
638+ * Returns 0 on success, -EINVAL otherwise.
639+ */
640+static int __init ccs_init(void)
641+{
642+ if (!ccs_find_security_ops() || !ccs_find_find_task_by_pid() ||
643+ !ccs_find_vfsmount_lock()) {
644+ printk(KERN_INFO "Sorry, I couldn't guess dependent "
645+ "symbols.\n");
646+ printk(KERN_INFO "I need some changes for supporting your "
647+ "environment.\n");
648+ printk(KERN_INFO "Please contact the author.\n");
649+ return -EINVAL;
650+ }
651+ printk(KERN_INFO "All dependent symbols have been guessed.\n");
652+ printk(KERN_INFO "Please verify these addresses using System.map for "
653+ "this kernel (e.g. /boot/System.map-`uname -r` ).\n");
654+ printk(KERN_INFO "If these addresses are correct, you can try loading "
655+ "AKARI module on this kernel.\n");
656+ return 0;
657+}
658+
659+/**
660+ * ccs_exit - Exit this module.
661+ *
662+ * Returns nothing.
663+ */
664+static void ccs_exit(void)
665+{
666+}
667+
668+module_init(ccs_init);
669+module_exit(ccs_exit);
670+MODULE_LICENSE("GPL");
--- tags/patches/1.0.29/policy_io.c (nonexistent)
+++ tags/patches/1.0.29/policy_io.c (revision 431)
@@ -0,0 +1,6436 @@
1+/*
2+ * security/ccsecurity/policy_io.c
3+ *
4+ * Copyright (C) 2005-2012 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.3+ 2012/05/05
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+static const char hex_asc[] = "0123456789abcdef";
998+#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
999+#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
1000+
1001+static inline char *pack_hex_byte(char *buf, u8 byte)
1002+{
1003+ *buf++ = hex_asc_hi(byte);
1004+ *buf++ = hex_asc_lo(byte);
1005+ return buf;
1006+}
1007+#endif
1008+
1009+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1010+static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
1011+{
1012+ return (a->s6_addr32[0] | a->s6_addr32[1] |
1013+ (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
1014+}
1015+#endif
1016+
1017+static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
1018+{
1019+ return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
1020+}
1021+
1022+static char *ip4_string(char *p, const u8 *addr)
1023+{
1024+ /*
1025+ * Since this function is called outside vsnprintf(), I can use
1026+ * sprintf() here.
1027+ */
1028+ return p +
1029+ sprintf(p, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
1030+}
1031+
1032+static char *ip6_compressed_string(char *p, const char *addr)
1033+{
1034+ int i, j, range;
1035+ unsigned char zerolength[8];
1036+ int longest = 1;
1037+ int colonpos = -1;
1038+ u16 word;
1039+ u8 hi, lo;
1040+ bool needcolon = false;
1041+ bool useIPv4;
1042+ struct in6_addr in6;
1043+
1044+ memcpy(&in6, addr, sizeof(struct in6_addr));
1045+
1046+ useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
1047+
1048+ memset(zerolength, 0, sizeof(zerolength));
1049+
1050+ if (useIPv4)
1051+ range = 6;
1052+ else
1053+ range = 8;
1054+
1055+ /* find position of longest 0 run */
1056+ for (i = 0; i < range; i++) {
1057+ for (j = i; j < range; j++) {
1058+ if (in6.s6_addr16[j] != 0)
1059+ break;
1060+ zerolength[i]++;
1061+ }
1062+ }
1063+ for (i = 0; i < range; i++) {
1064+ if (zerolength[i] > longest) {
1065+ longest = zerolength[i];
1066+ colonpos = i;
1067+ }
1068+ }
1069+ if (longest == 1) /* don't compress a single 0 */
1070+ colonpos = -1;
1071+
1072+ /* emit address */
1073+ for (i = 0; i < range; i++) {
1074+ if (i == colonpos) {
1075+ if (needcolon || i == 0)
1076+ *p++ = ':';
1077+ *p++ = ':';
1078+ needcolon = false;
1079+ i += longest - 1;
1080+ continue;
1081+ }
1082+ if (needcolon) {
1083+ *p++ = ':';
1084+ needcolon = false;
1085+ }
1086+ /* hex u16 without leading 0s */
1087+ word = ntohs(in6.s6_addr16[i]);
1088+ hi = word >> 8;
1089+ lo = word & 0xff;
1090+ if (hi) {
1091+ if (hi > 0x0f)
1092+ p = pack_hex_byte(p, hi);
1093+ else
1094+ *p++ = hex_asc_lo(hi);
1095+ p = pack_hex_byte(p, lo);
1096+ } else if (lo > 0x0f)
1097+ p = pack_hex_byte(p, lo);
1098+ else
1099+ *p++ = hex_asc_lo(lo);
1100+ needcolon = true;
1101+ }
1102+
1103+ if (useIPv4) {
1104+ if (needcolon)
1105+ *p++ = ':';
1106+ p = ip4_string(p, &in6.s6_addr[12]);
1107+ }
1108+ *p = '\0';
1109+
1110+ return p;
1111+}
1112+#endif
1113+
1114+/**
1115+ * ccs_print_ipv4 - Print an IPv4 address.
1116+ *
1117+ * @buffer: Buffer to write to.
1118+ * @buffer_len: Size of @buffer.
1119+ * @ip: Pointer to "u32 in network byte order".
1120+ *
1121+ * Returns written length.
1122+ */
1123+static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
1124+ const u32 *ip)
1125+{
1126+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1127+ return snprintf(buffer, buffer_len, "%pI4", ip);
1128+#else
1129+ char addr[sizeof("255.255.255.255")];
1130+ ip4_string(addr, (const u8 *) ip);
1131+ return snprintf(buffer, buffer_len, "%s", addr);
1132+#endif
1133+}
1134+
1135+/**
1136+ * ccs_print_ipv6 - Print an IPv6 address.
1137+ *
1138+ * @buffer: Buffer to write to.
1139+ * @buffer_len: Size of @buffer.
1140+ * @ip: Pointer to "struct in6_addr".
1141+ *
1142+ * Returns written length.
1143+ */
1144+static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
1145+ const struct in6_addr *ip)
1146+{
1147+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1148+ return snprintf(buffer, buffer_len, "%pI6c", ip);
1149+#else
1150+ char addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
1151+ ip6_compressed_string(addr, (const u8 *) ip);
1152+ return snprintf(buffer, buffer_len, "%s", addr);
1153+#endif
1154+}
1155+
1156+/**
1157+ * ccs_print_ip - Print an IP address.
1158+ *
1159+ * @buf: Buffer to write to.
1160+ * @size: Size of @buf.
1161+ * @ptr: Pointer to "struct ipaddr_union".
1162+ *
1163+ * Returns nothing.
1164+ */
1165+static void ccs_print_ip(char *buf, const unsigned int size,
1166+ const struct ccs_ipaddr_union *ptr)
1167+{
1168+ int len;
1169+ if (ptr->is_ipv6)
1170+ len = ccs_print_ipv6(buf, size, &ptr->ip[0]);
1171+ else
1172+ len = ccs_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0]);
1173+ if (!memcmp(&ptr->ip[0], &ptr->ip[1], 16) || len >= size / 2)
1174+ return;
1175+ buf[len++] = '-';
1176+ if (ptr->is_ipv6)
1177+ ccs_print_ipv6(buf + len, size - len, &ptr->ip[1]);
1178+ else
1179+ ccs_print_ipv4(buf + len, size - len,
1180+ &ptr->ip[1].s6_addr32[0]);
1181+}
1182+
1183+#endif
1184+
1185+/***** SECTION5: Variables definition section *****/
1186+
1187+/* Permit policy management by non-root user? */
1188+static bool ccs_manage_by_non_root;
1189+
1190+/* Lock for protecting policy. */
1191+DEFINE_MUTEX(ccs_policy_lock);
1192+
1193+/* Has /sbin/init started? */
1194+bool ccs_policy_loaded;
1195+
1196+/* List of namespaces. */
1197+LIST_HEAD(ccs_namespace_list);
1198+/* True if namespace other than ccs_kernel_namespace is defined. */
1199+static bool ccs_namespace_enabled;
1200+
1201+/* Initial namespace.*/
1202+static struct ccs_policy_namespace ccs_kernel_namespace;
1203+
1204+/* List of "struct ccs_condition". */
1205+LIST_HEAD(ccs_condition_list);
1206+
1207+#ifdef CONFIG_CCSECURITY_PORTRESERVE
1208+/* Bitmap for reserved local port numbers.*/
1209+static u8 ccs_reserved_port_map[8192];
1210+#endif
1211+
1212+/* Wait queue for kernel -> userspace notification. */
1213+static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
1214+/* Wait queue for userspace -> kernel notification. */
1215+static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
1216+
1217+/* The list for "struct ccs_query". */
1218+static LIST_HEAD(ccs_query_list);
1219+
1220+/* Lock for manipulating ccs_query_list. */
1221+static DEFINE_SPINLOCK(ccs_query_list_lock);
1222+
1223+/* Number of "struct file" referring /proc/ccs/query interface. */
1224+static atomic_t ccs_query_observers = ATOMIC_INIT(0);
1225+
1226+/* Wait queue for /proc/ccs/audit. */
1227+static DECLARE_WAIT_QUEUE_HEAD(ccs_log_wait);
1228+
1229+/* The list for "struct ccs_log". */
1230+static LIST_HEAD(ccs_log);
1231+
1232+/* Lock for "struct list_head ccs_log". */
1233+static DEFINE_SPINLOCK(ccs_log_lock);
1234+
1235+/* Length of "stuct list_head ccs_log". */
1236+static unsigned int ccs_log_count;
1237+
1238+/* Timestamp counter for last updated. */
1239+static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
1240+
1241+/* Counter for number of updates. */
1242+static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
1243+
1244+/* Operations for /proc/ccs/self_domain interface. */
1245+static
1246+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1247+const
1248+#endif
1249+struct file_operations ccs_self_operations = {
1250+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
1251+ .write = ccs_write_self,
1252+#endif
1253+ .read = ccs_read_self,
1254+};
1255+
1256+/* Operations for /proc/ccs/ interface. */
1257+static
1258+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1259+const
1260+#endif
1261+struct file_operations ccs_operations = {
1262+ .open = ccs_open,
1263+ .release = ccs_release,
1264+ .poll = ccs_poll,
1265+ .read = ccs_read,
1266+ .write = ccs_write,
1267+};
1268+
1269+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
1270+
1271+/* The inode operations for /proc/ccs/ directory. */
1272+static struct inode_operations ccs_dir_inode_operations;
1273+
1274+/* The inode operations for files under /proc/ccs/ directory. */
1275+static struct inode_operations ccs_file_inode_operations;
1276+
1277+#endif
1278+
1279+/***** SECTION6: Dependent functions section *****/
1280+
1281+/**
1282+ * list_for_each_cookie - iterate over a list with cookie.
1283+ *
1284+ * @pos: Pointer to "struct list_head".
1285+ * @head: Pointer to "struct list_head".
1286+ */
1287+#define list_for_each_cookie(pos, head) \
1288+ for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
1289+ pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
1290+
1291+/**
1292+ * ccs_read_token - Read a word from a line.
1293+ *
1294+ * @param: Pointer to "struct ccs_acl_param".
1295+ *
1296+ * Returns a word on success, "" otherwise.
1297+ *
1298+ * To allow the caller to skip NULL check, this function returns "" rather than
1299+ * NULL if there is no more words to read.
1300+ */
1301+static char *ccs_read_token(struct ccs_acl_param *param)
1302+{
1303+ char *pos = param->data;
1304+ char *del = strchr(pos, ' ');
1305+ if (del)
1306+ *del++ = '\0';
1307+ else
1308+ del = pos + strlen(pos);
1309+ param->data = del;
1310+ return pos;
1311+}
1312+
1313+/**
1314+ * ccs_make_byte - Make byte value from three octal characters.
1315+ *
1316+ * @c1: The first character.
1317+ * @c2: The second character.
1318+ * @c3: The third character.
1319+ *
1320+ * Returns byte value.
1321+ */
1322+static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
1323+{
1324+ return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
1325+}
1326+
1327+/**
1328+ * ccs_correct_word2 - Check whether the given string follows the naming rules.
1329+ *
1330+ * @string: The byte sequence to check. Not '\0'-terminated.
1331+ * @len: Length of @string.
1332+ *
1333+ * Returns true if @string follows the naming rules, false otherwise.
1334+ */
1335+static bool ccs_correct_word2(const char *string, size_t len)
1336+{
1337+ const char *const start = string;
1338+ bool in_repetition = false;
1339+ unsigned char c;
1340+ unsigned char d;
1341+ unsigned char e;
1342+ if (!len)
1343+ goto out;
1344+ while (len--) {
1345+ c = *string++;
1346+ if (c == '\\') {
1347+ if (!len--)
1348+ goto out;
1349+ c = *string++;
1350+ switch (c) {
1351+ case '\\': /* "\\" */
1352+ continue;
1353+ case '$': /* "\$" */
1354+ case '+': /* "\+" */
1355+ case '?': /* "\?" */
1356+ case '*': /* "\*" */
1357+ case '@': /* "\@" */
1358+ case 'x': /* "\x" */
1359+ case 'X': /* "\X" */
1360+ case 'a': /* "\a" */
1361+ case 'A': /* "\A" */
1362+ case '-': /* "\-" */
1363+ continue;
1364+ case '{': /* "/\{" */
1365+ if (string - 3 < start || *(string - 3) != '/')
1366+ break;
1367+ in_repetition = true;
1368+ continue;
1369+ case '}': /* "\}/" */
1370+ if (*string != '/')
1371+ break;
1372+ if (!in_repetition)
1373+ break;
1374+ in_repetition = false;
1375+ continue;
1376+ case '0': /* "\ooo" */
1377+ case '1':
1378+ case '2':
1379+ case '3':
1380+ if (!len-- || !len--)
1381+ break;
1382+ d = *string++;
1383+ e = *string++;
1384+ if (d < '0' || d > '7' || e < '0' || e > '7')
1385+ break;
1386+ c = ccs_make_byte(c, d, e);
1387+ if (c <= ' ' || c >= 127)
1388+ continue;
1389+ }
1390+ goto out;
1391+ } else if (in_repetition && c == '/') {
1392+ goto out;
1393+ } else if (c <= ' ' || c >= 127) {
1394+ goto out;
1395+ }
1396+ }
1397+ if (in_repetition)
1398+ goto out;
1399+ return true;
1400+out:
1401+ return false;
1402+}
1403+
1404+/**
1405+ * ccs_correct_word - Check whether the given string follows the naming rules.
1406+ *
1407+ * @string: The string to check.
1408+ *
1409+ * Returns true if @string follows the naming rules, false otherwise.
1410+ */
1411+static bool ccs_correct_word(const char *string)
1412+{
1413+ return ccs_correct_word2(string, strlen(string));
1414+}
1415+
1416+/**
1417+ * ccs_get_group - Allocate memory for "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group".
1418+ *
1419+ * @param: Pointer to "struct ccs_acl_param".
1420+ * @idx: Index number.
1421+ *
1422+ * Returns pointer to "struct ccs_group" on success, NULL otherwise.
1423+ */
1424+static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
1425+ const u8 idx)
1426+{
1427+ struct ccs_group e = { };
1428+ struct ccs_group *group = NULL;
1429+ struct list_head *list;
1430+ const char *group_name = ccs_read_token(param);
1431+ bool found = false;
1432+ if (!ccs_correct_word(group_name) || idx >= CCS_MAX_GROUP)
1433+ return NULL;
1434+ e.group_name = ccs_get_name(group_name);
1435+ if (!e.group_name)
1436+ return NULL;
1437+ if (mutex_lock_interruptible(&ccs_policy_lock))
1438+ goto out;
1439+ list = &param->ns->group_list[idx];
1440+ list_for_each_entry(group, list, head.list) {
1441+ if (e.group_name != group->group_name ||
1442+ atomic_read(&group->head.users) == CCS_GC_IN_PROGRESS)
1443+ continue;
1444+ atomic_inc(&group->head.users);
1445+ found = true;
1446+ break;
1447+ }
1448+ if (!found) {
1449+ struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
1450+ if (entry) {
1451+ INIT_LIST_HEAD(&entry->member_list);
1452+ atomic_set(&entry->head.users, 1);
1453+ list_add_tail_rcu(&entry->head.list, list);
1454+ group = entry;
1455+ found = true;
1456+ }
1457+ }
1458+ mutex_unlock(&ccs_policy_lock);
1459+out:
1460+ ccs_put_name(e.group_name);
1461+ return found ? group : NULL;
1462+}
1463+
1464+/**
1465+ * ccs_parse_name_union - Parse a ccs_name_union.
1466+ *
1467+ * @param: Pointer to "struct ccs_acl_param".
1468+ * @ptr: Pointer to "struct ccs_name_union".
1469+ *
1470+ * Returns true on success, false otherwise.
1471+ */
1472+static bool ccs_parse_name_union(struct ccs_acl_param *param,
1473+ struct ccs_name_union *ptr)
1474+{
1475+ char *filename;
1476+ if (param->data[0] == '@') {
1477+ param->data++;
1478+ ptr->group = ccs_get_group(param, CCS_PATH_GROUP);
1479+ return ptr->group != NULL;
1480+ }
1481+ filename = ccs_read_token(param);
1482+ if (!ccs_correct_word(filename))
1483+ return false;
1484+ ptr->filename = ccs_get_name(filename);
1485+ return ptr->filename != NULL;
1486+}
1487+
1488+/**
1489+ * ccs_parse_ulong - Parse an "unsigned long" value.
1490+ *
1491+ * @result: Pointer to "unsigned long".
1492+ * @str: Pointer to string to parse.
1493+ *
1494+ * Returns one of values in "enum ccs_value_type".
1495+ *
1496+ * The @src is updated to point the first character after the value
1497+ * on success.
1498+ */
1499+static u8 ccs_parse_ulong(unsigned long *result, char **str)
1500+{
1501+ const char *cp = *str;
1502+ char *ep;
1503+ int base = 10;
1504+ if (*cp == '0') {
1505+ char c = *(cp + 1);
1506+ if (c == 'x' || c == 'X') {
1507+ base = 16;
1508+ cp += 2;
1509+ } else if (c >= '0' && c <= '7') {
1510+ base = 8;
1511+ cp++;
1512+ }
1513+ }
1514+ *result = simple_strtoul(cp, &ep, base);
1515+ if (cp == ep)
1516+ return CCS_VALUE_TYPE_INVALID;
1517+ *str = ep;
1518+ switch (base) {
1519+ case 16:
1520+ return CCS_VALUE_TYPE_HEXADECIMAL;
1521+ case 8:
1522+ return CCS_VALUE_TYPE_OCTAL;
1523+ default:
1524+ return CCS_VALUE_TYPE_DECIMAL;
1525+ }
1526+}
1527+
1528+/**
1529+ * ccs_parse_number_union - Parse a ccs_number_union.
1530+ *
1531+ * @param: Pointer to "struct ccs_acl_param".
1532+ * @ptr: Pointer to "struct ccs_number_union".
1533+ *
1534+ * Returns true on success, false otherwise.
1535+ */
1536+static bool ccs_parse_number_union(struct ccs_acl_param *param,
1537+ struct ccs_number_union *ptr)
1538+{
1539+ char *data;
1540+ u8 type;
1541+ unsigned long v;
1542+ memset(ptr, 0, sizeof(*ptr));
1543+ if (param->data[0] == '@') {
1544+ param->data++;
1545+ ptr->group = ccs_get_group(param, CCS_NUMBER_GROUP);
1546+ return ptr->group != NULL;
1547+ }
1548+ data = ccs_read_token(param);
1549+ type = ccs_parse_ulong(&v, &data);
1550+ if (type == CCS_VALUE_TYPE_INVALID)
1551+ return false;
1552+ ptr->values[0] = v;
1553+ ptr->value_type[0] = type;
1554+ if (!*data) {
1555+ ptr->values[1] = v;
1556+ ptr->value_type[1] = type;
1557+ return true;
1558+ }
1559+ if (*data++ != '-')
1560+ return false;
1561+ type = ccs_parse_ulong(&v, &data);
1562+ if (type == CCS_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
1563+ return false;
1564+ ptr->values[1] = v;
1565+ ptr->value_type[1] = type;
1566+ return true;
1567+}
1568+
1569+#ifdef CONFIG_CCSECURITY_NETWORK
1570+
1571+/**
1572+ * ccs_parse_ipaddr_union - Parse an IP address.
1573+ *
1574+ * @param: Pointer to "struct ccs_acl_param".
1575+ * @ptr: Pointer to "struct ccs_ipaddr_union".
1576+ *
1577+ * Returns true on success, false otherwise.
1578+ */
1579+static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
1580+ struct ccs_ipaddr_union *ptr)
1581+{
1582+ u8 * const min = ptr->ip[0].in6_u.u6_addr8;
1583+ u8 * const max = ptr->ip[1].in6_u.u6_addr8;
1584+ char *address = ccs_read_token(param);
1585+ const char *end;
1586+ if (!strchr(address, ':') &&
1587+ ccs_in4_pton(address, -1, min, '-', &end) > 0) {
1588+ ptr->is_ipv6 = false;
1589+ if (!*end)
1590+ ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
1591+ else if (*end++ != '-' ||
1592+ ccs_in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
1593+ return false;
1594+ return true;
1595+ }
1596+ if (ccs_in6_pton(address, -1, min, '-', &end) > 0) {
1597+ ptr->is_ipv6 = true;
1598+ if (!*end)
1599+ memmove(max, min, sizeof(u16) * 8);
1600+ else if (*end++ != '-' ||
1601+ ccs_in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
1602+ return false;
1603+ return true;
1604+ }
1605+ return false;
1606+}
1607+
1608+#endif
1609+
1610+/**
1611+ * ccs_get_dqword - ccs_get_name() for a quoted string.
1612+ *
1613+ * @start: String to save.
1614+ *
1615+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
1616+ */
1617+static const struct ccs_path_info *ccs_get_dqword(char *start)
1618+{
1619+ char *cp = start + strlen(start) - 1;
1620+ if (cp == start || *start++ != '"' || *cp != '"')
1621+ return NULL;
1622+ *cp = '\0';
1623+ if (*start && !ccs_correct_word(start))
1624+ return NULL;
1625+ return ccs_get_name(start);
1626+}
1627+
1628+/**
1629+ * ccs_parse_name_union_quoted - Parse a quoted word.
1630+ *
1631+ * @param: Pointer to "struct ccs_acl_param".
1632+ * @ptr: Pointer to "struct ccs_name_union".
1633+ *
1634+ * Returns true on success, false otherwise.
1635+ */
1636+static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
1637+ struct ccs_name_union *ptr)
1638+{
1639+ char *filename = param->data;
1640+ if (*filename == '@')
1641+ return ccs_parse_name_union(param, ptr);
1642+ ptr->filename = ccs_get_dqword(filename);
1643+ return ptr->filename != NULL;
1644+}
1645+
1646+/**
1647+ * ccs_parse_argv - Parse an argv[] condition part.
1648+ *
1649+ * @left: Lefthand value.
1650+ * @right: Righthand value.
1651+ * @argv: Pointer to "struct ccs_argv".
1652+ *
1653+ * Returns true on success, false otherwise.
1654+ */
1655+static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv)
1656+{
1657+ if (ccs_parse_ulong(&argv->index, &left) != CCS_VALUE_TYPE_DECIMAL ||
1658+ *left++ != ']' || *left)
1659+ return false;
1660+ argv->value = ccs_get_dqword(right);
1661+ return argv->value != NULL;
1662+}
1663+
1664+/**
1665+ * ccs_parse_envp - Parse an envp[] condition part.
1666+ *
1667+ * @left: Lefthand value.
1668+ * @right: Righthand value.
1669+ * @envp: Pointer to "struct ccs_envp".
1670+ *
1671+ * Returns true on success, false otherwise.
1672+ */
1673+static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp)
1674+{
1675+ const struct ccs_path_info *name;
1676+ const struct ccs_path_info *value;
1677+ char *cp = left + strlen(left) - 1;
1678+ if (*cp-- != ']' || *cp != '"')
1679+ goto out;
1680+ *cp = '\0';
1681+ if (!ccs_correct_word(left))
1682+ goto out;
1683+ name = ccs_get_name(left);
1684+ if (!name)
1685+ goto out;
1686+ if (!strcmp(right, "NULL")) {
1687+ value = NULL;
1688+ } else {
1689+ value = ccs_get_dqword(right);
1690+ if (!value) {
1691+ ccs_put_name(name);
1692+ goto out;
1693+ }
1694+ }
1695+ envp->name = name;
1696+ envp->value = value;
1697+ return true;
1698+out:
1699+ return false;
1700+}
1701+
1702+/**
1703+ * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
1704+ *
1705+ * @a: Pointer to "struct ccs_condition".
1706+ * @b: Pointer to "struct ccs_condition".
1707+ *
1708+ * Returns true if @a == @b, false otherwise.
1709+ */
1710+static bool ccs_same_condition(const struct ccs_condition *a,
1711+ const struct ccs_condition *b)
1712+{
1713+ return a->size == b->size && a->condc == b->condc &&
1714+ a->numbers_count == b->numbers_count &&
1715+ a->names_count == b->names_count &&
1716+ a->argc == b->argc && a->envc == b->envc &&
1717+ a->grant_log == b->grant_log &&
1718+ a->exec_transit == b->exec_transit && a->transit == b->transit
1719+ && !memcmp(a + 1, b + 1, a->size - sizeof(*a));
1720+}
1721+
1722+/**
1723+ * ccs_condition_type - Get condition type.
1724+ *
1725+ * @word: Keyword string.
1726+ *
1727+ * Returns one of values in "enum ccs_conditions_index" on success,
1728+ * CCS_MAX_CONDITION_KEYWORD otherwise.
1729+ */
1730+static u8 ccs_condition_type(const char *word)
1731+{
1732+ u8 i;
1733+ for (i = 0; i < CCS_MAX_CONDITION_KEYWORD; i++) {
1734+ if (!strcmp(word, ccs_condition_keyword[i]))
1735+ break;
1736+ }
1737+ return i;
1738+}
1739+
1740+/**
1741+ * ccs_commit_condition - Commit "struct ccs_condition".
1742+ *
1743+ * @entry: Pointer to "struct ccs_condition".
1744+ *
1745+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1746+ *
1747+ * This function merges duplicated entries. This function returns NULL if
1748+ * @entry is not duplicated but memory quota for policy has exceeded.
1749+ */
1750+static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
1751+{
1752+ struct ccs_condition *ptr;
1753+ bool found = false;
1754+ if (mutex_lock_interruptible(&ccs_policy_lock)) {
1755+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
1756+ ptr = NULL;
1757+ found = true;
1758+ goto out;
1759+ }
1760+ list_for_each_entry(ptr, &ccs_condition_list, head.list) {
1761+ if (!ccs_same_condition(ptr, entry) ||
1762+ atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
1763+ continue;
1764+ /* Same entry found. Share this entry. */
1765+ atomic_inc(&ptr->head.users);
1766+ found = true;
1767+ break;
1768+ }
1769+ if (!found) {
1770+ if (ccs_memory_ok(entry, entry->size)) {
1771+ atomic_set(&entry->head.users, 1);
1772+ list_add(&entry->head.list, &ccs_condition_list);
1773+ } else {
1774+ found = true;
1775+ ptr = NULL;
1776+ }
1777+ }
1778+ mutex_unlock(&ccs_policy_lock);
1779+out:
1780+ if (found) {
1781+ ccs_del_condition(&entry->head.list);
1782+ kfree(entry);
1783+ entry = ptr;
1784+ }
1785+ return entry;
1786+}
1787+
1788+/**
1789+ * ccs_correct_path - Check whether the given pathname follows the naming rules.
1790+ *
1791+ * @filename: The pathname to check.
1792+ *
1793+ * Returns true if @filename follows the naming rules, false otherwise.
1794+ */
1795+static bool ccs_correct_path(const char *filename)
1796+{
1797+ return *filename == '/' && ccs_correct_word(filename);
1798+}
1799+
1800+/**
1801+ * ccs_domain_def - Check whether the given token can be a domainname.
1802+ *
1803+ * @buffer: The token to check.
1804+ *
1805+ * Returns true if @buffer possibly be a domainname, false otherwise.
1806+ */
1807+static bool ccs_domain_def(const unsigned char *buffer)
1808+{
1809+ const unsigned char *cp;
1810+ int len;
1811+ if (*buffer != '<')
1812+ return false;
1813+ cp = strchr(buffer, ' ');
1814+ if (!cp)
1815+ len = strlen(buffer);
1816+ else
1817+ len = cp - buffer;
1818+ if (buffer[len - 1] != '>' || !ccs_correct_word2(buffer + 1, len - 2))
1819+ return false;
1820+ return true;
1821+}
1822+
1823+/**
1824+ * ccs_correct_domain - Check whether the given domainname follows the naming rules.
1825+ *
1826+ * @domainname: The domainname to check.
1827+ *
1828+ * Returns true if @domainname follows the naming rules, false otherwise.
1829+ */
1830+static bool ccs_correct_domain(const unsigned char *domainname)
1831+{
1832+ if (!domainname || !ccs_domain_def(domainname))
1833+ return false;
1834+ domainname = strchr(domainname, ' ');
1835+ if (!domainname++)
1836+ return true;
1837+ while (1) {
1838+ const unsigned char *cp = strchr(domainname, ' ');
1839+ if (!cp)
1840+ break;
1841+ if (*domainname != '/' ||
1842+ !ccs_correct_word2(domainname, cp - domainname))
1843+ return false;
1844+ domainname = cp + 1;
1845+ }
1846+ return ccs_correct_path(domainname);
1847+}
1848+
1849+/**
1850+ * ccs_normalize_line - Format string.
1851+ *
1852+ * @buffer: The line to normalize.
1853+ *
1854+ * Returns nothing.
1855+ *
1856+ * Leading and trailing whitespaces are removed.
1857+ * Multiple whitespaces are packed into single space.
1858+ */
1859+static void ccs_normalize_line(unsigned char *buffer)
1860+{
1861+ unsigned char *sp = buffer;
1862+ unsigned char *dp = buffer;
1863+ bool first = true;
1864+ while (*sp && (*sp <= ' ' || *sp >= 127))
1865+ sp++;
1866+ while (*sp) {
1867+ if (!first)
1868+ *dp++ = ' ';
1869+ first = false;
1870+ while (*sp > ' ' && *sp < 127)
1871+ *dp++ = *sp++;
1872+ while (*sp && (*sp <= ' ' || *sp >= 127))
1873+ sp++;
1874+ }
1875+ *dp = '\0';
1876+}
1877+
1878+/**
1879+ * ccs_get_domainname - Read a domainname from a line.
1880+ *
1881+ * @param: Pointer to "struct ccs_acl_param".
1882+ *
1883+ * Returns a domainname on success, NULL otherwise.
1884+ */
1885+static const struct ccs_path_info *ccs_get_domainname
1886+(struct ccs_acl_param *param)
1887+{
1888+ char *start = param->data;
1889+ char *pos = start;
1890+ while (*pos) {
1891+ if (*pos++ != ' ' || *pos++ == '/')
1892+ continue;
1893+ pos -= 2;
1894+ *pos++ = '\0';
1895+ break;
1896+ }
1897+ param->data = pos;
1898+ if (ccs_correct_domain(start))
1899+ return ccs_get_name(start);
1900+ return NULL;
1901+}
1902+
1903+/**
1904+ * ccs_get_transit_preference - Parse domain transition preference for execve().
1905+ *
1906+ * @param: Pointer to "struct ccs_acl_param".
1907+ * @e: Pointer to "struct ccs_condition".
1908+ *
1909+ * Returns the condition string part.
1910+ */
1911+static char *ccs_get_transit_preference(struct ccs_acl_param *param,
1912+ struct ccs_condition *e)
1913+{
1914+ char * const pos = param->data;
1915+ bool flag;
1916+ if (*pos == '<') {
1917+ e->transit = ccs_get_domainname(param);
1918+ goto done;
1919+ }
1920+ {
1921+ char *cp = strchr(pos, ' ');
1922+ if (cp)
1923+ *cp = '\0';
1924+ flag = ccs_correct_path(pos) || !strcmp(pos, "keep") ||
1925+ !strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
1926+ !strcmp(pos, "child") || !strcmp(pos, "parent");
1927+ if (cp)
1928+ *cp = ' ';
1929+ }
1930+ if (!flag)
1931+ return pos;
1932+ e->transit = ccs_get_name(ccs_read_token(param));
1933+done:
1934+ if (e->transit) {
1935+ e->exec_transit = true;
1936+ return param->data;
1937+ }
1938+ /*
1939+ * Return a bad read-only condition string that will let
1940+ * ccs_get_condition() return NULL.
1941+ */
1942+ return "/";
1943+}
1944+
1945+/**
1946+ * ccs_get_condition - Parse condition part.
1947+ *
1948+ * @param: Pointer to "struct ccs_acl_param".
1949+ *
1950+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1951+ */
1952+struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param)
1953+{
1954+ struct ccs_condition *entry = NULL;
1955+ struct ccs_condition_element *condp = NULL;
1956+ struct ccs_number_union *numbers_p = NULL;
1957+ struct ccs_name_union *names_p = NULL;
1958+ struct ccs_argv *argv = NULL;
1959+ struct ccs_envp *envp = NULL;
1960+ struct ccs_condition e = { };
1961+ char * const start_of_string = ccs_get_transit_preference(param, &e);
1962+ char * const end_of_string = start_of_string + strlen(start_of_string);
1963+ char *pos;
1964+rerun:
1965+ pos = start_of_string;
1966+ while (1) {
1967+ u8 left = -1;
1968+ u8 right = -1;
1969+ char *left_word = pos;
1970+ char *cp;
1971+ char *right_word;
1972+ bool is_not;
1973+ if (!*left_word)
1974+ break;
1975+ /*
1976+ * Since left-hand condition does not allow use of "path_group"
1977+ * or "number_group" and environment variable's names do not
1978+ * accept '=', it is guaranteed that the original line consists
1979+ * of one or more repetition of $left$operator$right blocks
1980+ * where "$left is free from '=' and ' '" and "$operator is
1981+ * either '=' or '!='" and "$right is free from ' '".
1982+ * Therefore, we can reconstruct the original line at the end
1983+ * of dry run even if we overwrite $operator with '\0'.
1984+ */
1985+ cp = strchr(pos, ' ');
1986+ if (cp) {
1987+ *cp = '\0'; /* Will restore later. */
1988+ pos = cp + 1;
1989+ } else {
1990+ pos = "";
1991+ }
1992+ right_word = strchr(left_word, '=');
1993+ if (!right_word || right_word == left_word)
1994+ goto out;
1995+ is_not = *(right_word - 1) == '!';
1996+ if (is_not)
1997+ *(right_word++ - 1) = '\0'; /* Will restore later. */
1998+ else if (*(right_word + 1) != '=')
1999+ *right_word++ = '\0'; /* Will restore later. */
2000+ else
2001+ goto out;
2002+ dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
2003+ is_not ? "!" : "", right_word);
2004+ if (!strcmp(left_word, "grant_log")) {
2005+ if (entry) {
2006+ if (is_not ||
2007+ entry->grant_log != CCS_GRANTLOG_AUTO)
2008+ goto out;
2009+ else if (!strcmp(right_word, "yes"))
2010+ entry->grant_log = CCS_GRANTLOG_YES;
2011+ else if (!strcmp(right_word, "no"))
2012+ entry->grant_log = CCS_GRANTLOG_NO;
2013+ else
2014+ goto out;
2015+ }
2016+ continue;
2017+ }
2018+ if (!strcmp(left_word, "auto_domain_transition")) {
2019+ if (entry) {
2020+ if (is_not || entry->transit)
2021+ goto out;
2022+ entry->transit = ccs_get_dqword(right_word);
2023+ if (!entry->transit ||
2024+ (entry->transit->name[0] != '/' &&
2025+ !ccs_domain_def(entry->transit->name)))
2026+ goto out;
2027+ }
2028+ continue;
2029+ }
2030+ if (!strncmp(left_word, "exec.argv[", 10)) {
2031+ if (!argv) {
2032+ e.argc++;
2033+ e.condc++;
2034+ } else {
2035+ e.argc--;
2036+ e.condc--;
2037+ left = CCS_ARGV_ENTRY;
2038+ argv->is_not = is_not;
2039+ if (!ccs_parse_argv(left_word + 10,
2040+ right_word, argv++))
2041+ goto out;
2042+ }
2043+ goto store_value;
2044+ }
2045+ if (!strncmp(left_word, "exec.envp[\"", 11)) {
2046+ if (!envp) {
2047+ e.envc++;
2048+ e.condc++;
2049+ } else {
2050+ e.envc--;
2051+ e.condc--;
2052+ left = CCS_ENVP_ENTRY;
2053+ envp->is_not = is_not;
2054+ if (!ccs_parse_envp(left_word + 11,
2055+ right_word, envp++))
2056+ goto out;
2057+ }
2058+ goto store_value;
2059+ }
2060+ left = ccs_condition_type(left_word);
2061+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
2062+ left);
2063+ if (left == CCS_MAX_CONDITION_KEYWORD) {
2064+ if (!numbers_p) {
2065+ e.numbers_count++;
2066+ } else {
2067+ e.numbers_count--;
2068+ left = CCS_NUMBER_UNION;
2069+ param->data = left_word;
2070+ if (*left_word == '@' ||
2071+ !ccs_parse_number_union(param,
2072+ numbers_p++))
2073+ goto out;
2074+ }
2075+ }
2076+ if (!condp)
2077+ e.condc++;
2078+ else
2079+ e.condc--;
2080+ if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
2081+ if (!names_p) {
2082+ e.names_count++;
2083+ } else {
2084+ e.names_count--;
2085+ right = CCS_NAME_UNION;
2086+ param->data = right_word;
2087+ if (!ccs_parse_name_union_quoted(param,
2088+ names_p++))
2089+ goto out;
2090+ }
2091+ goto store_value;
2092+ }
2093+ right = ccs_condition_type(right_word);
2094+ if (right == CCS_MAX_CONDITION_KEYWORD) {
2095+ if (!numbers_p) {
2096+ e.numbers_count++;
2097+ } else {
2098+ e.numbers_count--;
2099+ right = CCS_NUMBER_UNION;
2100+ param->data = right_word;
2101+ if (!ccs_parse_number_union(param,
2102+ numbers_p++))
2103+ goto out;
2104+ }
2105+ }
2106+store_value:
2107+ if (!condp) {
2108+ dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
2109+ "match=%u\n", __LINE__, left, right, !is_not);
2110+ continue;
2111+ }
2112+ condp->left = left;
2113+ condp->right = right;
2114+ condp->equals = !is_not;
2115+ dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
2116+ __LINE__, condp->left, condp->right,
2117+ condp->equals);
2118+ condp++;
2119+ }
2120+ dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
2121+ __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
2122+ e.envc);
2123+ if (entry) {
2124+ BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
2125+ e.condc);
2126+ return ccs_commit_condition(entry);
2127+ }
2128+ e.size = sizeof(*entry)
2129+ + e.condc * sizeof(struct ccs_condition_element)
2130+ + e.numbers_count * sizeof(struct ccs_number_union)
2131+ + e.names_count * sizeof(struct ccs_name_union)
2132+ + e.argc * sizeof(struct ccs_argv)
2133+ + e.envc * sizeof(struct ccs_envp);
2134+ entry = kzalloc(e.size, CCS_GFP_FLAGS);
2135+ if (!entry)
2136+ goto out2;
2137+ *entry = e;
2138+ e.transit = NULL;
2139+ condp = (struct ccs_condition_element *) (entry + 1);
2140+ numbers_p = (struct ccs_number_union *) (condp + e.condc);
2141+ names_p = (struct ccs_name_union *) (numbers_p + e.numbers_count);
2142+ argv = (struct ccs_argv *) (names_p + e.names_count);
2143+ envp = (struct ccs_envp *) (argv + e.argc);
2144+ {
2145+ bool flag = false;
2146+ for (pos = start_of_string; pos < end_of_string; pos++) {
2147+ if (*pos)
2148+ continue;
2149+ if (flag) /* Restore " ". */
2150+ *pos = ' ';
2151+ else if (*(pos + 1) == '=') /* Restore "!=". */
2152+ *pos = '!';
2153+ else /* Restore "=". */
2154+ *pos = '=';
2155+ flag = !flag;
2156+ }
2157+ }
2158+ goto rerun;
2159+out:
2160+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
2161+ if (entry) {
2162+ ccs_del_condition(&entry->head.list);
2163+ kfree(entry);
2164+ }
2165+out2:
2166+ ccs_put_name(e.transit);
2167+ return NULL;
2168+}
2169+
2170+/**
2171+ * ccs_yesno - Return "yes" or "no".
2172+ *
2173+ * @value: Bool value.
2174+ *
2175+ * Returns "yes" if @value is not 0, "no" otherwise.
2176+ */
2177+static const char *ccs_yesno(const unsigned int value)
2178+{
2179+ return value ? "yes" : "no";
2180+}
2181+
2182+/**
2183+ * ccs_addprintf - strncat()-like-snprintf().
2184+ *
2185+ * @buffer: Buffer to write to. Must be '\0'-terminated.
2186+ * @len: Size of @buffer.
2187+ * @fmt: The printf()'s format string, followed by parameters.
2188+ *
2189+ * Returns nothing.
2190+ */
2191+static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
2192+{
2193+ va_list args;
2194+ const int pos = strlen(buffer);
2195+ va_start(args, fmt);
2196+ vsnprintf(buffer + pos, len - pos - 1, fmt, args);
2197+ va_end(args);
2198+}
2199+
2200+/**
2201+ * ccs_flush - Flush queued string to userspace's buffer.
2202+ *
2203+ * @head: Pointer to "struct ccs_io_buffer".
2204+ *
2205+ * Returns true if all data was flushed, false otherwise.
2206+ */
2207+static bool ccs_flush(struct ccs_io_buffer *head)
2208+{
2209+ while (head->r.w_pos) {
2210+ const char *w = head->r.w[0];
2211+ size_t len = strlen(w);
2212+ if (len) {
2213+ if (len > head->read_user_buf_avail)
2214+ len = head->read_user_buf_avail;
2215+ if (!len)
2216+ return false;
2217+ if (copy_to_user(head->read_user_buf, w, len))
2218+ return false;
2219+ head->read_user_buf_avail -= len;
2220+ head->read_user_buf += len;
2221+ w += len;
2222+ }
2223+ head->r.w[0] = w;
2224+ if (*w)
2225+ return false;
2226+ /* Add '\0' for audit logs and query. */
2227+ if (head->type == CCS_AUDIT || head->type == CCS_QUERY) {
2228+ if (!head->read_user_buf_avail ||
2229+ copy_to_user(head->read_user_buf, "", 1))
2230+ return false;
2231+ head->read_user_buf_avail--;
2232+ head->read_user_buf++;
2233+ }
2234+ head->r.w_pos--;
2235+ for (len = 0; len < head->r.w_pos; len++)
2236+ head->r.w[len] = head->r.w[len + 1];
2237+ }
2238+ head->r.avail = 0;
2239+ return true;
2240+}
2241+
2242+/**
2243+ * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
2244+ *
2245+ * @head: Pointer to "struct ccs_io_buffer".
2246+ * @string: String to print.
2247+ *
2248+ * Returns nothing.
2249+ *
2250+ * Note that @string has to be kept valid until @head is kfree()d.
2251+ * This means that char[] allocated on stack memory cannot be passed to
2252+ * this function. Use ccs_io_printf() for char[] allocated on stack memory.
2253+ */
2254+static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
2255+{
2256+ if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
2257+ head->r.w[head->r.w_pos++] = string;
2258+ ccs_flush(head);
2259+ } else
2260+ printk(KERN_WARNING "Too many words in a line.\n");
2261+}
2262+
2263+/**
2264+ * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
2265+ *
2266+ * @head: Pointer to "struct ccs_io_buffer".
2267+ * @fmt: The printf()'s format string, followed by parameters.
2268+ *
2269+ * Returns nothing.
2270+ */
2271+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
2272+{
2273+ va_list args;
2274+ size_t len;
2275+ size_t pos = head->r.avail;
2276+ int size = head->readbuf_size - pos;
2277+ if (size <= 0)
2278+ return;
2279+ va_start(args, fmt);
2280+ len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
2281+ va_end(args);
2282+ if (pos + len >= head->readbuf_size) {
2283+ printk(KERN_WARNING "Too many words in a line.\n");
2284+ return;
2285+ }
2286+ head->r.avail += len;
2287+ ccs_set_string(head, head->read_buf + pos);
2288+}
2289+
2290+/**
2291+ * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
2292+ *
2293+ * @head: Pointer to "struct ccs_io_buffer".
2294+ *
2295+ * Returns nothing.
2296+ */
2297+static void ccs_set_space(struct ccs_io_buffer *head)
2298+{
2299+ ccs_set_string(head, " ");
2300+}
2301+
2302+/**
2303+ * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
2304+ *
2305+ * @head: Pointer to "struct ccs_io_buffer".
2306+ *
2307+ * Returns true if all data was flushed, false otherwise.
2308+ */
2309+static bool ccs_set_lf(struct ccs_io_buffer *head)
2310+{
2311+ ccs_set_string(head, "\n");
2312+ return !head->r.w_pos;
2313+}
2314+
2315+/**
2316+ * ccs_set_slash - Put a shash to "struct ccs_io_buffer" structure.
2317+ *
2318+ * @head: Pointer to "struct ccs_io_buffer".
2319+ *
2320+ * Returns nothing.
2321+ */
2322+static void ccs_set_slash(struct ccs_io_buffer *head)
2323+{
2324+ ccs_set_string(head, "/");
2325+}
2326+
2327+/**
2328+ * ccs_init_policy_namespace - Initialize namespace.
2329+ *
2330+ * @ns: Pointer to "struct ccs_policy_namespace".
2331+ *
2332+ * Returns nothing.
2333+ */
2334+static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns)
2335+{
2336+ unsigned int idx;
2337+ for (idx = 0; idx < CCS_MAX_ACL_GROUPS; idx++)
2338+ INIT_LIST_HEAD(&ns->acl_group[idx]);
2339+ for (idx = 0; idx < CCS_MAX_GROUP; idx++)
2340+ INIT_LIST_HEAD(&ns->group_list[idx]);
2341+ for (idx = 0; idx < CCS_MAX_POLICY; idx++)
2342+ INIT_LIST_HEAD(&ns->policy_list[idx]);
2343+ ns->profile_version = 20100903;
2344+ ccs_namespace_enabled = !list_empty(&ccs_namespace_list);
2345+ list_add_tail_rcu(&ns->namespace_list, &ccs_namespace_list);
2346+}
2347+
2348+/**
2349+ * ccs_print_namespace - Print namespace header.
2350+ *
2351+ * @head: Pointer to "struct ccs_io_buffer".
2352+ *
2353+ * Returns nothing.
2354+ */
2355+static void ccs_print_namespace(struct ccs_io_buffer *head)
2356+{
2357+ if (!ccs_namespace_enabled)
2358+ return;
2359+ ccs_set_string(head,
2360+ container_of(head->r.ns, struct ccs_policy_namespace,
2361+ namespace_list)->name);
2362+ ccs_set_space(head);
2363+}
2364+
2365+/**
2366+ * ccs_assign_profile - Create a new profile.
2367+ *
2368+ * @ns: Pointer to "struct ccs_policy_namespace".
2369+ * @profile: Profile number to create.
2370+ *
2371+ * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
2372+ */
2373+static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
2374+ const unsigned int profile)
2375+{
2376+ struct ccs_profile *ptr;
2377+ struct ccs_profile *entry;
2378+ if (profile >= CCS_MAX_PROFILES)
2379+ return NULL;
2380+ ptr = ns->profile_ptr[profile];
2381+ if (ptr)
2382+ return ptr;
2383+ entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
2384+ if (mutex_lock_interruptible(&ccs_policy_lock))
2385+ goto out;
2386+ ptr = ns->profile_ptr[profile];
2387+ if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
2388+ ptr = entry;
2389+ ptr->default_config = CCS_CONFIG_DISABLED |
2390+ CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
2391+ memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
2392+ sizeof(ptr->config));
2393+ ptr->pref[CCS_PREF_MAX_AUDIT_LOG] =
2394+ CONFIG_CCSECURITY_MAX_AUDIT_LOG;
2395+ ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
2396+ CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
2397+ mb(); /* Avoid out-of-order execution. */
2398+ ns->profile_ptr[profile] = ptr;
2399+ entry = NULL;
2400+ }
2401+ mutex_unlock(&ccs_policy_lock);
2402+out:
2403+ kfree(entry);
2404+ return ptr;
2405+}
2406+
2407+/**
2408+ * ccs_check_profile - Check all profiles currently assigned to domains are defined.
2409+ *
2410+ * Returns nothing.
2411+ */
2412+static void ccs_check_profile(void)
2413+{
2414+ struct ccs_domain_info *domain;
2415+ const int idx = ccs_read_lock();
2416+ ccs_policy_loaded = true;
2417+ printk(KERN_INFO "CCSecurity: 1.8.3+ 2012/05/05\n");
2418+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2419+ const u8 profile = domain->profile;
2420+ const struct ccs_policy_namespace *ns = domain->ns;
2421+ if (ns->profile_version != 20100903)
2422+ printk(KERN_ERR
2423+ "Profile version %u is not supported.\n",
2424+ ns->profile_version);
2425+ else if (!ns->profile_ptr[profile])
2426+ printk(KERN_ERR
2427+ "Profile %u (used by '%s') is not defined.\n",
2428+ profile, domain->domainname->name);
2429+ else
2430+ continue;
2431+ printk(KERN_ERR
2432+ "Userland tools for TOMOYO 1.8 must be installed and "
2433+ "policy must be initialized.\n");
2434+ printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
2435+ "for more information.\n");
2436+ panic("STOP!");
2437+ }
2438+ ccs_read_unlock(idx);
2439+ printk(KERN_INFO "Mandatory Access Control activated.\n");
2440+}
2441+
2442+/**
2443+ * ccs_profile - Find a profile.
2444+ *
2445+ * @profile: Profile number to find.
2446+ *
2447+ * Returns pointer to "struct ccs_profile".
2448+ */
2449+static struct ccs_profile *ccs_profile(const u8 profile)
2450+{
2451+ static struct ccs_profile ccs_null_profile;
2452+ struct ccs_profile *ptr = ccs_current_namespace()->
2453+ profile_ptr[profile];
2454+ if (!ptr)
2455+ ptr = &ccs_null_profile;
2456+ return ptr;
2457+}
2458+
2459+/**
2460+ * ccs_get_config - Get config for specified profile's specified functionality.
2461+ *
2462+ * @profile: Profile number.
2463+ * @index: Index number of functionality.
2464+ *
2465+ * Returns config.
2466+ *
2467+ * First, check for CONFIG::category::functionality.
2468+ * If CONFIG::category::functionality is set to use default, then check
2469+ * CONFIG::category. If CONFIG::category is set to use default, then use
2470+ * CONFIG. CONFIG cannot be set to use default.
2471+ */
2472+u8 ccs_get_config(const u8 profile, const u8 index)
2473+{
2474+ u8 config;
2475+ const struct ccs_profile *p;
2476+ if (!ccs_policy_loaded)
2477+ return CCS_CONFIG_DISABLED;
2478+ p = ccs_profile(profile);
2479+ config = p->config[index];
2480+ if (config == CCS_CONFIG_USE_DEFAULT)
2481+ config = p->config[ccs_index2category[index]
2482+ + CCS_MAX_MAC_INDEX];
2483+ if (config == CCS_CONFIG_USE_DEFAULT)
2484+ config = p->default_config;
2485+ return config;
2486+}
2487+
2488+/**
2489+ * ccs_find_yesno - Find values for specified keyword.
2490+ *
2491+ * @string: String to check.
2492+ * @find: Name of keyword.
2493+ *
2494+ * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
2495+ */
2496+static s8 ccs_find_yesno(const char *string, const char *find)
2497+{
2498+ const char *cp = strstr(string, find);
2499+ if (cp) {
2500+ cp += strlen(find);
2501+ if (!strncmp(cp, "=yes", 4))
2502+ return 1;
2503+ else if (!strncmp(cp, "=no", 3))
2504+ return 0;
2505+ }
2506+ return -1;
2507+}
2508+
2509+/**
2510+ * ccs_set_uint - Set value for specified preference.
2511+ *
2512+ * @i: Pointer to "unsigned int".
2513+ * @string: String to check.
2514+ * @find: Name of keyword.
2515+ *
2516+ * Returns nothing.
2517+ */
2518+static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
2519+{
2520+ const char *cp = strstr(string, find);
2521+ if (cp)
2522+ sscanf(cp + strlen(find), "=%u", i);
2523+}
2524+
2525+/**
2526+ * ccs_str_starts - Check whether the given string starts with the given keyword.
2527+ *
2528+ * @src: Pointer to pointer to the string.
2529+ * @find: Pointer to the keyword.
2530+ *
2531+ * Returns true if @src starts with @find, false otherwise.
2532+ *
2533+ * The @src is updated to point the first character after the @find
2534+ * if @src starts with @find.
2535+ */
2536+static bool ccs_str_starts(char **src, const char *find)
2537+{
2538+ const int len = strlen(find);
2539+ char *tmp = *src;
2540+ if (strncmp(tmp, find, len))
2541+ return false;
2542+ tmp += len;
2543+ *src = tmp;
2544+ return true;
2545+}
2546+
2547+/**
2548+ * ccs_print_group - Print group's name.
2549+ *
2550+ * @head: Pointer to "struct ccs_io_buffer".
2551+ * @group: Pointer to "struct ccsgroup". Maybe NULL.
2552+ *
2553+ * Returns true if @group is not NULL. false otherwise.
2554+ */
2555+static bool ccs_print_group(struct ccs_io_buffer *head,
2556+ const struct ccs_group *group)
2557+{
2558+ if (group) {
2559+ ccs_set_string(head, "@");
2560+ ccs_set_string(head, group->group_name->name);
2561+ return true;
2562+ }
2563+ return false;
2564+}
2565+
2566+/**
2567+ * ccs_set_mode - Set mode for specified profile.
2568+ *
2569+ * @name: Name of functionality.
2570+ * @value: Mode for @name.
2571+ * @profile: Pointer to "struct ccs_profile".
2572+ *
2573+ * Returns 0 on success, negative value otherwise.
2574+ */
2575+static int ccs_set_mode(char *name, const char *value,
2576+ struct ccs_profile *profile)
2577+{
2578+ u8 i;
2579+ u8 config;
2580+ if (!strcmp(name, "CONFIG")) {
2581+ i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
2582+ config = profile->default_config;
2583+ } else if (ccs_str_starts(&name, "CONFIG::")) {
2584+ config = 0;
2585+ for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
2586+ i++) {
2587+ int len = 0;
2588+ if (i < CCS_MAX_MAC_INDEX) {
2589+ const u8 c = ccs_index2category[i];
2590+ const char *category =
2591+ ccs_category_keywords[c];
2592+ len = strlen(category);
2593+ if (strncmp(name, category, len) ||
2594+ name[len++] != ':' || name[len++] != ':')
2595+ continue;
2596+ }
2597+ if (strcmp(name + len, ccs_mac_keywords[i]))
2598+ continue;
2599+ config = profile->config[i];
2600+ break;
2601+ }
2602+ if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
2603+ return -EINVAL;
2604+ } else {
2605+ return -EINVAL;
2606+ }
2607+ if (strstr(value, "use_default")) {
2608+ config = CCS_CONFIG_USE_DEFAULT;
2609+ } else {
2610+ u8 mode;
2611+ for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
2612+ if (strstr(value, ccs_mode[mode]))
2613+ /*
2614+ * Update lower 3 bits in order to distinguish
2615+ * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
2616+ */
2617+ config = (config & ~7) | mode;
2618+ if (config != CCS_CONFIG_USE_DEFAULT) {
2619+ switch (ccs_find_yesno(value, "grant_log")) {
2620+ case 1:
2621+ config |= CCS_CONFIG_WANT_GRANT_LOG;
2622+ break;
2623+ case 0:
2624+ config &= ~CCS_CONFIG_WANT_GRANT_LOG;
2625+ break;
2626+ }
2627+ switch (ccs_find_yesno(value, "reject_log")) {
2628+ case 1:
2629+ config |= CCS_CONFIG_WANT_REJECT_LOG;
2630+ break;
2631+ case 0:
2632+ config &= ~CCS_CONFIG_WANT_REJECT_LOG;
2633+ break;
2634+ }
2635+ }
2636+ }
2637+ if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
2638+ profile->config[i] = config;
2639+ else if (config != CCS_CONFIG_USE_DEFAULT)
2640+ profile->default_config = config;
2641+ return 0;
2642+}
2643+
2644+/**
2645+ * ccs_write_profile - Write profile table.
2646+ *
2647+ * @head: Pointer to "struct ccs_io_buffer".
2648+ *
2649+ * Returns 0 on success, negative value otherwise.
2650+ */
2651+static int ccs_write_profile(struct ccs_io_buffer *head)
2652+{
2653+ char *data = head->write_buf;
2654+ unsigned int i;
2655+ char *cp;
2656+ struct ccs_profile *profile;
2657+ if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
2658+ == 1)
2659+ return 0;
2660+ i = simple_strtoul(data, &cp, 10);
2661+ if (*cp != '-')
2662+ return -EINVAL;
2663+ data = cp + 1;
2664+ profile = ccs_assign_profile(head->w.ns, i);
2665+ if (!profile)
2666+ return -EINVAL;
2667+ cp = strchr(data, '=');
2668+ if (!cp)
2669+ return -EINVAL;
2670+ *cp++ = '\0';
2671+ if (!strcmp(data, "COMMENT")) {
2672+ static DEFINE_SPINLOCK(lock);
2673+ const struct ccs_path_info *new_comment = ccs_get_name(cp);
2674+ const struct ccs_path_info *old_comment;
2675+ if (!new_comment)
2676+ return -ENOMEM;
2677+ spin_lock(&lock);
2678+ old_comment = profile->comment;
2679+ profile->comment = new_comment;
2680+ spin_unlock(&lock);
2681+ ccs_put_name(old_comment);
2682+ return 0;
2683+ }
2684+ if (!strcmp(data, "PREFERENCE")) {
2685+ for (i = 0; i < CCS_MAX_PREF; i++)
2686+ ccs_set_uint(&profile->pref[i], cp,
2687+ ccs_pref_keywords[i]);
2688+ return 0;
2689+ }
2690+ return ccs_set_mode(data, cp, profile);
2691+}
2692+
2693+/**
2694+ * ccs_print_config - Print mode for specified functionality.
2695+ *
2696+ * @head: Pointer to "struct ccs_io_buffer".
2697+ * @config: Mode for that functionality.
2698+ *
2699+ * Returns nothing.
2700+ *
2701+ * Caller prints functionality's name.
2702+ */
2703+static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)
2704+{
2705+ ccs_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
2706+ ccs_mode[config & 3],
2707+ ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),
2708+ ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));
2709+}
2710+
2711+/**
2712+ * ccs_read_profile - Read profile table.
2713+ *
2714+ * @head: Pointer to "struct ccs_io_buffer".
2715+ *
2716+ * Returns nothing.
2717+ */
2718+static void ccs_read_profile(struct ccs_io_buffer *head)
2719+{
2720+ u8 index;
2721+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
2722+ namespace_list);
2723+ const struct ccs_profile *profile;
2724+ if (head->r.eof)
2725+ return;
2726+next:
2727+ index = head->r.index;
2728+ profile = ns->profile_ptr[index];
2729+ switch (head->r.step) {
2730+ case 0:
2731+ ccs_print_namespace(head);
2732+ ccs_io_printf(head, "PROFILE_VERSION=%u\n",
2733+ ns->profile_version);
2734+ head->r.step++;
2735+ break;
2736+ case 1:
2737+ for ( ; head->r.index < CCS_MAX_PROFILES; head->r.index++)
2738+ if (ns->profile_ptr[head->r.index])
2739+ break;
2740+ if (head->r.index == CCS_MAX_PROFILES) {
2741+ head->r.eof = true;
2742+ return;
2743+ }
2744+ head->r.step++;
2745+ break;
2746+ case 2:
2747+ {
2748+ u8 i;
2749+ const struct ccs_path_info *comment = profile->comment;
2750+ ccs_print_namespace(head);
2751+ ccs_io_printf(head, "%u-COMMENT=", index);
2752+ ccs_set_string(head, comment ? comment->name : "");
2753+ ccs_set_lf(head);
2754+ ccs_print_namespace(head);
2755+ ccs_io_printf(head, "%u-PREFERENCE={ ", index);
2756+ for (i = 0; i < CCS_MAX_PREF; i++)
2757+ ccs_io_printf(head, "%s=%u ",
2758+ ccs_pref_keywords[i],
2759+ profile->pref[i]);
2760+ ccs_set_string(head, "}\n");
2761+ head->r.step++;
2762+ }
2763+ break;
2764+ case 3:
2765+ {
2766+ ccs_print_namespace(head);
2767+ ccs_io_printf(head, "%u-%s", index, "CONFIG");
2768+ ccs_print_config(head, profile->default_config);
2769+ head->r.bit = 0;
2770+ head->r.step++;
2771+ }
2772+ break;
2773+ case 4:
2774+ for ( ; head->r.bit < CCS_MAX_MAC_INDEX
2775+ + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
2776+ const u8 i = head->r.bit;
2777+ const u8 config = profile->config[i];
2778+ if (config == CCS_CONFIG_USE_DEFAULT)
2779+ continue;
2780+ ccs_print_namespace(head);
2781+ if (i < CCS_MAX_MAC_INDEX)
2782+ ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
2783+ ccs_category_keywords
2784+ [ccs_index2category[i]],
2785+ ccs_mac_keywords[i]);
2786+ else
2787+ ccs_io_printf(head, "%u-CONFIG::%s", index,
2788+ ccs_mac_keywords[i]);
2789+ ccs_print_config(head, config);
2790+ head->r.bit++;
2791+ break;
2792+ }
2793+ if (head->r.bit == CCS_MAX_MAC_INDEX
2794+ + CCS_MAX_MAC_CATEGORY_INDEX) {
2795+ head->r.index++;
2796+ head->r.step = 1;
2797+ }
2798+ break;
2799+ }
2800+ if (ccs_flush(head))
2801+ goto next;
2802+}
2803+
2804+/**
2805+ * ccs_update_policy - Update an entry for exception policy.
2806+ *
2807+ * @size: Size of new entry in bytes.
2808+ * @param: Pointer to "struct ccs_acl_param".
2809+ *
2810+ * Returns 0 on success, negative value otherwise.
2811+ *
2812+ * Caller holds ccs_read_lock().
2813+ */
2814+static int ccs_update_policy(const int size, struct ccs_acl_param *param)
2815+{
2816+ struct ccs_acl_head *new_entry = &param->e.acl_head;
2817+ int error = param->is_delete ? -ENOENT : -ENOMEM;
2818+ struct ccs_acl_head *entry;
2819+ struct list_head *list = param->list;
2820+ BUG_ON(size < sizeof(*entry));
2821+ if (mutex_lock_interruptible(&ccs_policy_lock))
2822+ return -ENOMEM;
2823+ list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
2824+ if (entry->is_deleted == CCS_GC_IN_PROGRESS)
2825+ continue;
2826+ if (memcmp(entry + 1, new_entry + 1, size - sizeof(*entry)))
2827+ continue;
2828+ entry->is_deleted = param->is_delete;
2829+ error = 0;
2830+ break;
2831+ }
2832+ if (error && !param->is_delete) {
2833+ entry = ccs_commit_ok(new_entry, size);
2834+ if (entry) {
2835+ list_add_tail_rcu(&entry->list, list);
2836+ error = 0;
2837+ }
2838+ }
2839+ mutex_unlock(&ccs_policy_lock);
2840+ return error;
2841+}
2842+
2843+/**
2844+ * ccs_update_manager_entry - Add a manager entry.
2845+ *
2846+ * @manager: The path to manager or the domainnamme.
2847+ * @is_delete: True if it is a delete request.
2848+ *
2849+ * Returns 0 on success, negative value otherwise.
2850+ */
2851+static int ccs_update_manager_entry(const char *manager,
2852+ const bool is_delete)
2853+{
2854+ struct ccs_acl_param param = {
2855+ /* .ns = &ccs_kernel_namespace, */
2856+ .is_delete = is_delete,
2857+ .list = &ccs_kernel_namespace.policy_list[CCS_ID_MANAGER],
2858+ };
2859+ struct ccs_manager *e = &param.e.manager;
2860+ int error = is_delete ? -ENOENT : -ENOMEM;
2861+ /* Forced zero clear for using memcmp() at ccs_update_policy(). */
2862+ memset(&param.e, 0, sizeof(param.e));
2863+ if (!ccs_correct_domain(manager) && !ccs_correct_word(manager))
2864+ return -EINVAL;
2865+ e->manager = ccs_get_name(manager);
2866+ if (e->manager) {
2867+ error = ccs_update_policy(sizeof(*e), &param);
2868+ ccs_put_name(e->manager);
2869+ }
2870+ return error;
2871+}
2872+
2873+/**
2874+ * ccs_write_manager - Write manager policy.
2875+ *
2876+ * @head: Pointer to "struct ccs_io_buffer".
2877+ *
2878+ * Returns 0 on success, negative value otherwise.
2879+ */
2880+static int ccs_write_manager(struct ccs_io_buffer *head)
2881+{
2882+ const char *data = head->write_buf;
2883+ if (!strcmp(data, "manage_by_non_root")) {
2884+ ccs_manage_by_non_root = !head->w.is_delete;
2885+ return 0;
2886+ }
2887+ return ccs_update_manager_entry(data, head->w.is_delete);
2888+}
2889+
2890+/**
2891+ * ccs_read_manager - Read manager policy.
2892+ *
2893+ * @head: Pointer to "struct ccs_io_buffer".
2894+ *
2895+ * Returns nothing.
2896+ *
2897+ * Caller holds ccs_read_lock().
2898+ */
2899+static void ccs_read_manager(struct ccs_io_buffer *head)
2900+{
2901+ if (head->r.eof)
2902+ return;
2903+ list_for_each_cookie(head->r.acl, &ccs_kernel_namespace.
2904+ policy_list[CCS_ID_MANAGER]) {
2905+ struct ccs_manager *ptr =
2906+ list_entry(head->r.acl, typeof(*ptr), head.list);
2907+ if (ptr->head.is_deleted)
2908+ continue;
2909+ if (!ccs_flush(head))
2910+ return;
2911+ ccs_set_string(head, ptr->manager->name);
2912+ ccs_set_lf(head);
2913+ }
2914+ head->r.eof = true;
2915+}
2916+
2917+/**
2918+ * ccs_manager - Check whether the current process is a policy manager.
2919+ *
2920+ * Returns true if the current process is permitted to modify policy
2921+ * via /proc/ccs/ interface.
2922+ *
2923+ * Caller holds ccs_read_lock().
2924+ */
2925+static bool ccs_manager(void)
2926+{
2927+ struct ccs_manager *ptr;
2928+ struct ccs_path_info exe;
2929+ struct ccs_security *task = ccs_current_security();
2930+ const struct ccs_path_info *domainname
2931+ = ccs_current_domain()->domainname;
2932+ bool found = false;
2933+ if (!ccs_policy_loaded)
2934+ return true;
2935+ if (task->ccs_flags & CCS_TASK_IS_MANAGER)
2936+ return true;
2937+ if (!ccs_manage_by_non_root &&
2938+ (!uid_eq(current_uid(), GLOBAL_ROOT_UID) ||
2939+ !uid_eq(current_euid(), GLOBAL_ROOT_UID)))
2940+ return false;
2941+ exe.name = ccs_get_exe();
2942+ if (!exe.name)
2943+ return false;
2944+ ccs_fill_path_info(&exe);
2945+ list_for_each_entry_srcu(ptr, &ccs_kernel_namespace.
2946+ policy_list[CCS_ID_MANAGER], head.list,
2947+ &ccs_ss) {
2948+ if (ptr->head.is_deleted)
2949+ continue;
2950+ if (ccs_pathcmp(domainname, ptr->manager) &&
2951+ ccs_pathcmp(&exe, ptr->manager))
2952+ continue;
2953+ /* Set manager flag. */
2954+ task->ccs_flags |= CCS_TASK_IS_MANAGER;
2955+ found = true;
2956+ break;
2957+ }
2958+ if (!found) { /* Reduce error messages. */
2959+ static pid_t ccs_last_pid;
2960+ const pid_t pid = current->pid;
2961+ if (ccs_last_pid != pid) {
2962+ printk(KERN_WARNING "%s ( %s ) is not permitted to "
2963+ "update policies.\n", domainname->name,
2964+ exe.name);
2965+ ccs_last_pid = pid;
2966+ }
2967+ }
2968+ kfree(exe.name);
2969+ return found;
2970+}
2971+
2972+/**
2973+ * ccs_find_domain - Find a domain by the given name.
2974+ *
2975+ * @domainname: The domainname to find.
2976+ *
2977+ * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
2978+ *
2979+ * Caller holds ccs_read_lock().
2980+ */
2981+static struct ccs_domain_info *ccs_find_domain(const char *domainname)
2982+{
2983+ struct ccs_domain_info *domain;
2984+ struct ccs_path_info name;
2985+ name.name = domainname;
2986+ ccs_fill_path_info(&name);
2987+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2988+ if (!domain->is_deleted &&
2989+ !ccs_pathcmp(&name, domain->domainname))
2990+ return domain;
2991+ }
2992+ return NULL;
2993+}
2994+
2995+/**
2996+ * ccs_select_domain - Parse select command.
2997+ *
2998+ * @head: Pointer to "struct ccs_io_buffer".
2999+ * @data: String to parse.
3000+ *
3001+ * Returns true on success, false otherwise.
3002+ *
3003+ * Caller holds ccs_read_lock().
3004+ */
3005+static bool ccs_select_domain(struct ccs_io_buffer *head, const char *data)
3006+{
3007+ unsigned int pid;
3008+ struct ccs_domain_info *domain = NULL;
3009+ bool global_pid = false;
3010+ if (strncmp(data, "select ", 7))
3011+ return false;
3012+ data += 7;
3013+ if (sscanf(data, "pid=%u", &pid) == 1 ||
3014+ (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
3015+ struct task_struct *p;
3016+ ccs_tasklist_lock();
3017+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3018+ if (global_pid)
3019+ p = ccsecurity_exports.find_task_by_pid_ns(pid,
3020+ &init_pid_ns);
3021+ else
3022+ p = ccsecurity_exports.find_task_by_vpid(pid);
3023+#else
3024+ p = find_task_by_pid(pid);
3025+#endif
3026+ if (p)
3027+ domain = ccs_task_domain(p);
3028+ ccs_tasklist_unlock();
3029+ } else if (!strncmp(data, "domain=", 7)) {
3030+ if (*(data + 7) == '<')
3031+ domain = ccs_find_domain(data + 7);
3032+ } else if (sscanf(data, "Q=%u", &pid) == 1) {
3033+ domain = ccs_find_domain_by_qid(pid);
3034+ } else
3035+ return false;
3036+ head->w.domain = domain;
3037+ /* Accessing read_buf is safe because head->io_sem is held. */
3038+ if (!head->read_buf)
3039+ return true; /* Do nothing if open(O_WRONLY). */
3040+ memset(&head->r, 0, sizeof(head->r));
3041+ head->r.print_this_domain_only = true;
3042+ if (domain)
3043+ head->r.domain = &domain->list;
3044+ else
3045+ head->r.eof = true;
3046+ ccs_io_printf(head, "# select %s\n", data);
3047+ if (domain && domain->is_deleted)
3048+ ccs_set_string(head, "# This is a deleted domain.\n");
3049+ return true;
3050+}
3051+
3052+/**
3053+ * ccs_update_acl - Update "struct ccs_acl_info" entry.
3054+ *
3055+ * @size: Size of new entry in bytes.
3056+ * @param: Pointer to "struct ccs_acl_param".
3057+ *
3058+ * Returns 0 on success, negative value otherwise.
3059+ *
3060+ * Caller holds ccs_read_lock().
3061+ */
3062+static int ccs_update_acl(const int size, struct ccs_acl_param *param)
3063+{
3064+ struct ccs_acl_info *new_entry = &param->e.acl_info;
3065+ const bool is_delete = param->is_delete;
3066+ int error = is_delete ? -ENOENT : -ENOMEM;
3067+ struct ccs_acl_info *entry;
3068+ struct list_head * const list = param->list;
3069+ BUG_ON(size < sizeof(*entry));
3070+ if (param->data[0]) {
3071+ new_entry->cond = ccs_get_condition(param);
3072+ if (!new_entry->cond)
3073+ return -EINVAL;
3074+ /*
3075+ * Domain transition preference is allowed for only
3076+ * "file execute"/"task auto_execute_handler"/
3077+ * "task denied_auto_execute_handler" entries.
3078+ */
3079+ if (new_entry->cond->exec_transit &&
3080+ !(new_entry->type == CCS_TYPE_PATH_ACL &&
3081+ new_entry->perm == 1 << CCS_TYPE_EXECUTE)
3082+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3083+ && new_entry->type != CCS_TYPE_AUTO_EXECUTE_HANDLER &&
3084+ new_entry->type != CCS_TYPE_DENIED_EXECUTE_HANDLER
3085+#endif
3086+ )
3087+ return -EINVAL;
3088+ }
3089+ if (mutex_lock_interruptible(&ccs_policy_lock))
3090+ return -ENOMEM;
3091+ list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
3092+ if (entry->is_deleted == CCS_GC_IN_PROGRESS)
3093+ continue;
3094+ if (entry->type != new_entry->type ||
3095+ entry->cond != new_entry->cond ||
3096+ memcmp(entry + 1, new_entry + 1, size - sizeof(*entry)))
3097+ continue;
3098+ if (is_delete)
3099+ entry->perm &= ~new_entry->perm;
3100+ else
3101+ entry->perm |= new_entry->perm;
3102+ entry->is_deleted = !entry->perm;
3103+ error = 0;
3104+ break;
3105+ }
3106+ if (error && !is_delete) {
3107+ entry = ccs_commit_ok(new_entry, size);
3108+ if (entry) {
3109+ list_add_tail_rcu(&entry->list, list);
3110+ error = 0;
3111+ }
3112+ }
3113+ mutex_unlock(&ccs_policy_lock);
3114+ return error;
3115+}
3116+
3117+/**
3118+ * ccs_permstr - Find permission keywords.
3119+ *
3120+ * @string: String representation for permissions in foo/bar/buz format.
3121+ * @keyword: Keyword to find from @string/
3122+ *
3123+ * Returns ture if @keyword was found in @string, false otherwise.
3124+ *
3125+ * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
3126+ */
3127+static bool ccs_permstr(const char *string, const char *keyword)
3128+{
3129+ const char *cp = strstr(string, keyword);
3130+ if (cp)
3131+ return cp == string || *(cp - 1) == '/';
3132+ return false;
3133+}
3134+
3135+/**
3136+ * ccs_write_task - Update task related list.
3137+ *
3138+ * @param: Pointer to "struct ccs_acl_param".
3139+ *
3140+ * Returns 0 on success, negative value otherwise.
3141+ *
3142+ * Caller holds ccs_read_lock().
3143+ */
3144+static int ccs_write_task(struct ccs_acl_param *param)
3145+{
3146+ int error;
3147+ const bool is_auto = ccs_str_starts(&param->data,
3148+ "auto_domain_transition ");
3149+ if (!is_auto && !ccs_str_starts(&param->data,
3150+ "manual_domain_transition ")) {
3151+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3152+ struct ccs_handler_acl *e = &param->e.handler_acl;
3153+ char *handler;
3154+ if (ccs_str_starts(&param->data, "auto_execute_handler "))
3155+ e->head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
3156+ else if (ccs_str_starts(&param->data,
3157+ "denied_execute_handler "))
3158+ e->head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
3159+ else
3160+ return -EINVAL;
3161+ handler = ccs_read_token(param);
3162+ if (!ccs_correct_path(handler))
3163+ return -EINVAL;
3164+ e->handler = ccs_get_name(handler);
3165+ if (!e->handler)
3166+ return -ENOMEM;
3167+ if (e->handler->is_patterned)
3168+ return -EINVAL; /* No patterns allowed. */
3169+ return ccs_update_acl(sizeof(*e), param);
3170+#else
3171+ error = -EINVAL;
3172+#endif
3173+ } else {
3174+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
3175+ struct ccs_task_acl *e = &param->e.task_acl;
3176+ e->head.type = is_auto ?
3177+ CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL;
3178+ e->domainname = ccs_get_domainname(param);
3179+ if (!e->domainname)
3180+ return -EINVAL;
3181+ return ccs_update_acl(sizeof(*e), param);
3182+#else
3183+ error = -EINVAL;
3184+#endif
3185+ }
3186+ return error;
3187+}
3188+
3189+#ifdef CONFIG_CCSECURITY_NETWORK
3190+
3191+/**
3192+ * ccs_write_inet_network - Write "struct ccs_inet_acl" list.
3193+ *
3194+ * @param: Pointer to "struct ccs_acl_param".
3195+ *
3196+ * Returns 0 on success, negative value otherwise.
3197+ *
3198+ * Caller holds ccs_read_lock().
3199+ */
3200+static int ccs_write_inet_network(struct ccs_acl_param *param)
3201+{
3202+ struct ccs_inet_acl *e = &param->e.inet_acl;
3203+ u8 type;
3204+ const char *protocol = ccs_read_token(param);
3205+ const char *operation = ccs_read_token(param);
3206+ e->head.type = CCS_TYPE_INET_ACL;
3207+ for (type = 0; type < CCS_SOCK_MAX; type++)
3208+ if (!strcmp(protocol, ccs_proto_keyword[type]))
3209+ break;
3210+ if (type == CCS_SOCK_MAX)
3211+ return -EINVAL;
3212+ e->protocol = type;
3213+ e->head.perm = 0;
3214+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
3215+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
3216+ e->head.perm |= 1 << type;
3217+ if (!e->head.perm)
3218+ return -EINVAL;
3219+ if (param->data[0] == '@') {
3220+ param->data++;
3221+ e->address.group = ccs_get_group(param, CCS_ADDRESS_GROUP);
3222+ if (!e->address.group)
3223+ return -ENOMEM;
3224+ } else {
3225+ if (!ccs_parse_ipaddr_union(param, &e->address))
3226+ return -EINVAL;
3227+ }
3228+ if (!ccs_parse_number_union(param, &e->port) ||
3229+ e->port.values[1] > 65535)
3230+ return -EINVAL;
3231+ return ccs_update_acl(sizeof(*e), param);
3232+}
3233+
3234+/**
3235+ * ccs_write_unix_network - Write "struct ccs_unix_acl" list.
3236+ *
3237+ * @param: Pointer to "struct ccs_acl_param".
3238+ *
3239+ * Returns 0 on success, negative value otherwise.
3240+ */
3241+static int ccs_write_unix_network(struct ccs_acl_param *param)
3242+{
3243+ struct ccs_unix_acl *e = &param->e.unix_acl;
3244+ u8 type;
3245+ const char *protocol = ccs_read_token(param);
3246+ const char *operation = ccs_read_token(param);
3247+ e->head.type = CCS_TYPE_UNIX_ACL;
3248+ for (type = 0; type < CCS_SOCK_MAX; type++)
3249+ if (!strcmp(protocol, ccs_proto_keyword[type]))
3250+ break;
3251+ if (type == CCS_SOCK_MAX)
3252+ return -EINVAL;
3253+ e->protocol = type;
3254+ e->head.perm = 0;
3255+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
3256+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
3257+ e->head.perm |= 1 << type;
3258+ if (!e->head.perm)
3259+ return -EINVAL;
3260+ if (!ccs_parse_name_union(param, &e->name))
3261+ return -EINVAL;
3262+ return ccs_update_acl(sizeof(*e), param);
3263+}
3264+
3265+#endif
3266+
3267+/**
3268+ * ccs_write_file - Update file related list.
3269+ *
3270+ * @param: Pointer to "struct ccs_acl_param".
3271+ *
3272+ * Returns 0 on success, negative value otherwise.
3273+ *
3274+ * Caller holds ccs_read_lock().
3275+ */
3276+static int ccs_write_file(struct ccs_acl_param *param)
3277+{
3278+ u16 perm = 0;
3279+ u8 type;
3280+ const char *operation = ccs_read_token(param);
3281+ for (type = 0; type < CCS_MAX_PATH_OPERATION; type++)
3282+ if (ccs_permstr(operation, ccs_path_keyword[type]))
3283+ perm |= 1 << type;
3284+ if (perm) {
3285+ struct ccs_path_acl *e = &param->e.path_acl;
3286+ e->head.type = CCS_TYPE_PATH_ACL;
3287+ e->head.perm = perm;
3288+ if (!ccs_parse_name_union(param, &e->name))
3289+ return -EINVAL;
3290+ return ccs_update_acl(sizeof(*e), param);
3291+ }
3292+ for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++)
3293+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pp2mac[type]]))
3294+ perm |= 1 << type;
3295+ if (perm) {
3296+ struct ccs_path2_acl *e = &param->e.path2_acl;
3297+ e->head.type = CCS_TYPE_PATH2_ACL;
3298+ e->head.perm = perm;
3299+ if (!ccs_parse_name_union(param, &e->name1) ||
3300+ !ccs_parse_name_union(param, &e->name2))
3301+ return -EINVAL;
3302+ return ccs_update_acl(sizeof(*e), param);
3303+ }
3304+ for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++)
3305+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pn2mac[type]]))
3306+ perm |= 1 << type;
3307+ if (perm) {
3308+ struct ccs_path_number_acl *e = &param->e.path_number_acl;
3309+ e->head.type = CCS_TYPE_PATH_NUMBER_ACL;
3310+ e->head.perm = perm;
3311+ if (!ccs_parse_name_union(param, &e->name) ||
3312+ !ccs_parse_number_union(param, &e->number))
3313+ return -EINVAL;
3314+ return ccs_update_acl(sizeof(*e), param);
3315+ }
3316+ for (type = 0; type < CCS_MAX_MKDEV_OPERATION; type++)
3317+ if (ccs_permstr(operation,
3318+ ccs_mac_keywords[ccs_pnnn2mac[type]]))
3319+ perm |= 1 << type;
3320+ if (perm) {
3321+ struct ccs_mkdev_acl *e = &param->e.mkdev_acl;
3322+ e->head.type = CCS_TYPE_MKDEV_ACL;
3323+ e->head.perm = perm;
3324+ if (!ccs_parse_name_union(param, &e->name) ||
3325+ !ccs_parse_number_union(param, &e->mode) ||
3326+ !ccs_parse_number_union(param, &e->major) ||
3327+ !ccs_parse_number_union(param, &e->minor))
3328+ return -EINVAL;
3329+ return ccs_update_acl(sizeof(*e), param);
3330+ }
3331+ if (ccs_permstr(operation, ccs_mac_keywords[CCS_MAC_FILE_MOUNT])) {
3332+ struct ccs_mount_acl *e = &param->e.mount_acl;
3333+ e->head.type = CCS_TYPE_MOUNT_ACL;
3334+ if (!ccs_parse_name_union(param, &e->dev_name) ||
3335+ !ccs_parse_name_union(param, &e->dir_name) ||
3336+ !ccs_parse_name_union(param, &e->fs_type) ||
3337+ !ccs_parse_number_union(param, &e->flags))
3338+ return -EINVAL;
3339+ return ccs_update_acl(sizeof(*e), param);
3340+ }
3341+ return -EINVAL;
3342+}
3343+
3344+#ifdef CONFIG_CCSECURITY_MISC
3345+
3346+/**
3347+ * ccs_write_misc - Update environment variable list.
3348+ *
3349+ * @param: Pointer to "struct ccs_acl_param".
3350+ *
3351+ * Returns 0 on success, negative value otherwise.
3352+ */
3353+static int ccs_write_misc(struct ccs_acl_param *param)
3354+{
3355+ if (ccs_str_starts(&param->data, "env ")) {
3356+ struct ccs_env_acl *e = &param->e.env_acl;
3357+ const char *data = ccs_read_token(param);
3358+ e->head.type = CCS_TYPE_ENV_ACL;
3359+ if (!ccs_correct_word(data) || strchr(data, '='))
3360+ return -EINVAL;
3361+ e->env = ccs_get_name(data);
3362+ if (!e->env)
3363+ return -ENOMEM;
3364+ return ccs_update_acl(sizeof(*e), param);
3365+ }
3366+ return -EINVAL;
3367+}
3368+
3369+#endif
3370+
3371+#ifdef CONFIG_CCSECURITY_IPC
3372+
3373+/**
3374+ * ccs_write_ipc - Update "struct ccs_signal_acl" list.
3375+ *
3376+ * @param: Pointer to "struct ccs_acl_param".
3377+ *
3378+ * Returns 0 on success, negative value otherwise.
3379+ */
3380+static int ccs_write_ipc(struct ccs_acl_param *param)
3381+{
3382+ struct ccs_signal_acl *e = &param->e.signal_acl;
3383+ e->head.type = CCS_TYPE_SIGNAL_ACL;
3384+ if (!ccs_parse_number_union(param, &e->sig))
3385+ return -EINVAL;
3386+ e->domainname = ccs_get_domainname(param);
3387+ if (!e->domainname)
3388+ return -EINVAL;
3389+ return ccs_update_acl(sizeof(*e), param);
3390+}
3391+
3392+#endif
3393+
3394+#ifdef CONFIG_CCSECURITY_CAPABILITY
3395+
3396+/**
3397+ * ccs_write_capability - Write "struct ccs_capability_acl" list.
3398+ *
3399+ * @param: Pointer to "struct ccs_acl_param".
3400+ *
3401+ * Returns 0 on success, negative value otherwise.
3402+ *
3403+ * Caller holds ccs_read_lock().
3404+ */
3405+static int ccs_write_capability(struct ccs_acl_param *param)
3406+{
3407+ struct ccs_capability_acl *e = &param->e.capability_acl;
3408+ const char *operation = ccs_read_token(param);
3409+ u8 type;
3410+ e->head.type = CCS_TYPE_CAPABILITY_ACL;
3411+ for (type = 0; type < CCS_MAX_CAPABILITY_INDEX; type++) {
3412+ if (strcmp(operation, ccs_mac_keywords[ccs_c2mac[type]]))
3413+ continue;
3414+ e->operation = type;
3415+ return ccs_update_acl(sizeof(*e), param);
3416+ }
3417+ return -EINVAL;
3418+}
3419+
3420+#endif
3421+
3422+/**
3423+ * ccs_write_acl - Write "struct ccs_acl_info" list.
3424+ *
3425+ * @ns: Pointer to "struct ccs_policy_namespace".
3426+ * @list: Pointer to "struct list_head".
3427+ * @data: Policy to be interpreted.
3428+ * @is_delete: True if it is a delete request.
3429+ *
3430+ * Returns 0 on success, negative value otherwise.
3431+ *
3432+ * Caller holds ccs_read_lock().
3433+ */
3434+static int ccs_write_acl(struct ccs_policy_namespace *ns,
3435+ struct list_head *list, char *data,
3436+ const bool is_delete)
3437+{
3438+ struct ccs_acl_param param = {
3439+ .ns = ns,
3440+ .list = list,
3441+ .data = data,
3442+ .is_delete = is_delete,
3443+ };
3444+ static const struct {
3445+ const char *keyword;
3446+ int (*write) (struct ccs_acl_param *);
3447+ } ccs_callback[] = {
3448+ { "file ", ccs_write_file },
3449+#ifdef CONFIG_CCSECURITY_NETWORK
3450+ { "network inet ", ccs_write_inet_network },
3451+ { "network unix ", ccs_write_unix_network },
3452+#endif
3453+#ifdef CONFIG_CCSECURITY_MISC
3454+ { "misc ", ccs_write_misc },
3455+#endif
3456+#ifdef CONFIG_CCSECURITY_CAPABILITY
3457+ { "capability ", ccs_write_capability },
3458+#endif
3459+#ifdef CONFIG_CCSECURITY_IPC
3460+ { "ipc signal ", ccs_write_ipc },
3461+#endif
3462+ { "task ", ccs_write_task },
3463+ };
3464+ u8 i;
3465+ /* Forced zero clear for using memcmp() at ccs_update_acl(). */
3466+ memset(&param.e, 0, sizeof(param.e));
3467+ param.e.acl_info.perm = 1;
3468+ for (i = 0; i < ARRAY_SIZE(ccs_callback); i++) {
3469+ int error;
3470+ if (!ccs_str_starts(&param.data, ccs_callback[i].keyword))
3471+ continue;
3472+ error = ccs_callback[i].write(&param);
3473+ ccs_del_acl(&param.e.acl_info.list);
3474+ return error;
3475+ }
3476+ return -EINVAL;
3477+}
3478+
3479+/**
3480+ * ccs_delete_domain - Delete a domain.
3481+ *
3482+ * @domainname: The name of domain.
3483+ *
3484+ * Returns 0.
3485+ */
3486+static int ccs_delete_domain(char *domainname)
3487+{
3488+ struct ccs_domain_info *domain;
3489+ struct ccs_path_info name;
3490+ name.name = domainname;
3491+ ccs_fill_path_info(&name);
3492+ if (mutex_lock_interruptible(&ccs_policy_lock))
3493+ return 0;
3494+ /* Is there an active domain? */
3495+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
3496+ /* Never delete ccs_kernel_domain. */
3497+ if (domain == &ccs_kernel_domain)
3498+ continue;
3499+ if (domain->is_deleted ||
3500+ ccs_pathcmp(domain->domainname, &name))
3501+ continue;
3502+ domain->is_deleted = true;
3503+ break;
3504+ }
3505+ mutex_unlock(&ccs_policy_lock);
3506+ return 0;
3507+}
3508+
3509+/**
3510+ * ccs_write_domain - Write domain policy.
3511+ *
3512+ * @head: Pointer to "struct ccs_io_buffer".
3513+ *
3514+ * Returns 0 on success, negative value otherwise.
3515+ *
3516+ * Caller holds ccs_read_lock().
3517+ */
3518+static int ccs_write_domain(struct ccs_io_buffer *head)
3519+{
3520+ char *data = head->write_buf;
3521+ struct ccs_policy_namespace *ns;
3522+ struct ccs_domain_info *domain = head->w.domain;
3523+ const bool is_delete = head->w.is_delete;
3524+ const bool is_select = !is_delete && ccs_str_starts(&data, "select ");
3525+ unsigned int profile;
3526+ if (*data == '<') {
3527+ domain = NULL;
3528+ if (is_delete)
3529+ ccs_delete_domain(data);
3530+ else if (is_select)
3531+ domain = ccs_find_domain(data);
3532+ else
3533+ domain = ccs_assign_domain(data, false);
3534+ head->w.domain = domain;
3535+ return 0;
3536+ }
3537+ if (!domain)
3538+ return -EINVAL;
3539+ ns = domain->ns;
3540+ if (sscanf(data, "use_profile %u\n", &profile) == 1
3541+ && profile < CCS_MAX_PROFILES) {
3542+ if (!ccs_policy_loaded || ns->profile_ptr[(u8) profile])
3543+ if (!is_delete)
3544+ domain->profile = (u8) profile;
3545+ return 0;
3546+ }
3547+ if (sscanf(data, "use_group %u\n", &profile) == 1
3548+ && profile < CCS_MAX_ACL_GROUPS) {
3549+ if (!is_delete)
3550+ domain->group = (u8) profile;
3551+ return 0;
3552+ }
3553+ for (profile = 0; profile < CCS_MAX_DOMAIN_INFO_FLAGS; profile++) {
3554+ const char *cp = ccs_dif[profile];
3555+ if (strncmp(data, cp, strlen(cp) - 1))
3556+ continue;
3557+ domain->flags[profile] = !is_delete;
3558+ return 0;
3559+ }
3560+ return ccs_write_acl(ns, &domain->acl_info_list, data, is_delete);
3561+}
3562+
3563+/**
3564+ * ccs_print_name_union - Print a ccs_name_union.
3565+ *
3566+ * @head: Pointer to "struct ccs_io_buffer".
3567+ * @ptr: Pointer to "struct ccs_name_union".
3568+ *
3569+ * Returns nothing.
3570+ */
3571+static void ccs_print_name_union(struct ccs_io_buffer *head,
3572+ const struct ccs_name_union *ptr)
3573+{
3574+ ccs_set_space(head);
3575+ if (!ccs_print_group(head, ptr->group))
3576+ ccs_set_string(head, ptr->filename->name);
3577+}
3578+
3579+/**
3580+ * ccs_print_name_union_quoted - Print a ccs_name_union with a quote.
3581+ *
3582+ * @head: Pointer to "struct ccs_io_buffer".
3583+ * @ptr: Pointer to "struct ccs_name_union".
3584+ *
3585+ * Returns nothing.
3586+ */
3587+static void ccs_print_name_union_quoted(struct ccs_io_buffer *head,
3588+ const struct ccs_name_union *ptr)
3589+{
3590+ if (!ccs_print_group(head, ptr->group)) {
3591+ ccs_set_string(head, "\"");
3592+ ccs_set_string(head, ptr->filename->name);
3593+ ccs_set_string(head, "\"");
3594+ }
3595+}
3596+
3597+/**
3598+ * ccs_print_number_union_nospace - Print a ccs_number_union without a space.
3599+ *
3600+ * @head: Pointer to "struct ccs_io_buffer".
3601+ * @ptr: Pointer to "struct ccs_number_union".
3602+ *
3603+ * Returns nothing.
3604+ */
3605+static void ccs_print_number_union_nospace(struct ccs_io_buffer *head,
3606+ const struct ccs_number_union *ptr)
3607+{
3608+ if (!ccs_print_group(head, ptr->group)) {
3609+ int i;
3610+ unsigned long min = ptr->values[0];
3611+ const unsigned long max = ptr->values[1];
3612+ u8 min_type = ptr->value_type[0];
3613+ const u8 max_type = ptr->value_type[1];
3614+ char buffer[128];
3615+ buffer[0] = '\0';
3616+ for (i = 0; i < 2; i++) {
3617+ switch (min_type) {
3618+ case CCS_VALUE_TYPE_HEXADECIMAL:
3619+ ccs_addprintf(buffer, sizeof(buffer), "0x%lX",
3620+ min);
3621+ break;
3622+ case CCS_VALUE_TYPE_OCTAL:
3623+ ccs_addprintf(buffer, sizeof(buffer), "0%lo",
3624+ min);
3625+ break;
3626+ default:
3627+ ccs_addprintf(buffer, sizeof(buffer), "%lu",
3628+ min);
3629+ break;
3630+ }
3631+ if (min == max && min_type == max_type)
3632+ break;
3633+ ccs_addprintf(buffer, sizeof(buffer), "-");
3634+ min_type = max_type;
3635+ min = max;
3636+ }
3637+ ccs_io_printf(head, "%s", buffer);
3638+ }
3639+}
3640+
3641+/**
3642+ * ccs_print_number_union - Print a ccs_number_union.
3643+ *
3644+ * @head: Pointer to "struct ccs_io_buffer".
3645+ * @ptr: Pointer to "struct ccs_number_union".
3646+ *
3647+ * Returns nothing.
3648+ */
3649+static void ccs_print_number_union(struct ccs_io_buffer *head,
3650+ const struct ccs_number_union *ptr)
3651+{
3652+ ccs_set_space(head);
3653+ ccs_print_number_union_nospace(head, ptr);
3654+}
3655+
3656+/**
3657+ * ccs_print_condition - Print condition part.
3658+ *
3659+ * @head: Pointer to "struct ccs_io_buffer".
3660+ * @cond: Pointer to "struct ccs_condition".
3661+ *
3662+ * Returns true on success, false otherwise.
3663+ */
3664+static bool ccs_print_condition(struct ccs_io_buffer *head,
3665+ const struct ccs_condition *cond)
3666+{
3667+ switch (head->r.cond_step) {
3668+ case 0:
3669+ head->r.cond_index = 0;
3670+ head->r.cond_step++;
3671+ if (cond->transit && cond->exec_transit) {
3672+ ccs_set_space(head);
3673+ ccs_set_string(head, cond->transit->name);
3674+ }
3675+ /* fall through */
3676+ case 1:
3677+ {
3678+ const u16 condc = cond->condc;
3679+ const struct ccs_condition_element *condp =
3680+ (typeof(condp)) (cond + 1);
3681+ const struct ccs_number_union *numbers_p =
3682+ (typeof(numbers_p)) (condp + condc);
3683+ const struct ccs_name_union *names_p =
3684+ (typeof(names_p))
3685+ (numbers_p + cond->numbers_count);
3686+ const struct ccs_argv *argv =
3687+ (typeof(argv)) (names_p + cond->names_count);
3688+ const struct ccs_envp *envp =
3689+ (typeof(envp)) (argv + cond->argc);
3690+ u16 skip;
3691+ for (skip = 0; skip < head->r.cond_index; skip++) {
3692+ const u8 left = condp->left;
3693+ const u8 right = condp->right;
3694+ condp++;
3695+ switch (left) {
3696+ case CCS_ARGV_ENTRY:
3697+ argv++;
3698+ continue;
3699+ case CCS_ENVP_ENTRY:
3700+ envp++;
3701+ continue;
3702+ case CCS_NUMBER_UNION:
3703+ numbers_p++;
3704+ break;
3705+ }
3706+ switch (right) {
3707+ case CCS_NAME_UNION:
3708+ names_p++;
3709+ break;
3710+ case CCS_NUMBER_UNION:
3711+ numbers_p++;
3712+ break;
3713+ }
3714+ }
3715+ while (head->r.cond_index < condc) {
3716+ const u8 match = condp->equals;
3717+ const u8 left = condp->left;
3718+ const u8 right = condp->right;
3719+ if (!ccs_flush(head))
3720+ return false;
3721+ condp++;
3722+ head->r.cond_index++;
3723+ ccs_set_space(head);
3724+ switch (left) {
3725+ case CCS_ARGV_ENTRY:
3726+ ccs_io_printf(head,
3727+ "exec.argv[%lu]%s=\"",
3728+ argv->index,
3729+ argv->is_not ? "!" : "");
3730+ ccs_set_string(head,
3731+ argv->value->name);
3732+ ccs_set_string(head, "\"");
3733+ argv++;
3734+ continue;
3735+ case CCS_ENVP_ENTRY:
3736+ ccs_set_string(head, "exec.envp[\"");
3737+ ccs_set_string(head, envp->name->name);
3738+ ccs_io_printf(head, "\"]%s=",
3739+ envp->is_not ? "!" : "");
3740+ if (envp->value) {
3741+ ccs_set_string(head, "\"");
3742+ ccs_set_string(head, envp->
3743+ value->name);
3744+ ccs_set_string(head, "\"");
3745+ } else {
3746+ ccs_set_string(head, "NULL");
3747+ }
3748+ envp++;
3749+ continue;
3750+ case CCS_NUMBER_UNION:
3751+ ccs_print_number_union_nospace
3752+ (head, numbers_p++);
3753+ break;
3754+ default:
3755+ ccs_set_string(head,
3756+ ccs_condition_keyword[left]);
3757+ break;
3758+ }
3759+ ccs_set_string(head, match ? "=" : "!=");
3760+ switch (right) {
3761+ case CCS_NAME_UNION:
3762+ ccs_print_name_union_quoted
3763+ (head, names_p++);
3764+ break;
3765+ case CCS_NUMBER_UNION:
3766+ ccs_print_number_union_nospace
3767+ (head, numbers_p++);
3768+ break;
3769+ default:
3770+ ccs_set_string(head,
3771+ ccs_condition_keyword[right]);
3772+ break;
3773+ }
3774+ }
3775+ }
3776+ head->r.cond_step++;
3777+ /* fall through */
3778+ case 2:
3779+ if (!ccs_flush(head))
3780+ break;
3781+ head->r.cond_step++;
3782+ /* fall through */
3783+ case 3:
3784+ if (cond->grant_log != CCS_GRANTLOG_AUTO)
3785+ ccs_io_printf(head, " grant_log=%s",
3786+ ccs_yesno(cond->grant_log ==
3787+ CCS_GRANTLOG_YES));
3788+ if (cond->transit && !cond->exec_transit) {
3789+ const char *name = cond->transit->name;
3790+ ccs_set_string(head, " auto_domain_transition=\"");
3791+ ccs_set_string(head, name);
3792+ ccs_set_string(head, "\"");
3793+ }
3794+ ccs_set_lf(head);
3795+ return true;
3796+ }
3797+ return false;
3798+}
3799+
3800+/**
3801+ * ccs_set_group - Print "acl_group " header keyword and category name.
3802+ *
3803+ * @head: Pointer to "struct ccs_io_buffer".
3804+ * @category: Category name.
3805+ *
3806+ * Returns nothing.
3807+ */
3808+static void ccs_set_group(struct ccs_io_buffer *head, const char *category)
3809+{
3810+ if (head->type == CCS_EXCEPTION_POLICY) {
3811+ ccs_print_namespace(head);
3812+ ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index);
3813+ }
3814+ ccs_set_string(head, category);
3815+}
3816+
3817+/**
3818+ * ccs_print_entry - Print an ACL entry.
3819+ *
3820+ * @head: Pointer to "struct ccs_io_buffer".
3821+ * @acl: Pointer to an ACL entry.
3822+ *
3823+ * Returns true on success, false otherwise.
3824+ */
3825+static bool ccs_print_entry(struct ccs_io_buffer *head,
3826+ const struct ccs_acl_info *acl)
3827+{
3828+ const u8 acl_type = acl->type;
3829+ const bool may_trigger_transition = acl->cond && acl->cond->transit;
3830+ bool first = true;
3831+ u8 bit;
3832+ if (head->r.print_cond_part)
3833+ goto print_cond_part;
3834+ if (acl->is_deleted)
3835+ return true;
3836+ if (!ccs_flush(head))
3837+ return false;
3838+ else if (acl_type == CCS_TYPE_PATH_ACL) {
3839+ struct ccs_path_acl *ptr
3840+ = container_of(acl, typeof(*ptr), head);
3841+ for (bit = 0; bit < CCS_MAX_PATH_OPERATION; bit++) {
3842+ if (!(acl->perm & (1 << bit)))
3843+ continue;
3844+ if (head->r.print_transition_related_only &&
3845+ bit != CCS_TYPE_EXECUTE && !may_trigger_transition)
3846+ continue;
3847+ if (first) {
3848+ ccs_set_group(head, "file ");
3849+ first = false;
3850+ } else {
3851+ ccs_set_slash(head);
3852+ }
3853+ ccs_set_string(head, ccs_path_keyword[bit]);
3854+ }
3855+ if (first)
3856+ return true;
3857+ ccs_print_name_union(head, &ptr->name);
3858+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3859+ } else if (acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
3860+ acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {
3861+ struct ccs_handler_acl *ptr
3862+ = container_of(acl, typeof(*ptr), head);
3863+ ccs_set_group(head, "task ");
3864+ ccs_set_string(head, acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER
3865+ ? "auto_execute_handler " :
3866+ "denied_execute_handler ");
3867+ ccs_set_string(head, ptr->handler->name);
3868+#endif
3869+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
3870+ } else if (acl_type == CCS_TYPE_AUTO_TASK_ACL ||
3871+ acl_type == CCS_TYPE_MANUAL_TASK_ACL) {
3872+ struct ccs_task_acl *ptr =
3873+ container_of(acl, typeof(*ptr), head);
3874+ ccs_set_group(head, "task ");
3875+ ccs_set_string(head, acl_type == CCS_TYPE_AUTO_TASK_ACL ?
3876+ "auto_domain_transition " :
3877+ "manual_domain_transition ");
3878+ ccs_set_string(head, ptr->domainname->name);
3879+#endif
3880+ } else if (head->r.print_transition_related_only &&
3881+ !may_trigger_transition) {
3882+ return true;
3883+ } else if (acl_type == CCS_TYPE_MKDEV_ACL) {
3884+ struct ccs_mkdev_acl *ptr =
3885+ container_of(acl, typeof(*ptr), head);
3886+ for (bit = 0; bit < CCS_MAX_MKDEV_OPERATION; bit++) {
3887+ if (!(acl->perm & (1 << bit)))
3888+ continue;
3889+ if (first) {
3890+ ccs_set_group(head, "file ");
3891+ first = false;
3892+ } else {
3893+ ccs_set_slash(head);
3894+ }
3895+ ccs_set_string(head, ccs_mac_keywords
3896+ [ccs_pnnn2mac[bit]]);
3897+ }
3898+ if (first)
3899+ return true;
3900+ ccs_print_name_union(head, &ptr->name);
3901+ ccs_print_number_union(head, &ptr->mode);
3902+ ccs_print_number_union(head, &ptr->major);
3903+ ccs_print_number_union(head, &ptr->minor);
3904+ } else if (acl_type == CCS_TYPE_PATH2_ACL) {
3905+ struct ccs_path2_acl *ptr =
3906+ container_of(acl, typeof(*ptr), head);
3907+ for (bit = 0; bit < CCS_MAX_PATH2_OPERATION; bit++) {
3908+ if (!(acl->perm & (1 << bit)))
3909+ continue;
3910+ if (first) {
3911+ ccs_set_group(head, "file ");
3912+ first = false;
3913+ } else {
3914+ ccs_set_slash(head);
3915+ }
3916+ ccs_set_string(head, ccs_mac_keywords
3917+ [ccs_pp2mac[bit]]);
3918+ }
3919+ if (first)
3920+ return true;
3921+ ccs_print_name_union(head, &ptr->name1);
3922+ ccs_print_name_union(head, &ptr->name2);
3923+ } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {
3924+ struct ccs_path_number_acl *ptr =
3925+ container_of(acl, typeof(*ptr), head);
3926+ for (bit = 0; bit < CCS_MAX_PATH_NUMBER_OPERATION; bit++) {
3927+ if (!(acl->perm & (1 << bit)))
3928+ continue;
3929+ if (first) {
3930+ ccs_set_group(head, "file ");
3931+ first = false;
3932+ } else {
3933+ ccs_set_slash(head);
3934+ }
3935+ ccs_set_string(head, ccs_mac_keywords
3936+ [ccs_pn2mac[bit]]);
3937+ }
3938+ if (first)
3939+ return true;
3940+ ccs_print_name_union(head, &ptr->name);
3941+ ccs_print_number_union(head, &ptr->number);
3942+#ifdef CONFIG_CCSECURITY_MISC
3943+ } else if (acl_type == CCS_TYPE_ENV_ACL) {
3944+ struct ccs_env_acl *ptr =
3945+ container_of(acl, typeof(*ptr), head);
3946+ ccs_set_group(head, "misc env ");
3947+ ccs_set_string(head, ptr->env->name);
3948+#endif
3949+#ifdef CONFIG_CCSECURITY_CAPABILITY
3950+ } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {
3951+ struct ccs_capability_acl *ptr =
3952+ container_of(acl, typeof(*ptr), head);
3953+ ccs_set_group(head, "capability ");
3954+ ccs_set_string(head, ccs_mac_keywords
3955+ [ccs_c2mac[ptr->operation]]);
3956+#endif
3957+#ifdef CONFIG_CCSECURITY_NETWORK
3958+ } else if (acl_type == CCS_TYPE_INET_ACL) {
3959+ struct ccs_inet_acl *ptr =
3960+ container_of(acl, typeof(*ptr), head);
3961+ for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
3962+ if (!(acl->perm & (1 << bit)))
3963+ continue;
3964+ if (first) {
3965+ ccs_set_group(head, "network inet ");
3966+ ccs_set_string(head, ccs_proto_keyword
3967+ [ptr->protocol]);
3968+ ccs_set_space(head);
3969+ first = false;
3970+ } else {
3971+ ccs_set_slash(head);
3972+ }
3973+ ccs_set_string(head, ccs_socket_keyword[bit]);
3974+ }
3975+ if (first)
3976+ return true;
3977+ ccs_set_space(head);
3978+ if (!ccs_print_group(head, ptr->address.group)) {
3979+ char buf[128];
3980+ ccs_print_ip(buf, sizeof(buf), &ptr->address);
3981+ ccs_io_printf(head, "%s", buf);
3982+ }
3983+ ccs_print_number_union(head, &ptr->port);
3984+ } else if (acl_type == CCS_TYPE_UNIX_ACL) {
3985+ struct ccs_unix_acl *ptr =
3986+ container_of(acl, typeof(*ptr), head);
3987+ for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
3988+ if (!(acl->perm & (1 << bit)))
3989+ continue;
3990+ if (first) {
3991+ ccs_set_group(head, "network unix ");
3992+ ccs_set_string(head, ccs_proto_keyword
3993+ [ptr->protocol]);
3994+ ccs_set_space(head);
3995+ first = false;
3996+ } else {
3997+ ccs_set_slash(head);
3998+ }
3999+ ccs_set_string(head, ccs_socket_keyword[bit]);
4000+ }
4001+ if (first)
4002+ return true;
4003+ ccs_print_name_union(head, &ptr->name);
4004+#endif
4005+#ifdef CONFIG_CCSECURITY_IPC
4006+ } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {
4007+ struct ccs_signal_acl *ptr =
4008+ container_of(acl, typeof(*ptr), head);
4009+ ccs_set_group(head, "ipc signal ");
4010+ ccs_print_number_union_nospace(head, &ptr->sig);
4011+ ccs_set_space(head);
4012+ ccs_set_string(head, ptr->domainname->name);
4013+#endif
4014+ } else if (acl_type == CCS_TYPE_MOUNT_ACL) {
4015+ struct ccs_mount_acl *ptr =
4016+ container_of(acl, typeof(*ptr), head);
4017+ ccs_set_group(head, "file mount");
4018+ ccs_print_name_union(head, &ptr->dev_name);
4019+ ccs_print_name_union(head, &ptr->dir_name);
4020+ ccs_print_name_union(head, &ptr->fs_type);
4021+ ccs_print_number_union(head, &ptr->flags);
4022+ }
4023+ if (acl->cond) {
4024+ head->r.print_cond_part = true;
4025+ head->r.cond_step = 0;
4026+ if (!ccs_flush(head))
4027+ return false;
4028+print_cond_part:
4029+ if (!ccs_print_condition(head, acl->cond))
4030+ return false;
4031+ head->r.print_cond_part = false;
4032+ } else {
4033+ ccs_set_lf(head);
4034+ }
4035+ return true;
4036+}
4037+
4038+/**
4039+ * ccs_read_acl - Read "struct ccs_acl_info" list.
4040+ *
4041+ * @head: Pointer to "struct ccs_io_buffer".
4042+ * @list: Pointer to "struct list_head".
4043+ *
4044+ * Returns true on success, false otherwise.
4045+ *
4046+ * Caller holds ccs_read_lock().
4047+ */
4048+static bool ccs_read_acl(struct ccs_io_buffer *head, struct list_head *list)
4049+{
4050+ list_for_each_cookie(head->r.acl, list) {
4051+ struct ccs_acl_info *ptr =
4052+ list_entry(head->r.acl, typeof(*ptr), list);
4053+ if (!ccs_print_entry(head, ptr))
4054+ return false;
4055+ }
4056+ head->r.acl = NULL;
4057+ return true;
4058+}
4059+
4060+/**
4061+ * ccs_read_domain - Read domain policy.
4062+ *
4063+ * @head: Pointer to "struct ccs_io_buffer".
4064+ *
4065+ * Returns nothing.
4066+ *
4067+ * Caller holds ccs_read_lock().
4068+ */
4069+static void ccs_read_domain(struct ccs_io_buffer *head)
4070+{
4071+ if (head->r.eof)
4072+ return;
4073+ list_for_each_cookie(head->r.domain, &ccs_domain_list) {
4074+ struct ccs_domain_info *domain =
4075+ list_entry(head->r.domain, typeof(*domain), list);
4076+ switch (head->r.step) {
4077+ u8 i;
4078+ case 0:
4079+ if (domain->is_deleted &&
4080+ !head->r.print_this_domain_only)
4081+ continue;
4082+ /* Print domainname and flags. */
4083+ ccs_set_string(head, domain->domainname->name);
4084+ ccs_set_lf(head);
4085+ ccs_io_printf(head, "use_profile %u\n",
4086+ domain->profile);
4087+ ccs_io_printf(head, "use_group %u\n", domain->group);
4088+ for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)
4089+ if (domain->flags[i])
4090+ ccs_set_string(head, ccs_dif[i]);
4091+ head->r.step++;
4092+ ccs_set_lf(head);
4093+ /* fall through */
4094+ case 1:
4095+ if (!ccs_read_acl(head, &domain->acl_info_list))
4096+ return;
4097+ head->r.step++;
4098+ if (!ccs_set_lf(head))
4099+ return;
4100+ /* fall through */
4101+ case 2:
4102+ head->r.step = 0;
4103+ if (head->r.print_this_domain_only)
4104+ goto done;
4105+ }
4106+ }
4107+done:
4108+ head->r.eof = true;
4109+}
4110+
4111+/**
4112+ * ccs_write_pid - Specify PID to obtain domainname.
4113+ *
4114+ * @head: Pointer to "struct ccs_io_buffer".
4115+ *
4116+ * Returns 0.
4117+ */
4118+static int ccs_write_pid(struct ccs_io_buffer *head)
4119+{
4120+ head->r.eof = false;
4121+ return 0;
4122+}
4123+
4124+/**
4125+ * ccs_read_pid - Read information of a process.
4126+ *
4127+ * @head: Pointer to "struct ccs_io_buffer".
4128+ *
4129+ * Returns the domainname which the specified PID is in or
4130+ * process information of the specified PID on success,
4131+ * empty string otherwise.
4132+ *
4133+ * Caller holds ccs_read_lock().
4134+ */
4135+static void ccs_read_pid(struct ccs_io_buffer *head)
4136+{
4137+ char *buf = head->write_buf;
4138+ bool task_info = false;
4139+ bool global_pid = false;
4140+ unsigned int pid;
4141+ struct task_struct *p;
4142+ struct ccs_domain_info *domain = NULL;
4143+ u32 ccs_flags = 0;
4144+ /* Accessing write_buf is safe because head->io_sem is held. */
4145+ if (!buf) {
4146+ head->r.eof = true;
4147+ return; /* Do nothing if open(O_RDONLY). */
4148+ }
4149+ if (head->r.w_pos || head->r.eof)
4150+ return;
4151+ head->r.eof = true;
4152+ if (ccs_str_starts(&buf, "info "))
4153+ task_info = true;
4154+ if (ccs_str_starts(&buf, "global-pid "))
4155+ global_pid = true;
4156+ pid = (unsigned int) simple_strtoul(buf, NULL, 10);
4157+ ccs_tasklist_lock();
4158+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
4159+ if (global_pid)
4160+ p = ccsecurity_exports.find_task_by_pid_ns(pid, &init_pid_ns);
4161+ else
4162+ p = ccsecurity_exports.find_task_by_vpid(pid);
4163+#else
4164+ p = find_task_by_pid(pid);
4165+#endif
4166+ if (p) {
4167+ domain = ccs_task_domain(p);
4168+ ccs_flags = ccs_task_flags(p);
4169+ }
4170+ ccs_tasklist_unlock();
4171+ if (!domain)
4172+ return;
4173+ if (!task_info) {
4174+ ccs_io_printf(head, "%u %u ", pid, domain->profile);
4175+ ccs_set_string(head, domain->domainname->name);
4176+ } else {
4177+ ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
4178+ ccs_yesno(ccs_flags &
4179+ CCS_TASK_IS_MANAGER),
4180+ ccs_yesno(ccs_flags &
4181+ CCS_TASK_IS_EXECUTE_HANDLER));
4182+ }
4183+}
4184+
4185+/**
4186+ * ccs_write_group - Write "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
4187+ *
4188+ * @param: Pointer to "struct ccs_acl_param".
4189+ * @type: Type of this group.
4190+ *
4191+ * Returns 0 on success, negative value otherwise.
4192+ */
4193+static int ccs_write_group(struct ccs_acl_param *param, const u8 type)
4194+{
4195+ struct ccs_group *group = ccs_get_group(param, type);
4196+ int error = -EINVAL;
4197+ if (!group)
4198+ return -ENOMEM;
4199+ param->list = &group->member_list;
4200+ if (type == CCS_PATH_GROUP) {
4201+ struct ccs_path_group *e = &param->e.path_group;
4202+ e->member_name = ccs_get_name(ccs_read_token(param));
4203+ if (!e->member_name) {
4204+ error = -ENOMEM;
4205+ goto out;
4206+ }
4207+ error = ccs_update_policy(sizeof(*e), param);
4208+ ccs_put_name(e->member_name);
4209+ } else if (type == CCS_NUMBER_GROUP) {
4210+ struct ccs_number_group *e = &param->e.number_group;
4211+ if (param->data[0] == '@' ||
4212+ !ccs_parse_number_union(param, &e->number))
4213+ goto out;
4214+ error = ccs_update_policy(sizeof(*e), param);
4215+#ifdef CONFIG_CCSECURITY_NETWORK
4216+ } else {
4217+ struct ccs_address_group *e = &param->e.address_group;
4218+ if (param->data[0] == '@' ||
4219+ !ccs_parse_ipaddr_union(param, &e->address))
4220+ goto out;
4221+ error = ccs_update_policy(sizeof(*e), param);
4222+#endif
4223+ }
4224+out:
4225+ ccs_put_group(group);
4226+ return error;
4227+}
4228+
4229+#ifdef CONFIG_CCSECURITY_PORTRESERVE
4230+/**
4231+ * ccs_lport_reserved - Check whether local port is reserved or not.
4232+ *
4233+ * @port: Port number.
4234+ *
4235+ * Returns true if local port is reserved, false otherwise.
4236+ */
4237+static bool __ccs_lport_reserved(const u16 port)
4238+{
4239+ return ccs_reserved_port_map[port >> 3] & (1 << (port & 7))
4240+ ? true : false;
4241+}
4242+
4243+/**
4244+ * ccs_write_reserved_port - Update "struct ccs_reserved" list.
4245+ *
4246+ * @param: Pointer to "struct ccs_acl_param".
4247+ *
4248+ * Returns 0 on success, negative value otherwise.
4249+ *
4250+ * Caller holds ccs_read_lock().
4251+ */
4252+static int ccs_write_reserved_port(struct ccs_acl_param *param)
4253+{
4254+ struct ccs_reserved *e = &param->e.reserved;
4255+ struct ccs_policy_namespace *ns = param->ns;
4256+ int error;
4257+ u8 *tmp;
4258+ if (param->data[0] == '@' ||
4259+ !ccs_parse_number_union(param, &e->port) ||
4260+ e->port.values[1] > 65535 || param->data[0])
4261+ return -EINVAL;
4262+ param->list = &ns->policy_list[CCS_ID_RESERVEDPORT];
4263+ error = ccs_update_policy(sizeof(*e), param);
4264+ if (error)
4265+ return error;
4266+ tmp = kzalloc(sizeof(ccs_reserved_port_map), CCS_GFP_FLAGS);
4267+ if (!tmp)
4268+ return -ENOMEM;
4269+ list_for_each_entry_srcu(ns, &ccs_namespace_list, namespace_list,
4270+ &ccs_ss) {
4271+ struct ccs_reserved *ptr;
4272+ struct list_head *list = &ns->policy_list[CCS_ID_RESERVEDPORT];
4273+ list_for_each_entry_srcu(ptr, list, head.list, &ccs_ss) {
4274+ unsigned int port;
4275+ if (ptr->head.is_deleted)
4276+ continue;
4277+ for (port = ptr->port.values[0];
4278+ port <= ptr->port.values[1]; port++)
4279+ tmp[port >> 3] |= 1 << (port & 7);
4280+ }
4281+ }
4282+ memmove(ccs_reserved_port_map, tmp, sizeof(ccs_reserved_port_map));
4283+ kfree(tmp);
4284+ /*
4285+ * Since this feature is no-op by default, we don't need to register
4286+ * this callback hook unless the first entry is added.
4287+ */
4288+ ccsecurity_ops.lport_reserved = __ccs_lport_reserved;
4289+ return 0;
4290+}
4291+#endif
4292+
4293+/**
4294+ * ccs_write_aggregator - Write "struct ccs_aggregator" list.
4295+ *
4296+ * @param: Pointer to "struct ccs_acl_param".
4297+ *
4298+ * Returns 0 on success, negative value otherwise.
4299+ */
4300+static int ccs_write_aggregator(struct ccs_acl_param *param)
4301+{
4302+ struct ccs_aggregator *e = &param->e.aggregator;
4303+ int error = param->is_delete ? -ENOENT : -ENOMEM;
4304+ const char *original_name = ccs_read_token(param);
4305+ const char *aggregated_name = ccs_read_token(param);
4306+ if (!ccs_correct_word(original_name) ||
4307+ !ccs_correct_path(aggregated_name))
4308+ return -EINVAL;
4309+ e->original_name = ccs_get_name(original_name);
4310+ e->aggregated_name = ccs_get_name(aggregated_name);
4311+ if (!e->original_name || !e->aggregated_name ||
4312+ e->aggregated_name->is_patterned) /* No patterns allowed. */
4313+ goto out;
4314+ param->list = &param->ns->policy_list[CCS_ID_AGGREGATOR];
4315+ error = ccs_update_policy(sizeof(*e), param);
4316+out:
4317+ ccs_put_name(e->original_name);
4318+ ccs_put_name(e->aggregated_name);
4319+ return error;
4320+}
4321+
4322+/**
4323+ * ccs_write_transition_control - Write "struct ccs_transition_control" list.
4324+ *
4325+ * @param: Pointer to "struct ccs_acl_param".
4326+ * @type: Type of this entry.
4327+ *
4328+ * Returns 0 on success, negative value otherwise.
4329+ */
4330+static int ccs_write_transition_control(struct ccs_acl_param *param,
4331+ const u8 type)
4332+{
4333+ struct ccs_transition_control *e = &param->e.transition_control;
4334+ int error = param->is_delete ? -ENOENT : -ENOMEM;
4335+ char *program = param->data;
4336+ char *domainname = strstr(program, " from ");
4337+ e->type = type;
4338+ if (domainname) {
4339+ *domainname = '\0';
4340+ domainname += 6;
4341+ } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
4342+ type == CCS_TRANSITION_CONTROL_KEEP) {
4343+ domainname = program;
4344+ program = NULL;
4345+ }
4346+ if (program && strcmp(program, "any")) {
4347+ if (!ccs_correct_path(program))
4348+ return -EINVAL;
4349+ e->program = ccs_get_name(program);
4350+ if (!e->program)
4351+ goto out;
4352+ }
4353+ if (domainname && strcmp(domainname, "any")) {
4354+ if (!ccs_correct_domain(domainname)) {
4355+ if (!ccs_correct_path(domainname))
4356+ goto out;
4357+ e->is_last_name = true;
4358+ }
4359+ e->domainname = ccs_get_name(domainname);
4360+ if (!e->domainname)
4361+ goto out;
4362+ }
4363+ param->list = &param->ns->policy_list[CCS_ID_TRANSITION_CONTROL];
4364+ error = ccs_update_policy(sizeof(*e), param);
4365+out:
4366+ ccs_put_name(e->domainname);
4367+ ccs_put_name(e->program);
4368+ return error;
4369+}
4370+
4371+/**
4372+ * ccs_write_exception - Write exception policy.
4373+ *
4374+ * @head: Pointer to "struct ccs_io_buffer".
4375+ *
4376+ * Returns 0 on success, negative value otherwise.
4377+ */
4378+static int ccs_write_exception(struct ccs_io_buffer *head)
4379+{
4380+ const bool is_delete = head->w.is_delete;
4381+ struct ccs_acl_param param = {
4382+ .ns = head->w.ns,
4383+ .is_delete = is_delete,
4384+ .data = head->write_buf,
4385+ };
4386+ u8 i;
4387+ /* Forced zero clear for using memcmp() at ccs_update_policy(). */
4388+ memset(&param.e, 0, sizeof(param.e));
4389+ if (ccs_str_starts(&param.data, "aggregator "))
4390+ return ccs_write_aggregator(&param);
4391+#ifdef CONFIG_CCSECURITY_PORTRESERVE
4392+ if (ccs_str_starts(&param.data, "deny_autobind "))
4393+ return ccs_write_reserved_port(&param);
4394+#endif
4395+ for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)
4396+ if (ccs_str_starts(&param.data, ccs_transition_type[i]))
4397+ return ccs_write_transition_control(&param, i);
4398+ for (i = 0; i < CCS_MAX_GROUP; i++)
4399+ if (ccs_str_starts(&param.data, ccs_group_name[i]))
4400+ return ccs_write_group(&param, i);
4401+ if (ccs_str_starts(&param.data, "acl_group ")) {
4402+ unsigned int group;
4403+ char *data;
4404+ group = simple_strtoul(param.data, &data, 10);
4405+ if (group < CCS_MAX_ACL_GROUPS && *data++ == ' ')
4406+ return ccs_write_acl(head->w.ns,
4407+ &head->w.ns->acl_group[group],
4408+ data, is_delete);
4409+ }
4410+ return -EINVAL;
4411+}
4412+
4413+/**
4414+ * ccs_read_group - Read "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
4415+ *
4416+ * @head: Pointer to "struct ccs_io_buffer".
4417+ * @idx: Index number.
4418+ *
4419+ * Returns true on success, false otherwise.
4420+ *
4421+ * Caller holds ccs_read_lock().
4422+ */
4423+static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)
4424+{
4425+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
4426+ namespace_list);
4427+ struct list_head *list = &ns->group_list[idx];
4428+ list_for_each_cookie(head->r.group, list) {
4429+ struct ccs_group *group =
4430+ list_entry(head->r.group, typeof(*group), head.list);
4431+ list_for_each_cookie(head->r.acl, &group->member_list) {
4432+ struct ccs_acl_head *ptr =
4433+ list_entry(head->r.acl, typeof(*ptr), list);
4434+ if (ptr->is_deleted)
4435+ continue;
4436+ if (!ccs_flush(head))
4437+ return false;
4438+ ccs_print_namespace(head);
4439+ ccs_set_string(head, ccs_group_name[idx]);
4440+ ccs_set_string(head, group->group_name->name);
4441+ if (idx == CCS_PATH_GROUP) {
4442+ ccs_set_space(head);
4443+ ccs_set_string(head, container_of
4444+ (ptr, struct ccs_path_group,
4445+ head)->member_name->name);
4446+ } else if (idx == CCS_NUMBER_GROUP) {
4447+ ccs_print_number_union(head, &container_of
4448+ (ptr, struct ccs_number_group,
4449+ head)->number);
4450+#ifdef CONFIG_CCSECURITY_NETWORK
4451+ } else if (idx == CCS_ADDRESS_GROUP) {
4452+ char buffer[128];
4453+ struct ccs_address_group *member =
4454+ container_of(ptr, typeof(*member),
4455+ head);
4456+ ccs_print_ip(buffer, sizeof(buffer),
4457+ &member->address);
4458+ ccs_io_printf(head, " %s", buffer);
4459+#endif
4460+ }
4461+ ccs_set_lf(head);
4462+ }
4463+ head->r.acl = NULL;
4464+ }
4465+ head->r.group = NULL;
4466+ return true;
4467+}
4468+
4469+/**
4470+ * ccs_read_policy - Read "struct ccs_..._entry" list.
4471+ *
4472+ * @head: Pointer to "struct ccs_io_buffer".
4473+ * @idx: Index number.
4474+ *
4475+ * Returns true on success, false otherwise.
4476+ *
4477+ * Caller holds ccs_read_lock().
4478+ */
4479+static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)
4480+{
4481+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
4482+ namespace_list);
4483+ struct list_head *list = &ns->policy_list[idx];
4484+ list_for_each_cookie(head->r.acl, list) {
4485+ struct ccs_acl_head *acl =
4486+ container_of(head->r.acl, typeof(*acl), list);
4487+ if (acl->is_deleted)
4488+ continue;
4489+ if (head->r.print_transition_related_only &&
4490+ idx != CCS_ID_TRANSITION_CONTROL)
4491+ continue;
4492+ if (!ccs_flush(head))
4493+ return false;
4494+ switch (idx) {
4495+ case CCS_ID_TRANSITION_CONTROL:
4496+ {
4497+ struct ccs_transition_control *ptr =
4498+ container_of(acl, typeof(*ptr), head);
4499+ ccs_print_namespace(head);
4500+ ccs_set_string(head,
4501+ ccs_transition_type[ptr->type]);
4502+ ccs_set_string(head, ptr->program ?
4503+ ptr->program->name : "any");
4504+ ccs_set_string(head, " from ");
4505+ ccs_set_string(head, ptr->domainname ?
4506+ ptr->domainname->name : "any");
4507+ }
4508+ break;
4509+ case CCS_ID_AGGREGATOR:
4510+ {
4511+ struct ccs_aggregator *ptr =
4512+ container_of(acl, typeof(*ptr), head);
4513+ ccs_print_namespace(head);
4514+ ccs_set_string(head, "aggregator ");
4515+ ccs_set_string(head, ptr->original_name->name);
4516+ ccs_set_space(head);
4517+ ccs_set_string(head,
4518+ ptr->aggregated_name->name);
4519+ }
4520+ break;
4521+#ifdef CONFIG_CCSECURITY_PORTRESERVE
4522+ case CCS_ID_RESERVEDPORT:
4523+ {
4524+ struct ccs_reserved *ptr =
4525+ container_of(acl, typeof(*ptr), head);
4526+ ccs_print_namespace(head);
4527+ ccs_set_string(head, "deny_autobind ");
4528+ ccs_print_number_union_nospace(head,
4529+ &ptr->port);
4530+ }
4531+ break;
4532+#endif
4533+ default:
4534+ continue;
4535+ }
4536+ ccs_set_lf(head);
4537+ }
4538+ head->r.acl = NULL;
4539+ return true;
4540+}
4541+
4542+/**
4543+ * ccs_read_exception - Read exception policy.
4544+ *
4545+ * @head: Pointer to "struct ccs_io_buffer".
4546+ *
4547+ * Returns nothing.
4548+ *
4549+ * Caller holds ccs_read_lock().
4550+ */
4551+static void ccs_read_exception(struct ccs_io_buffer *head)
4552+{
4553+ struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
4554+ namespace_list);
4555+ if (head->r.eof)
4556+ return;
4557+ while (head->r.step < CCS_MAX_POLICY &&
4558+ ccs_read_policy(head, head->r.step))
4559+ head->r.step++;
4560+ if (head->r.step < CCS_MAX_POLICY)
4561+ return;
4562+ while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP &&
4563+ ccs_read_group(head, head->r.step - CCS_MAX_POLICY))
4564+ head->r.step++;
4565+ if (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP)
4566+ return;
4567+ while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP
4568+ + CCS_MAX_ACL_GROUPS) {
4569+ head->r.acl_group_index =
4570+ head->r.step - CCS_MAX_POLICY - CCS_MAX_GROUP;
4571+ if (!ccs_read_acl(head, &ns->acl_group
4572+ [head->r.acl_group_index]))
4573+ return;
4574+ head->r.step++;
4575+ }
4576+ head->r.eof = true;
4577+}
4578+
4579+/**
4580+ * ccs_truncate - Truncate a line.
4581+ *
4582+ * @str: String to truncate.
4583+ *
4584+ * Returns length of truncated @str.
4585+ */
4586+static int ccs_truncate(char *str)
4587+{
4588+ char *start = str;
4589+ while (*(unsigned char *) str > (unsigned char) ' ')
4590+ str++;
4591+ *str = '\0';
4592+ return strlen(start) + 1;
4593+}
4594+
4595+/**
4596+ * ccs_add_entry - Add an ACL to current thread's domain. Used by learning mode.
4597+ *
4598+ * @header: Lines containing ACL.
4599+ *
4600+ * Returns nothing.
4601+ */
4602+static void ccs_add_entry(char *header)
4603+{
4604+ char *buffer;
4605+ char *realpath = NULL;
4606+ char *argv0 = NULL;
4607+ char *symlink = NULL;
4608+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4609+ char *handler;
4610+#endif
4611+ char *cp = strchr(header, '\n');
4612+ int len;
4613+ if (!cp)
4614+ return;
4615+ cp = strchr(cp + 1, '\n');
4616+ if (!cp)
4617+ return;
4618+ *cp++ = '\0';
4619+ len = strlen(cp) + 1;
4620+ /* strstr() will return NULL if ordering is wrong. */
4621+ if (*cp == 'f') {
4622+ argv0 = strstr(header, " argv[]={ \"");
4623+ if (argv0) {
4624+ argv0 += 10;
4625+ len += ccs_truncate(argv0) + 14;
4626+ }
4627+ realpath = strstr(header, " exec={ realpath=\"");
4628+ if (realpath) {
4629+ realpath += 8;
4630+ len += ccs_truncate(realpath) + 6;
4631+ }
4632+ symlink = strstr(header, " symlink.target=\"");
4633+ if (symlink)
4634+ len += ccs_truncate(symlink + 1) + 1;
4635+ }
4636+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4637+ handler = strstr(header, "type=execute_handler");
4638+ if (handler)
4639+ len += ccs_truncate(handler) + 6;
4640+#endif
4641+ buffer = kmalloc(len, CCS_GFP_FLAGS);
4642+ if (!buffer)
4643+ return;
4644+ snprintf(buffer, len - 1, "%s", cp);
4645+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4646+ if (handler)
4647+ ccs_addprintf(buffer, len, " task.%s", handler);
4648+#endif
4649+ if (realpath)
4650+ ccs_addprintf(buffer, len, " exec.%s", realpath);
4651+ if (argv0)
4652+ ccs_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
4653+ if (symlink)
4654+ ccs_addprintf(buffer, len, "%s", symlink);
4655+ ccs_normalize_line(buffer);
4656+ {
4657+ struct ccs_domain_info *domain = ccs_current_domain();
4658+ if (!ccs_write_acl(domain->ns, &domain->acl_info_list,
4659+ buffer, false))
4660+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
4661+ }
4662+ kfree(buffer);
4663+}
4664+
4665+/**
4666+ * ccs_domain_quota_ok - Check for domain's quota.
4667+ *
4668+ * @r: Pointer to "struct ccs_request_info".
4669+ *
4670+ * Returns true if the domain is not exceeded quota, false otherwise.
4671+ *
4672+ * Caller holds ccs_read_lock().
4673+ */
4674+static bool ccs_domain_quota_ok(struct ccs_request_info *r)
4675+{
4676+ unsigned int count = 0;
4677+ struct ccs_domain_info * const domain = ccs_current_domain();
4678+ struct ccs_acl_info *ptr;
4679+ if (r->mode != CCS_CONFIG_LEARNING)
4680+ return false;
4681+ if (!domain)
4682+ return true;
4683+ list_for_each_entry_srcu(ptr, &domain->acl_info_list, list, &ccs_ss) {
4684+ u16 perm;
4685+ u8 i;
4686+ if (ptr->is_deleted)
4687+ continue;
4688+ switch (ptr->type) {
4689+ case CCS_TYPE_PATH_ACL:
4690+ case CCS_TYPE_PATH2_ACL:
4691+ case CCS_TYPE_PATH_NUMBER_ACL:
4692+ case CCS_TYPE_MKDEV_ACL:
4693+#ifdef CONFIG_CCSECURITY_NETWORK
4694+ case CCS_TYPE_INET_ACL:
4695+ case CCS_TYPE_UNIX_ACL:
4696+#endif
4697+ perm = ptr->perm;
4698+ break;
4699+#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
4700+ case CCS_TYPE_AUTO_EXECUTE_HANDLER:
4701+ case CCS_TYPE_DENIED_EXECUTE_HANDLER:
4702+#endif
4703+#ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
4704+ case CCS_TYPE_AUTO_TASK_ACL:
4705+ case CCS_TYPE_MANUAL_TASK_ACL:
4706+#endif
4707+ perm = 0;
4708+ break;
4709+ default:
4710+ perm = 1;
4711+ }
4712+ for (i = 0; i < 16; i++)
4713+ if (perm & (1 << i))
4714+ count++;
4715+ }
4716+ if (count < ccs_profile(r->profile)->pref[CCS_PREF_MAX_LEARNING_ENTRY])
4717+ return true;
4718+ if (!domain->flags[CCS_DIF_QUOTA_WARNED]) {
4719+ domain->flags[CCS_DIF_QUOTA_WARNED] = true;
4720+ /* r->granted = false; */
4721+ ccs_write_log(r, "%s", ccs_dif[CCS_DIF_QUOTA_WARNED]);
4722+ printk(KERN_WARNING "WARNING: "
4723+ "Domain '%s' has too many ACLs to hold. "
4724+ "Stopped learning mode.\n", domain->domainname->name);
4725+ }
4726+ return false;
4727+}
4728+
4729+/**
4730+ * ccs_supervisor - Ask for the supervisor's decision.
4731+ *
4732+ * @r: Pointer to "struct ccs_request_info".
4733+ * @fmt: The printf()'s format string, followed by parameters.
4734+ *
4735+ * Returns 0 if the supervisor decided to permit the access request which
4736+ * violated the policy in enforcing mode, CCS_RETRY_REQUEST if the supervisor
4737+ * decided to retry the access request which violated the policy in enforcing
4738+ * mode, 0 if it is not in enforcing mode, -EPERM otherwise.
4739+ */
4740+static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
4741+{
4742+ va_list args;
4743+ int error;
4744+ int len;
4745+ static unsigned int ccs_serial;
4746+ struct ccs_query entry = { };
4747+ bool quota_exceeded = false;
4748+ va_start(args, fmt);
4749+ len = vsnprintf((char *) &len, 1, fmt, args) + 1;
4750+ va_end(args);
4751+ /* Write /proc/ccs/audit. */
4752+ va_start(args, fmt);
4753+ ccs_write_log2(r, len, fmt, args);
4754+ va_end(args);
4755+ /* Nothing more to do if granted. */
4756+ if (r->granted)
4757+ return 0;
4758+ if (r->mode)
4759+ ccs_update_stat(r->mode);
4760+ switch (r->mode) {
4761+ int i;
4762+ struct ccs_profile *p;
4763+ case CCS_CONFIG_ENFORCING:
4764+ error = -EPERM;
4765+ if (atomic_read(&ccs_query_observers))
4766+ break;
4767+ if (r->dont_sleep_on_enforce_error)
4768+ goto out;
4769+ p = ccs_profile(r->profile);
4770+ /* Check enforcing_penalty parameter. */
4771+ for (i = 0; i < p->pref[CCS_PREF_ENFORCING_PENALTY]; i++) {
4772+ set_current_state(TASK_INTERRUPTIBLE);
4773+ schedule_timeout(HZ / 10);
4774+ }
4775+ goto out;
4776+ case CCS_CONFIG_LEARNING:
4777+ error = 0;
4778+ /* Check max_learning_entry parameter. */
4779+ if (ccs_domain_quota_ok(r))
4780+ break;
4781+ /* fall through */
4782+ default:
4783+ return 0;
4784+ }
4785+ /* Get message. */
4786+ va_start(args, fmt);
4787+ entry.query = ccs_init_log(r, len, fmt, args);
4788+ va_end(args);
4789+ if (!entry.query)
4790+ goto out;
4791+ entry.query_len = strlen(entry.query) + 1;
4792+ if (!error) {
4793+ ccs_add_entry(entry.query);
4794+ goto out;
4795+ }
4796+ len = ccs_round2(entry.query_len);
4797+ entry.domain = ccs_current_domain();
4798+ spin_lock(&ccs_query_list_lock);
4799+ if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
4800+ ccs_memory_used[CCS_MEMORY_QUERY] + len
4801+ >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
4802+ quota_exceeded = true;
4803+ } else {
4804+ entry.serial = ccs_serial++;
4805+ entry.retry = r->retry;
4806+ ccs_memory_used[CCS_MEMORY_QUERY] += len;
4807+ list_add_tail(&entry.list, &ccs_query_list);
4808+ }
4809+ spin_unlock(&ccs_query_list_lock);
4810+ if (quota_exceeded)
4811+ goto out;
4812+ /* Give 10 seconds for supervisor's opinion. */
4813+ while (entry.timer < 10) {
4814+ wake_up_all(&ccs_query_wait);
4815+ if (wait_event_interruptible_timeout
4816+ (ccs_answer_wait, entry.answer ||
4817+ !atomic_read(&ccs_query_observers), HZ))
4818+ break;
4819+ else
4820+ entry.timer++;
4821+ }
4822+ spin_lock(&ccs_query_list_lock);
4823+ list_del(&entry.list);
4824+ ccs_memory_used[CCS_MEMORY_QUERY] -= len;
4825+ spin_unlock(&ccs_query_list_lock);
4826+ switch (entry.answer) {
4827+ case 3: /* Asked to retry by administrator. */
4828+ error = CCS_RETRY_REQUEST;
4829+ r->retry++;
4830+ break;
4831+ case 1:
4832+ /* Granted by administrator. */
4833+ error = 0;
4834+ break;
4835+ default:
4836+ /* Timed out or rejected by administrator. */
4837+ break;
4838+ }
4839+out:
4840+ kfree(entry.query);
4841+ return error;
4842+}
4843+
4844+/**
4845+ * ccs_audit_log - Audit permission check log.
4846+ *
4847+ * @r: Pointer to "struct ccs_request_info".
4848+ *
4849+ * Returns return value of ccs_supervisor().
4850+ */
4851+int ccs_audit_log(struct ccs_request_info *r)
4852+{
4853+ switch (r->param_type) {
4854+ u8 type;
4855+ char buf[48];
4856+#ifdef CONFIG_CCSECURITY_NETWORK
4857+ const u32 *address;
4858+#endif
4859+ case CCS_TYPE_PATH_ACL:
4860+ return ccs_supervisor(r, "file %s %s\n", ccs_path_keyword
4861+ [r->param.path.operation],
4862+ r->param.path.filename->name);
4863+ case CCS_TYPE_PATH2_ACL:
4864+ return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords
4865+ [ccs_pp2mac[r->param.path2.operation]],
4866+ r->param.path2.filename1->name,
4867+ r->param.path2.filename2->name);
4868+ case CCS_TYPE_PATH_NUMBER_ACL:
4869+ type = r->param.path_number.operation;
4870+ switch (type) {
4871+ case CCS_TYPE_CREATE:
4872+ case CCS_TYPE_MKDIR:
4873+ case CCS_TYPE_MKFIFO:
4874+ case CCS_TYPE_MKSOCK:
4875+ case CCS_TYPE_CHMOD:
4876+ snprintf(buf, sizeof(buf), "0%lo",
4877+ r->param.path_number.number);
4878+ break;
4879+ case CCS_TYPE_IOCTL:
4880+ snprintf(buf, sizeof(buf), "0x%lX",
4881+ r->param.path_number.number);
4882+ break;
4883+ default:
4884+ snprintf(buf, sizeof(buf), "%lu",
4885+ r->param.path_number.number);
4886+ break;
4887+ }
4888+ return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords
4889+ [ccs_pn2mac[type]],
4890+ r->param.path_number.filename->name,
4891+ buf);
4892+ case CCS_TYPE_MKDEV_ACL:
4893+ return ccs_supervisor(r, "file %s %s 0%o %u %u\n",
4894+ ccs_mac_keywords
4895+ [ccs_pnnn2mac[r->param.mkdev.operation]],
4896+ r->param.mkdev.filename->name,
4897+ r->param.mkdev.mode,
4898+ r->param.mkdev.major,
4899+ r->param.mkdev.minor);
4900+ case CCS_TYPE_MOUNT_ACL:
4901+ return ccs_supervisor(r, "file mount %s %s %s 0x%lX\n",
4902+ r->param.mount.dev->name,
4903+ r->param.mount.dir->name,
4904+ r->param.mount.type->name,
4905+ r->param.mount.flags);
4906+#ifdef CONFIG_CCSECURITY_MISC
4907+ case CCS_TYPE_ENV_ACL:
4908+ return ccs_supervisor(r, "misc env %s\n",
4909+ r->param.environ.name->name);
4910+#endif
4911+#ifdef CONFIG_CCSECURITY_CAPABILITY
4912+ case CCS_TYPE_CAPABILITY_ACL:
4913+ return ccs_supervisor(r, "capability %s\n", ccs_mac_keywords
4914+ [ccs_c2mac[r->param.capability.
4915+ operation]]);
4916+#endif
4917+#ifdef CONFIG_CCSECURITY_NETWORK
4918+ case CCS_TYPE_INET_ACL:
4919+ address = r->param.inet_network.address;
4920+ if (r->param.inet_network.is_ipv6)
4921+ ccs_print_ipv6(buf, sizeof(buf),
4922+ (const struct in6_addr *) address);
4923+ else
4924+ ccs_print_ipv4(buf, sizeof(buf), address);
4925+ return ccs_supervisor(r, "network inet %s %s %s %u\n",
4926+ ccs_proto_keyword[r->param.inet_network.
4927+ protocol],
4928+ ccs_socket_keyword[r->param.inet_network.
4929+ operation],
4930+ buf, r->param.inet_network.port);
4931+ case CCS_TYPE_UNIX_ACL:
4932+ return ccs_supervisor(r, "network unix %s %s %s\n",
4933+ ccs_proto_keyword[r->param.
4934+ unix_network.protocol],
4935+ ccs_socket_keyword[r->param.unix_network.
4936+ operation],
4937+ r->param.unix_network.address->name);
4938+#endif
4939+#ifdef CONFIG_CCSECURITY_IPC
4940+ case CCS_TYPE_SIGNAL_ACL:
4941+ return ccs_supervisor(r, "ipc signal %d %s\n",
4942+ r->param.signal.sig,
4943+ r->param.signal.dest_pattern);
4944+#endif
4945+ }
4946+ return 0;
4947+}
4948+
4949+/**
4950+ * ccs_find_domain_by_qid - Get domain by query id.
4951+ *
4952+ * @serial: Query ID assigned by ccs_supervisor().
4953+ *
4954+ * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
4955+ */
4956+static struct ccs_domain_info *ccs_find_domain_by_qid(unsigned int serial)
4957+{
4958+ struct ccs_query *ptr;
4959+ struct ccs_domain_info *domain = NULL;
4960+ spin_lock(&ccs_query_list_lock);
4961+ list_for_each_entry(ptr, &ccs_query_list, list) {
4962+ if (ptr->serial != serial)
4963+ continue;
4964+ domain = ptr->domain;
4965+ break;
4966+ }
4967+ spin_unlock(&ccs_query_list_lock);
4968+ return domain;
4969+}
4970+
4971+/**
4972+ * ccs_read_query - Read access requests which violated policy in enforcing mode.
4973+ *
4974+ * @head: Pointer to "struct ccs_io_buffer".
4975+ *
4976+ * Returns nothing.
4977+ */
4978+static void ccs_read_query(struct ccs_io_buffer *head)
4979+{
4980+ struct list_head *tmp;
4981+ unsigned int pos = 0;
4982+ size_t len = 0;
4983+ char *buf;
4984+ if (head->r.w_pos)
4985+ return;
4986+ kfree(head->read_buf);
4987+ head->read_buf = NULL;
4988+ spin_lock(&ccs_query_list_lock);
4989+ list_for_each(tmp, &ccs_query_list) {
4990+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
4991+ if (pos++ != head->r.query_index)
4992+ continue;
4993+ len = ptr->query_len;
4994+ break;
4995+ }
4996+ spin_unlock(&ccs_query_list_lock);
4997+ if (!len) {
4998+ head->r.query_index = 0;
4999+ return;
5000+ }
5001+ buf = kzalloc(len + 32, CCS_GFP_FLAGS);
5002+ if (!buf)
5003+ return;
5004+ pos = 0;
5005+ spin_lock(&ccs_query_list_lock);
5006+ list_for_each(tmp, &ccs_query_list) {
5007+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
5008+ if (pos++ != head->r.query_index)
5009+ continue;
5010+ /*
5011+ * Some query can be skipped because ccs_query_list
5012+ * can change, but I don't care.
5013+ */
5014+ if (len == ptr->query_len)
5015+ snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
5016+ ptr->retry, ptr->query);
5017+ break;
5018+ }
5019+ spin_unlock(&ccs_query_list_lock);
5020+ if (buf[0]) {
5021+ head->read_buf = buf;
5022+ head->r.w[head->r.w_pos++] = buf;
5023+ head->r.query_index++;
5024+ } else {
5025+ kfree(buf);
5026+ }
5027+}
5028+
5029+/**
5030+ * ccs_write_answer - Write the supervisor's decision.
5031+ *
5032+ * @head: Pointer to "struct ccs_io_buffer".
5033+ *
5034+ * Returns 0 on success, -EINVAL otherwise.
5035+ */
5036+static int ccs_write_answer(struct ccs_io_buffer *head)
5037+{
5038+ char *data = head->write_buf;
5039+ struct list_head *tmp;
5040+ unsigned int serial;
5041+ unsigned int answer;
5042+ spin_lock(&ccs_query_list_lock);
5043+ list_for_each(tmp, &ccs_query_list) {
5044+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
5045+ ptr->timer = 0;
5046+ }
5047+ spin_unlock(&ccs_query_list_lock);
5048+ if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
5049+ return -EINVAL;
5050+ spin_lock(&ccs_query_list_lock);
5051+ list_for_each(tmp, &ccs_query_list) {
5052+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
5053+ if (ptr->serial != serial)
5054+ continue;
5055+ ptr->answer = (u8) answer;
5056+ /* Remove from ccs_query_list. */
5057+ if (ptr->answer) {
5058+ list_del(&ptr->list);
5059+ INIT_LIST_HEAD(&ptr->list);
5060+ }
5061+ break;
5062+ }
5063+ spin_unlock(&ccs_query_list_lock);
5064+ wake_up_all(&ccs_answer_wait);
5065+ return 0;
5066+}
5067+
5068+/**
5069+ * ccs_read_version - Get version.
5070+ *
5071+ * @head: Pointer to "struct ccs_io_buffer".
5072+ *
5073+ * Returns nothing.
5074+ */
5075+static void ccs_read_version(struct ccs_io_buffer *head)
5076+{
5077+ if (head->r.eof)
5078+ return;
5079+ ccs_set_string(head, "1.8.3");
5080+ head->r.eof = true;
5081+}
5082+
5083+/**
5084+ * ccs_update_stat - Update statistic counters.
5085+ *
5086+ * @index: Index for policy type.
5087+ *
5088+ * Returns nothing.
5089+ */
5090+static void ccs_update_stat(const u8 index)
5091+{
5092+ struct timeval tv;
5093+ do_gettimeofday(&tv);
5094+ /*
5095+ * I don't use atomic operations because race condition is not fatal.
5096+ */
5097+ ccs_stat_updated[index]++;
5098+ ccs_stat_modified[index] = tv.tv_sec;
5099+}
5100+
5101+/**
5102+ * ccs_read_stat - Read statistic data.
5103+ *
5104+ * @head: Pointer to "struct ccs_io_buffer".
5105+ *
5106+ * Returns nothing.
5107+ */
5108+static void ccs_read_stat(struct ccs_io_buffer *head)
5109+{
5110+ u8 i;
5111+ unsigned int total = 0;
5112+ if (head->r.eof)
5113+ return;
5114+ for (i = 0; i < CCS_MAX_POLICY_STAT; i++) {
5115+ ccs_io_printf(head, "Policy %-30s %10u", ccs_policy_headers[i],
5116+ ccs_stat_updated[i]);
5117+ if (ccs_stat_modified[i]) {
5118+ struct ccs_time stamp;
5119+ ccs_convert_time(ccs_stat_modified[i], &stamp);
5120+ ccs_io_printf(head, " (Last: %04u/%02u/%02u "
5121+ "%02u:%02u:%02u)",
5122+ stamp.year, stamp.month, stamp.day,
5123+ stamp.hour, stamp.min, stamp.sec);
5124+ }
5125+ ccs_set_lf(head);
5126+ }
5127+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++) {
5128+ unsigned int used = ccs_memory_used[i];
5129+ total += used;
5130+ ccs_io_printf(head, "Memory used by %-22s %10u",
5131+ ccs_memory_headers[i], used);
5132+ used = ccs_memory_quota[i];
5133+ if (used

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

Show on old repository browser