• R/O
  • SSH
  • HTTPS

akari: Commit


Commit MetaInfo

Revision197 (tree)
Zeit2011-04-11 17:21:49
Autorkumaneko

Log Message

1.0.12

Ändern Zusammenfassung

Diff

--- tags/patches/1.0.12/README (nonexistent)
+++ tags/patches/1.0.12/README (revision 197)
@@ -0,0 +1,117 @@
1+Notes for AKARI project
2+
3+AKARI is Access Keeping And Regulating Instrument for Linux 2.6 kernels.
4+
5+You can use AKARI for analyzing your system's behavior (i.e. reports which
6+application accesses which resources like strace command does) and optionally
7+restricting your system's behavior (i.e. controls which application can
8+access which resources like TOMOYO/AppArmor does).
9+
10+AKARI is forked from TOMOYO 1.8 and made as a LKM (loadable kernel module)
11+so that you don't need to replace your kernels installed in your system.
12+
13+This patch is released under the GPLv2.
14+
15+Project URL: http://akari.sourceforge.jp/
16+
17+ChangeLog:
18+
19+Version 1.0 2010/10/10 First release.
20+
21+Version 1.0.1 2010/10/18 Minor update release.
22+
23+ Synchronize with TOMOYO revision 4069.
24+
25+ Fix off-by-two in ccs_check_unix_address().
26+
27+ Implement post accept() LSM hook.
28+
29+Version 1.0.2 2010/10/25 Minor update release.
30+
31+ Synchronize with TOMOYO revision 4090.
32+
33+ Add getattr() and readdir() checks.
34+
35+ Use "YYYY/MM/DD hh:mm:ss" format for /proc/ccs/ interface.
36+
37+ Do not automatically add / for umount().
38+
39+Version 1.0.3 2010/11/01 Minor update release.
40+
41+ Synchronize with TOMOYO revision 4104.
42+
43+ Fix pathname handling in ccs_unix_entry().
44+
45+Version 1.0.4 2010/11/11 Minor update release.
46+
47+ Synchronize with TOMOYO 1.8.0 release.
48+
49+ Add sysctl() check for 2.6.21 to 2.6.32 kernels.
50+
51+ Fix double new_decode_dev() bug for mknod().
52+
53+ Fix keyword typo.
54+
55+ Fix build failure on some kernels.
56+
57+ Changed pathname prefix priority.
58+
59+ Use hash table for faster scan.
60+
61+ Updated function comments.
62+
63+Version 1.0.5 2010/11/22 Minor update release.
64+
65+ Make ccs_domain_info/ccs_flags inheritable for 2.6.29 and later kernels.
66+
67+Version 1.0.6 2010/12/31 Minor update release.
68+
69+ Synchronize with TOMOYO revision 4280.
70+
71+ Use same interface for audit logs.
72+
73+ Split ccs_null_security into ccs_default_security and ccs_oom_security.
74+
75+Version 1.0.7 2011/01/21 Minor update release.
76+
77+ Synchronize with TOMOYO revision 4400.
78+
79+ Use filesystem name for unnamed devices when vfsmount is missing.
80+
81+Version 1.0.8 2011/02/07 Minor update release.
82+
83+ Synchronize with TOMOYO revision 4545.
84+
85+ Fix infinite loop bug when reading /proc/ccs/audit or /proc/ccs/query .
86+
87+Version 1.0.9 2011/02/14 Minor update release.
88+
89+ Fix missing permission check for interpreters in 2.6.30 and later kernels.
90+
91+Version 1.0.10 2011/02/15 Minor update release.
92+
93+ Fix missing permission check for interpreters in 2.6.23 and earlier kernels.
94+
95+ Fix wrong execute permission check and domain transition in 2.6.28 and earlier kernels.
96+
97+Version 1.0.11 2010/04/01 Minor update release.
98+
99+ Synchronize with TOMOYO 1.8.1 release.
100+
101+ Run garbage collector without waiting for /proc/ccs/ users.
102+
103+ Support built-in policy configuration.
104+
105+ Remove /proc/ccs/meminfo interface.
106+
107+ Pack policy when printing via /proc/ccs/ interface.
108+
109+ Fix conditional policy parsing.
110+
111+ Serialize updating profile's comment line.
112+
113+Version 1.0.12 2011/04/11 Minor update release.
114+
115+ Synchronize with TOMOYO revision 4874.
116+
117+ Fix fcntl(F_SETFL, O_APPEND) handling.
--- tags/patches/1.0.12/file.c (nonexistent)
+++ tags/patches/1.0.12/file.c (revision 197)
@@ -0,0 +1,1648 @@
1+/*
2+ * security/ccsecurity/file.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1+ 2011/04/11
7+ */
8+
9+#include "internal.h"
10+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
11+
12+/*
13+ * may_open() receives open flags modified by open_to_namei_flags() until
14+ * 2.6.32. We stop here in case some distributions backported ACC_MODE changes,
15+ * for we can't determine whether may_open() receives open flags modified by
16+ * open_to_namei_flags() or not.
17+ */
18+#ifdef ACC_MODE
19+#error ACC_MODE already defined.
20+#endif
21+#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
22+
23+#if defined(RHEL_MAJOR) && RHEL_MAJOR == 6
24+/* RHEL6 passes unmodified flags since 2.6.32-71.14.1.el6 . */
25+#undef ACC_MODE
26+#define ACC_MODE(x) ("\004\002\006"[(x)&O_ACCMODE])
27+#endif
28+
29+#endif
30+
31+/* Mapping table from "enum ccs_path_acl_index" to "enum ccs_mac_index". */
32+static const u8 ccs_p2mac[CCS_MAX_PATH_OPERATION] = {
33+ [CCS_TYPE_EXECUTE] = CCS_MAC_FILE_EXECUTE,
34+ [CCS_TYPE_READ] = CCS_MAC_FILE_OPEN,
35+ [CCS_TYPE_WRITE] = CCS_MAC_FILE_OPEN,
36+ [CCS_TYPE_APPEND] = CCS_MAC_FILE_OPEN,
37+ [CCS_TYPE_UNLINK] = CCS_MAC_FILE_UNLINK,
38+ [CCS_TYPE_GETATTR] = CCS_MAC_FILE_GETATTR,
39+ [CCS_TYPE_RMDIR] = CCS_MAC_FILE_RMDIR,
40+ [CCS_TYPE_TRUNCATE] = CCS_MAC_FILE_TRUNCATE,
41+ [CCS_TYPE_SYMLINK] = CCS_MAC_FILE_SYMLINK,
42+ [CCS_TYPE_CHROOT] = CCS_MAC_FILE_CHROOT,
43+ [CCS_TYPE_UMOUNT] = CCS_MAC_FILE_UMOUNT,
44+};
45+
46+/* Mapping table from "enum ccs_mkdev_acl_index" to "enum ccs_mac_index". */
47+const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION] = {
48+ [CCS_TYPE_MKBLOCK] = CCS_MAC_FILE_MKBLOCK,
49+ [CCS_TYPE_MKCHAR] = CCS_MAC_FILE_MKCHAR,
50+};
51+
52+/* Mapping table from "enum ccs_path2_acl_index" to "enum ccs_mac_index". */
53+const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION] = {
54+ [CCS_TYPE_LINK] = CCS_MAC_FILE_LINK,
55+ [CCS_TYPE_RENAME] = CCS_MAC_FILE_RENAME,
56+ [CCS_TYPE_PIVOT_ROOT] = CCS_MAC_FILE_PIVOT_ROOT,
57+};
58+
59+/*
60+ * Mapping table from "enum ccs_path_number_acl_index" to "enum ccs_mac_index".
61+ */
62+const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION] = {
63+ [CCS_TYPE_CREATE] = CCS_MAC_FILE_CREATE,
64+ [CCS_TYPE_MKDIR] = CCS_MAC_FILE_MKDIR,
65+ [CCS_TYPE_MKFIFO] = CCS_MAC_FILE_MKFIFO,
66+ [CCS_TYPE_MKSOCK] = CCS_MAC_FILE_MKSOCK,
67+ [CCS_TYPE_IOCTL] = CCS_MAC_FILE_IOCTL,
68+ [CCS_TYPE_CHMOD] = CCS_MAC_FILE_CHMOD,
69+ [CCS_TYPE_CHOWN] = CCS_MAC_FILE_CHOWN,
70+ [CCS_TYPE_CHGRP] = CCS_MAC_FILE_CHGRP,
71+};
72+
73+/**
74+ * ccs_put_name_union - Drop reference on "struct ccs_name_union".
75+ *
76+ * @ptr: Pointer to "struct ccs_name_union".
77+ *
78+ * Returns nothing.
79+ */
80+void ccs_put_name_union(struct ccs_name_union *ptr)
81+{
82+ if (!ptr)
83+ return;
84+ if (ptr->is_group)
85+ ccs_put_group(ptr->group);
86+ else
87+ ccs_put_name(ptr->filename);
88+}
89+
90+/**
91+ * ccs_put_name_union - Drop reference on "struct ccs_number_union".
92+ *
93+ * @ptr: Pointer to "struct ccs_number_union".
94+ *
95+ * Returns nothing.
96+ */
97+void ccs_put_number_union(struct ccs_number_union *ptr)
98+{
99+ if (ptr && ptr->is_group)
100+ ccs_put_group(ptr->group);
101+}
102+
103+/**
104+ * ccs_compare_number_union - Check whether a value matches "struct ccs_number_union" or not.
105+ *
106+ * @value: Number to check.
107+ * @ptr: Pointer to "struct ccs_number_union".
108+ *
109+ * Returns true if @value matches @ptr, false otherwise.
110+ */
111+bool ccs_compare_number_union(const unsigned long value,
112+ const struct ccs_number_union *ptr)
113+{
114+ if (ptr->is_group)
115+ return ccs_number_matches_group(value, value, ptr->group);
116+ return value >= ptr->values[0] && value <= ptr->values[1];
117+}
118+
119+/**
120+ * ccs_compare_name_union - Check whether a name matches "struct ccs_name_union" or not.
121+ *
122+ * @name: Pointer to "struct ccs_path_info".
123+ * @ptr: Pointer to "struct ccs_name_union".
124+ *
125+ * Returns "struct ccs_path_info" if @name matches @ptr, NULL otherwise.
126+ */
127+const struct ccs_path_info *ccs_compare_name_union
128+(const struct ccs_path_info *name, const struct ccs_name_union *ptr)
129+{
130+ if (ptr->is_group)
131+ return ccs_path_matches_group(name, ptr->group);
132+ if (ccs_path_matches_pattern(name, ptr->filename))
133+ return ptr->filename;
134+ return NULL;
135+}
136+
137+/**
138+ * ccs_add_slash - Add trailing '/' if needed.
139+ *
140+ * @buf: Pointer to "struct ccs_path_info".
141+ *
142+ * Returns nothing.
143+ *
144+ * @buf must be generated by ccs_encode() because this function does not
145+ * allocate memory for adding '/'.
146+ */
147+static void ccs_add_slash(struct ccs_path_info *buf)
148+{
149+ if (buf->is_dir)
150+ return;
151+ /* This is OK because ccs_encode() reserves space for appending "/". */
152+ strcat((char *) buf->name, "/");
153+ ccs_fill_path_info(buf);
154+}
155+
156+/**
157+ * ccs_get_realpath - Get realpath.
158+ *
159+ * @buf: Pointer to "struct ccs_path_info".
160+ * @dentry: Pointer to "struct dentry".
161+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
162+ *
163+ * Returns true on success, false otherwise.
164+ */
165+static bool ccs_get_realpath(struct ccs_path_info *buf, struct dentry *dentry,
166+ struct vfsmount *mnt)
167+{
168+ struct path path = { mnt, dentry };
169+ buf->name = ccs_realpath_from_path(&path);
170+ if (buf->name) {
171+ ccs_fill_path_info(buf);
172+ return true;
173+ }
174+ return false;
175+}
176+
177+/**
178+ * ccs_audit_path_log - Audit path request log.
179+ *
180+ * @r: Pointer to "struct ccs_request_info".
181+ *
182+ * Returns 0 on success, negative value otherwise.
183+ */
184+static int ccs_audit_path_log(struct ccs_request_info *r)
185+{
186+ return ccs_supervisor(r, "file %s %s\n", ccs_path_keyword
187+ [r->param.path.operation],
188+ r->param.path.filename->name);
189+}
190+
191+/**
192+ * ccs_audit_path2_log - Audit path/path request log.
193+ *
194+ * @r: Pointer to "struct ccs_request_info".
195+ *
196+ * Returns 0 on success, negative value otherwise.
197+ */
198+static int ccs_audit_path2_log(struct ccs_request_info *r)
199+{
200+ return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords
201+ [ccs_pp2mac[r->param.path2.operation]],
202+ r->param.path2.filename1->name,
203+ r->param.path2.filename2->name);
204+}
205+
206+/**
207+ * ccs_audit_mkdev_log - Audit path/number/number/number request log.
208+ *
209+ * @r: Pointer to "struct ccs_request_info".
210+ *
211+ * Returns 0 on success, negative value otherwise.
212+ */
213+static int ccs_audit_mkdev_log(struct ccs_request_info *r)
214+{
215+ return ccs_supervisor(r, "file %s %s 0%o %u %u\n", ccs_mac_keywords
216+ [ccs_pnnn2mac[r->param.mkdev.operation]],
217+ r->param.mkdev.filename->name,
218+ r->param.mkdev.mode, r->param.mkdev.major,
219+ r->param.mkdev.minor);
220+}
221+
222+/**
223+ * ccs_audit_path_number_log - Audit path/number request log.
224+ *
225+ * @r: Pointer to "struct ccs_request_info".
226+ *
227+ * Returns 0 on success, negative value otherwise.
228+ */
229+static int ccs_audit_path_number_log(struct ccs_request_info *r)
230+{
231+ const u8 type = r->param.path_number.operation;
232+ u8 radix;
233+ char buffer[64];
234+ switch (type) {
235+ case CCS_TYPE_CREATE:
236+ case CCS_TYPE_MKDIR:
237+ case CCS_TYPE_MKFIFO:
238+ case CCS_TYPE_MKSOCK:
239+ case CCS_TYPE_CHMOD:
240+ radix = CCS_VALUE_TYPE_OCTAL;
241+ break;
242+ case CCS_TYPE_IOCTL:
243+ radix = CCS_VALUE_TYPE_HEXADECIMAL;
244+ break;
245+ default:
246+ radix = CCS_VALUE_TYPE_DECIMAL;
247+ break;
248+ }
249+ ccs_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
250+ radix);
251+ return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords
252+ [ccs_pn2mac[type]],
253+ r->param.path_number.filename->name, buffer);
254+}
255+
256+/**
257+ * ccs_check_path_acl - Check permission for path operation.
258+ *
259+ * @r: Pointer to "struct ccs_request_info".
260+ * @ptr: Pointer to "struct ccs_acl_info".
261+ *
262+ * Returns true if granted, false otherwise.
263+ *
264+ * To be able to use wildcard for domain transition, this function sets
265+ * matching entry on success. Since the caller holds ccs_read_lock(),
266+ * it is safe to set matching entry.
267+ */
268+static bool ccs_check_path_acl(struct ccs_request_info *r,
269+ const struct ccs_acl_info *ptr)
270+{
271+ const struct ccs_path_acl *acl = container_of(ptr, typeof(*acl), head);
272+ if (acl->perm & (1 << r->param.path.operation)) {
273+ r->param.path.matched_path =
274+ ccs_compare_name_union(r->param.path.filename,
275+ &acl->name);
276+ return r->param.path.matched_path != NULL;
277+ }
278+ return false;
279+}
280+
281+/**
282+ * ccs_check_path_number_acl - Check permission for path number operation.
283+ *
284+ * @r: Pointer to "struct ccs_request_info".
285+ * @ptr: Pointer to "struct ccs_acl_info".
286+ *
287+ * Returns true if granted, false otherwise.
288+ */
289+static bool ccs_check_path_number_acl(struct ccs_request_info *r,
290+ const struct ccs_acl_info *ptr)
291+{
292+ const struct ccs_path_number_acl *acl =
293+ container_of(ptr, typeof(*acl), head);
294+ return (acl->perm & (1 << r->param.path_number.operation)) &&
295+ ccs_compare_number_union(r->param.path_number.number,
296+ &acl->number) &&
297+ ccs_compare_name_union(r->param.path_number.filename,
298+ &acl->name);
299+}
300+
301+/**
302+ * ccs_check_path2_acl - Check permission for path path operation.
303+ *
304+ * @r: Pointer to "struct ccs_request_info".
305+ * @ptr: Pointer to "struct ccs_acl_info".
306+ *
307+ * Returns true if granted, false otherwise.
308+ */
309+static bool ccs_check_path2_acl(struct ccs_request_info *r,
310+ const struct ccs_acl_info *ptr)
311+{
312+ const struct ccs_path2_acl *acl =
313+ container_of(ptr, typeof(*acl), head);
314+ return (acl->perm & (1 << r->param.path2.operation)) &&
315+ ccs_compare_name_union(r->param.path2.filename1, &acl->name1)
316+ && ccs_compare_name_union(r->param.path2.filename2,
317+ &acl->name2);
318+}
319+
320+/**
321+ * ccs_check_cmkdev_acl - Check permission for path number number number operation.
322+ *
323+ * @r: Pointer to "struct ccs_request_info".
324+ * @ptr: Pointer to "struct ccs_acl_info".
325+ *
326+ * Returns true if granted, false otherwise.
327+ */
328+static bool ccs_check_mkdev_acl(struct ccs_request_info *r,
329+ const struct ccs_acl_info *ptr)
330+{
331+ const struct ccs_mkdev_acl *acl =
332+ container_of(ptr, typeof(*acl), head);
333+ return (acl->perm & (1 << r->param.mkdev.operation)) &&
334+ ccs_compare_number_union(r->param.mkdev.mode, &acl->mode) &&
335+ ccs_compare_number_union(r->param.mkdev.major, &acl->major) &&
336+ ccs_compare_number_union(r->param.mkdev.minor, &acl->minor) &&
337+ ccs_compare_name_union(r->param.mkdev.filename, &acl->name);
338+}
339+
340+/**
341+ * ccs_same_path_acl - Check for duplicated "struct ccs_path_acl" entry.
342+ *
343+ * @a: Pointer to "struct ccs_acl_info".
344+ * @b: Pointer to "struct ccs_acl_info".
345+ *
346+ * Returns true if @a == @b except permission bits, false otherwise.
347+ */
348+static bool ccs_same_path_acl(const struct ccs_acl_info *a,
349+ const struct ccs_acl_info *b)
350+{
351+ const struct ccs_path_acl *p1 = container_of(a, typeof(*p1), head);
352+ const struct ccs_path_acl *p2 = container_of(b, typeof(*p2), head);
353+ return ccs_same_name_union(&p1->name, &p2->name);
354+}
355+
356+/**
357+ * ccs_merge_path_acl - Merge duplicated "struct ccs_path_acl" entry.
358+ *
359+ * @a: Pointer to "struct ccs_acl_info".
360+ * @b: Pointer to "struct ccs_acl_info".
361+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
362+ *
363+ * Returns true if @a is empty, false otherwise.
364+ */
365+static bool ccs_merge_path_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
366+ const bool is_delete)
367+{
368+ u16 * const a_perm = &container_of(a, struct ccs_path_acl, head)->perm;
369+ u16 perm = *a_perm;
370+ const u16 b_perm = container_of(b, struct ccs_path_acl, head)->perm;
371+ if (is_delete)
372+ perm &= ~b_perm;
373+ else
374+ perm |= b_perm;
375+ *a_perm = perm;
376+ return !perm;
377+}
378+
379+/**
380+ * ccs_update_path_acl - Update "struct ccs_path_acl" list.
381+ *
382+ * @perm: Permission.
383+ * @param: Pointer to "struct ccs_acl_param".
384+ *
385+ * Returns 0 on success, negative value otherwise.
386+ *
387+ * Caller holds ccs_read_lock().
388+ */
389+static int ccs_update_path_acl(const u16 perm, struct ccs_acl_param *param)
390+{
391+ struct ccs_path_acl e = {
392+ .head.type = CCS_TYPE_PATH_ACL,
393+ .perm = perm
394+ };
395+ int error;
396+ if (!ccs_parse_name_union(ccs_read_token(param), &e.name))
397+ error = -EINVAL;
398+ else
399+ error = ccs_update_domain(&e.head, sizeof(e), param,
400+ ccs_same_path_acl,
401+ ccs_merge_path_acl);
402+ ccs_put_name_union(&e.name);
403+ return error;
404+}
405+
406+/**
407+ * ccs_same_mkdev_acl - Check for duplicated "struct ccs_mkdev_acl" entry.
408+ *
409+ * @a: Pointer to "struct ccs_acl_info".
410+ * @b: Pointer to "struct ccs_acl_info".
411+ *
412+ * Returns true if @a == @b except permission bits, false otherwise.
413+ */
414+static bool ccs_same_mkdev_acl(const struct ccs_acl_info *a,
415+ const struct ccs_acl_info *b)
416+{
417+ const struct ccs_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
418+ const struct ccs_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
419+ return ccs_same_name_union(&p1->name, &p2->name) &&
420+ ccs_same_number_union(&p1->mode, &p2->mode) &&
421+ ccs_same_number_union(&p1->major, &p2->major) &&
422+ ccs_same_number_union(&p1->minor, &p2->minor);
423+}
424+
425+/**
426+ * ccs_merge_mkdev_acl - Merge duplicated "struct ccs_mkdev_acl" entry.
427+ *
428+ * @a: Pointer to "struct ccs_acl_info".
429+ * @b: Pointer to "struct ccs_acl_info".
430+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
431+ *
432+ * Returns true if @a is empty, false otherwise.
433+ */
434+static bool ccs_merge_mkdev_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
435+ const bool is_delete)
436+{
437+ u8 *const a_perm = &container_of(a, struct ccs_mkdev_acl, head)->perm;
438+ u8 perm = *a_perm;
439+ const u8 b_perm = container_of(b, struct ccs_mkdev_acl, head)->perm;
440+ if (is_delete)
441+ perm &= ~b_perm;
442+ else
443+ perm |= b_perm;
444+ *a_perm = perm;
445+ return !perm;
446+}
447+
448+/**
449+ * ccs_update_mkdev_acl - Update "struct ccs_mkdev_acl" list.
450+ *
451+ * @perm: Permission.
452+ * @param: Pointer to "struct ccs_acl_param".
453+ *
454+ * Returns 0 on success, negative value otherwise.
455+ *
456+ * Caller holds ccs_read_lock().
457+ */
458+static int ccs_update_mkdev_acl(const u8 perm, struct ccs_acl_param *param)
459+{
460+ struct ccs_mkdev_acl e = {
461+ .head.type = CCS_TYPE_MKDEV_ACL,
462+ .perm = perm
463+ };
464+ int error;
465+ if (!ccs_parse_name_union(ccs_read_token(param), &e.name) ||
466+ !ccs_parse_number_union(ccs_read_token(param), &e.mode) ||
467+ !ccs_parse_number_union(ccs_read_token(param), &e.major) ||
468+ !ccs_parse_number_union(ccs_read_token(param), &e.minor))
469+ error = -EINVAL;
470+ else
471+ error = ccs_update_domain(&e.head, sizeof(e), param,
472+ ccs_same_mkdev_acl,
473+ ccs_merge_mkdev_acl);
474+ ccs_put_name_union(&e.name);
475+ ccs_put_number_union(&e.mode);
476+ ccs_put_number_union(&e.major);
477+ ccs_put_number_union(&e.minor);
478+ return error;
479+}
480+
481+/**
482+ * ccs_same_path2_acl - Check for duplicated "struct ccs_path2_acl" entry.
483+ *
484+ * @a: Pointer to "struct ccs_acl_info".
485+ * @b: Pointer to "struct ccs_acl_info".
486+ *
487+ * Returns true if @a == @b except permission bits, false otherwise.
488+ */
489+static bool ccs_same_path2_acl(const struct ccs_acl_info *a,
490+ const struct ccs_acl_info *b)
491+{
492+ const struct ccs_path2_acl *p1 = container_of(a, typeof(*p1), head);
493+ const struct ccs_path2_acl *p2 = container_of(b, typeof(*p2), head);
494+ return ccs_same_name_union(&p1->name1, &p2->name1) &&
495+ ccs_same_name_union(&p1->name2, &p2->name2);
496+}
497+
498+/**
499+ * ccs_merge_path2_acl - Merge duplicated "struct ccs_path2_acl" entry.
500+ *
501+ * @a: Pointer to "struct ccs_acl_info".
502+ * @b: Pointer to "struct ccs_acl_info".
503+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
504+ *
505+ * Returns true if @a is empty, false otherwise.
506+ */
507+static bool ccs_merge_path2_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
508+ const bool is_delete)
509+{
510+ u8 * const a_perm = &container_of(a, struct ccs_path2_acl, head)->perm;
511+ u8 perm = *a_perm;
512+ const u8 b_perm = container_of(b, struct ccs_path2_acl, head)->perm;
513+ if (is_delete)
514+ perm &= ~b_perm;
515+ else
516+ perm |= b_perm;
517+ *a_perm = perm;
518+ return !perm;
519+}
520+
521+/**
522+ * ccs_update_path2_acl - Update "struct ccs_path2_acl" list.
523+ *
524+ * @perm: Permission.
525+ * @param: Pointer to "struct ccs_acl_param".
526+ *
527+ * Returns 0 on success, negative value otherwise.
528+ *
529+ * Caller holds ccs_read_lock().
530+ */
531+static int ccs_update_path2_acl(const u8 perm, struct ccs_acl_param *param)
532+{
533+ struct ccs_path2_acl e = {
534+ .head.type = CCS_TYPE_PATH2_ACL,
535+ .perm = perm
536+ };
537+ int error;
538+ if (!ccs_parse_name_union(ccs_read_token(param), &e.name1) ||
539+ !ccs_parse_name_union(ccs_read_token(param), &e.name2))
540+ error = -EINVAL;
541+ else
542+ error = ccs_update_domain(&e.head, sizeof(e), param,
543+ ccs_same_path2_acl,
544+ ccs_merge_path2_acl);
545+ ccs_put_name_union(&e.name1);
546+ ccs_put_name_union(&e.name2);
547+ return error;
548+}
549+
550+/**
551+ * ccs_same_mount_acl - Check for duplicated "struct ccs_mount_acl" entry.
552+ *
553+ * @a: Pointer to "struct ccs_acl_info".
554+ * @b: Pointer to "struct ccs_acl_info".
555+ *
556+ * Returns true if @a == @b except permission bits, false otherwise.
557+ */
558+static bool ccs_same_mount_acl(const struct ccs_acl_info *a,
559+ const struct ccs_acl_info *b)
560+{
561+ const struct ccs_mount_acl *p1 = container_of(a, typeof(*p1), head);
562+ const struct ccs_mount_acl *p2 = container_of(b, typeof(*p2), head);
563+ return ccs_same_name_union(&p1->dev_name, &p2->dev_name) &&
564+ ccs_same_name_union(&p1->dir_name, &p2->dir_name) &&
565+ ccs_same_name_union(&p1->fs_type, &p2->fs_type) &&
566+ ccs_same_number_union(&p1->flags, &p2->flags);
567+}
568+
569+/**
570+ * ccs_update_mount_acl - Write "struct ccs_mount_acl" list.
571+ *
572+ * @param: Pointer to "struct ccs_acl_param".
573+ *
574+ * Returns 0 on success, negative value otherwise.
575+ *
576+ * Caller holds ccs_read_lock().
577+ */
578+static int ccs_update_mount_acl(struct ccs_acl_param *param)
579+{
580+ struct ccs_mount_acl e = { .head.type = CCS_TYPE_MOUNT_ACL };
581+ int error;
582+ if (!ccs_parse_name_union(ccs_read_token(param), &e.dev_name) ||
583+ !ccs_parse_name_union(ccs_read_token(param), &e.dir_name) ||
584+ !ccs_parse_name_union(ccs_read_token(param), &e.fs_type) ||
585+ !ccs_parse_number_union(ccs_read_token(param), &e.flags))
586+ error = -EINVAL;
587+ else
588+ error = ccs_update_domain(&e.head, sizeof(e), param,
589+ ccs_same_mount_acl, NULL);
590+ ccs_put_name_union(&e.dev_name);
591+ ccs_put_name_union(&e.dir_name);
592+ ccs_put_name_union(&e.fs_type);
593+ ccs_put_number_union(&e.flags);
594+ return error;
595+}
596+
597+/**
598+ * ccs_path_permission - Check permission for path operation.
599+ *
600+ * @r: Pointer to "struct ccs_request_info".
601+ * @operation: Type of operation.
602+ * @filename: Filename to check.
603+ *
604+ * Returns 0 on success, CCS_RETRY_REQUEST on retry, negative value otherwise.
605+ *
606+ * Caller holds ccs_read_lock().
607+ */
608+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
609+ const struct ccs_path_info *filename)
610+{
611+ int error;
612+ r->type = ccs_p2mac[operation];
613+ r->mode = ccs_get_mode(r->profile, r->type);
614+ if (r->mode == CCS_CONFIG_DISABLED)
615+ return 0;
616+ r->param_type = CCS_TYPE_PATH_ACL;
617+ r->param.path.filename = filename;
618+ r->param.path.operation = operation;
619+ do {
620+ ccs_check_acl(r, ccs_check_path_acl);
621+ error = ccs_audit_path_log(r);
622+ /*
623+ * Do not retry for execute request, for aggregator may have
624+ * changed.
625+ */
626+ } while (error == CCS_RETRY_REQUEST && operation != CCS_TYPE_EXECUTE);
627+ return error;
628+}
629+
630+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
631+
632+/**
633+ * __ccs_save_open_mode - Remember original flags passed to sys_open().
634+ *
635+ * @mode: Flags passed to sys_open().
636+ *
637+ * Returns nothing.
638+ *
639+ * TOMOYO does not check "file write" if open(path, O_TRUNC | O_RDONLY) was
640+ * requested because write() is not permitted. Instead, TOMOYO checks
641+ * "file truncate" if O_TRUNC is passed.
642+ *
643+ * TOMOYO does not check "file read" and "file write" if open(path, 3) was
644+ * requested because read()/write() are not permitted. Instead, TOMOYO checks
645+ * "file ioctl" when ioctl() is requested.
646+ */
647+static void __ccs_save_open_mode(int mode)
648+{
649+ if ((mode & 3) == 3)
650+ ccs_current_security()->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
651+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
652+ /* O_TRUNC passes MAY_WRITE to ccs_open_permission(). */
653+ else if (!(mode & 3) && (mode & O_TRUNC))
654+ ccs_current_security()->ccs_flags |=
655+ CCS_OPEN_FOR_READ_TRUNCATE;
656+#endif
657+}
658+
659+/**
660+ * __ccs_clear_open_mode - Forget original flags passed to sys_open().
661+ *
662+ * Returns nothing.
663+ */
664+static void __ccs_clear_open_mode(void)
665+{
666+ ccs_current_security()->ccs_flags &= ~(CCS_OPEN_FOR_IOCTL_ONLY |
667+ CCS_OPEN_FOR_READ_TRUNCATE);
668+}
669+
670+#endif
671+
672+/**
673+ * __ccs_open_permission - Check permission for "read" and "write".
674+ *
675+ * @dentry: Pointer to "struct dentry".
676+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
677+ * @flag: Flags for open().
678+ *
679+ * Returns 0 on success, negative value otherwise.
680+ */
681+static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
682+ const int flag)
683+{
684+ struct ccs_request_info r;
685+ struct ccs_obj_info obj = {
686+ .path1.dentry = dentry,
687+ .path1.mnt = mnt,
688+ };
689+ const u32 ccs_flags = ccs_current_flags();
690+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
691+ const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
692+#else
693+ const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
694+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
695+ (ccs_flags & CCS_OPEN_FOR_READ_TRUNCATE) ? 4 :
696+#endif
697+ ACC_MODE(flag);
698+#endif
699+ int error = 0;
700+ struct ccs_path_info buf;
701+ int idx;
702+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
703+ if (current->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
704+ return 0;
705+#endif
706+ buf.name = NULL;
707+ r.mode = CCS_CONFIG_DISABLED;
708+ idx = ccs_read_lock();
709+ if (acc_mode && ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
710+ != CCS_CONFIG_DISABLED) {
711+ if (!ccs_get_realpath(&buf, dentry, mnt)) {
712+ error = -ENOMEM;
713+ goto out;
714+ }
715+ r.obj = &obj;
716+ if (acc_mode & MAY_READ)
717+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
718+ if (!error && (acc_mode & MAY_WRITE))
719+ error = ccs_path_permission(&r, (flag & O_APPEND) ?
720+ CCS_TYPE_APPEND :
721+ CCS_TYPE_WRITE, &buf);
722+ }
723+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
724+ if (!error && (flag & O_TRUNC) &&
725+ ccs_init_request_info(&r, CCS_MAC_FILE_TRUNCATE)
726+ != CCS_CONFIG_DISABLED) {
727+ if (!buf.name && !ccs_get_realpath(&buf, dentry, mnt)) {
728+ error = -ENOMEM;
729+ goto out;
730+ }
731+ r.obj = &obj;
732+ error = ccs_path_permission(&r, CCS_TYPE_TRUNCATE, &buf);
733+ }
734+#endif
735+out:
736+ kfree(buf.name);
737+ ccs_read_unlock(idx);
738+ if (r.mode != CCS_CONFIG_ENFORCING)
739+ error = 0;
740+ return error;
741+}
742+
743+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
744+
745+/**
746+ * ccs_new_open_permission - Check permission for "read" and "write".
747+ *
748+ * @filp: Pointer to "struct file".
749+ *
750+ * Returns 0 on success, negative value otherwise.
751+ */
752+static int ccs_new_open_permission(struct file *filp)
753+{
754+ return __ccs_open_permission(filp->f_path.dentry, filp->f_path.mnt,
755+ filp->f_flags);
756+}
757+
758+#endif
759+
760+/**
761+ * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "getattr", "chroot" and "unmount".
762+ *
763+ * @operation: Type of operation.
764+ * @dir: Pointer to "struct inode". Maybe NULL.
765+ * @dentry: Pointer to "struct dentry".
766+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
767+ * @target: Symlink's target if @operation is CCS_TYPE_SYMLINK.
768+ * NULL otherwise.
769+ *
770+ * Returns 0 on success, negative value otherwise.
771+ */
772+static int ccs_path_perm(const u8 operation, struct inode *dir,
773+ struct dentry *dentry, struct vfsmount *mnt,
774+ const char *target)
775+{
776+ struct ccs_request_info r;
777+ struct ccs_obj_info obj = {
778+ .path1.dentry = dentry,
779+ .path1.mnt = mnt,
780+ };
781+ int error = 0;
782+ struct ccs_path_info buf;
783+ bool is_enforce = false;
784+ struct ccs_path_info symlink_target;
785+ int idx;
786+ buf.name = NULL;
787+ symlink_target.name = NULL;
788+ idx = ccs_read_lock();
789+ if (ccs_init_request_info(&r, ccs_p2mac[operation])
790+ == CCS_CONFIG_DISABLED)
791+ goto out;
792+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
793+ error = -ENOMEM;
794+ if (!ccs_get_realpath(&buf, dentry, mnt))
795+ goto out;
796+ r.obj = &obj;
797+ switch (operation) {
798+ case CCS_TYPE_RMDIR:
799+ case CCS_TYPE_CHROOT:
800+ ccs_add_slash(&buf);
801+ break;
802+ case CCS_TYPE_SYMLINK:
803+ symlink_target.name = ccs_encode(target);
804+ if (!symlink_target.name)
805+ goto out;
806+ ccs_fill_path_info(&symlink_target);
807+ obj.symlink_target = &symlink_target;
808+ break;
809+ }
810+ error = ccs_path_permission(&r, operation, &buf);
811+ if (operation == CCS_TYPE_SYMLINK)
812+ kfree(symlink_target.name);
813+out:
814+ kfree(buf.name);
815+ ccs_read_unlock(idx);
816+ if (!is_enforce)
817+ error = 0;
818+ return error;
819+}
820+
821+/**
822+ * ccs_mkdev_perm - Check permission for "mkblock" and "mkchar".
823+ *
824+ * @operation: Type of operation. (CCS_TYPE_MKCHAR or CCS_TYPE_MKBLOCK)
825+ * @dir: Pointer to "struct inode".
826+ * @dentry: Pointer to "struct dentry".
827+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
828+ * @mode: Create mode.
829+ * @dev: Device number.
830+ *
831+ * Returns 0 on success, negative value otherwise.
832+ */
833+static int ccs_mkdev_perm(const u8 operation, struct inode *dir,
834+ struct dentry *dentry, struct vfsmount *mnt,
835+ const unsigned int mode, unsigned int dev)
836+{
837+ struct ccs_request_info r;
838+ struct ccs_obj_info obj = {
839+ .path1.dentry = dentry,
840+ .path1.mnt = mnt,
841+ };
842+ int error = 0;
843+ struct ccs_path_info buf;
844+ bool is_enforce = false;
845+ int idx;
846+ idx = ccs_read_lock();
847+ if (ccs_init_request_info(&r, ccs_pnnn2mac[operation])
848+ == CCS_CONFIG_DISABLED)
849+ goto out;
850+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
851+ error = -EPERM;
852+ if (!capable(CAP_MKNOD))
853+ goto out;
854+ error = -ENOMEM;
855+ if (!ccs_get_realpath(&buf, dentry, mnt))
856+ goto out;
857+ r.obj = &obj;
858+#ifdef CONFIG_SECURITY_PATH
859+ dev = new_decode_dev(dev);
860+#endif
861+ r.param_type = CCS_TYPE_MKDEV_ACL;
862+ r.param.mkdev.filename = &buf;
863+ r.param.mkdev.operation = operation;
864+ r.param.mkdev.mode = mode;
865+ r.param.mkdev.major = MAJOR(dev);
866+ r.param.mkdev.minor = MINOR(dev);
867+ do {
868+ ccs_check_acl(&r, ccs_check_mkdev_acl);
869+ error = ccs_audit_mkdev_log(&r);
870+ } while (error == CCS_RETRY_REQUEST);
871+ kfree(buf.name);
872+out:
873+ ccs_read_unlock(idx);
874+ if (!is_enforce)
875+ error = 0;
876+ return error;
877+}
878+
879+/**
880+ * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
881+ *
882+ * @operation: Type of operation.
883+ * @dir1: Pointer to "struct inode". Maybe NULL.
884+ * @dentry1: Pointer to "struct dentry".
885+ * @mnt1: Pointer to "struct vfsmount". Maybe NULL.
886+ * @dir2: Pointer to "struct inode". Maybe NULL.
887+ * @dentry2: Pointer to "struct dentry".
888+ * @mnt2: Pointer to "struct vfsmount". Maybe NULL.
889+ *
890+ * Returns 0 on success, negative value otherwise.
891+ */
892+static int ccs_path2_perm(const u8 operation, struct inode *dir1,
893+ struct dentry *dentry1, struct vfsmount *mnt1,
894+ struct inode *dir2, struct dentry *dentry2,
895+ struct vfsmount *mnt2)
896+{
897+ struct ccs_request_info r;
898+ int error = 0;
899+ struct ccs_path_info buf1;
900+ struct ccs_path_info buf2;
901+ bool is_enforce = false;
902+ struct ccs_obj_info obj = {
903+ .path1.dentry = dentry1,
904+ .path1.mnt = mnt1,
905+ .path2.dentry = dentry2,
906+ .path2.mnt = mnt2,
907+ };
908+ int idx;
909+ buf1.name = NULL;
910+ buf2.name = NULL;
911+ idx = ccs_read_lock();
912+ if (ccs_init_request_info(&r, ccs_pp2mac[operation])
913+ == CCS_CONFIG_DISABLED)
914+ goto out;
915+ is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
916+ error = -ENOMEM;
917+ if (!ccs_get_realpath(&buf1, dentry1, mnt1) ||
918+ !ccs_get_realpath(&buf2, dentry2, mnt2))
919+ goto out;
920+ switch (operation) {
921+ case CCS_TYPE_RENAME:
922+ case CCS_TYPE_LINK:
923+ if (!dentry1->d_inode || !S_ISDIR(dentry1->d_inode->i_mode))
924+ break;
925+ /* fall through */
926+ case CCS_TYPE_PIVOT_ROOT:
927+ ccs_add_slash(&buf1);
928+ ccs_add_slash(&buf2);
929+ break;
930+ }
931+ r.obj = &obj;
932+ r.param_type = CCS_TYPE_PATH2_ACL;
933+ r.param.path2.operation = operation;
934+ r.param.path2.filename1 = &buf1;
935+ r.param.path2.filename2 = &buf2;
936+ do {
937+ ccs_check_acl(&r, ccs_check_path2_acl);
938+ error = ccs_audit_path2_log(&r);
939+ } while (error == CCS_RETRY_REQUEST);
940+out:
941+ kfree(buf1.name);
942+ kfree(buf2.name);
943+ ccs_read_unlock(idx);
944+ if (!is_enforce)
945+ error = 0;
946+ return error;
947+}
948+
949+/**
950+ * ccs_same_path_number_acl - Check for duplicated "struct ccs_path_number_acl" entry.
951+ *
952+ * @a: Pointer to "struct ccs_acl_info".
953+ * @b: Pointer to "struct ccs_acl_info".
954+ *
955+ * Returns true if @a == @b except permission bits, false otherwise.
956+ */
957+static bool ccs_same_path_number_acl(const struct ccs_acl_info *a,
958+ const struct ccs_acl_info *b)
959+{
960+ const struct ccs_path_number_acl *p1 = container_of(a, typeof(*p1),
961+ head);
962+ const struct ccs_path_number_acl *p2 = container_of(b, typeof(*p2),
963+ head);
964+ return ccs_same_name_union(&p1->name, &p2->name) &&
965+ ccs_same_number_union(&p1->number, &p2->number);
966+}
967+
968+/**
969+ * ccs_merge_path_number_acl - Merge duplicated "struct ccs_path_number_acl" entry.
970+ *
971+ * @a: Pointer to "struct ccs_acl_info".
972+ * @b: Pointer to "struct ccs_acl_info".
973+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
974+ *
975+ * Returns true if @a is empty, false otherwise.
976+ */
977+static bool ccs_merge_path_number_acl(struct ccs_acl_info *a,
978+ struct ccs_acl_info *b,
979+ const bool is_delete)
980+{
981+ u8 * const a_perm = &container_of(a, struct ccs_path_number_acl, head)
982+ ->perm;
983+ u8 perm = *a_perm;
984+ const u8 b_perm = container_of(b, struct ccs_path_number_acl, head)
985+ ->perm;
986+ if (is_delete)
987+ perm &= ~b_perm;
988+ else
989+ perm |= b_perm;
990+ *a_perm = perm;
991+ return !perm;
992+}
993+
994+/**
995+ * ccs_update_path_number_acl - Update create/mkdir/mkfifo/mksock/ioctl/chmod/chown/chgrp ACL.
996+ *
997+ * @perm: Permission.
998+ * @param: Pointer to "struct ccs_acl_param".
999+ *
1000+ * Returns 0 on success, negative value otherwise.
1001+ */
1002+static int ccs_update_path_number_acl(const u8 perm,
1003+ struct ccs_acl_param *param)
1004+{
1005+ struct ccs_path_number_acl e = {
1006+ .head.type = CCS_TYPE_PATH_NUMBER_ACL,
1007+ .perm = perm
1008+ };
1009+ int error;
1010+ if (!ccs_parse_name_union(ccs_read_token(param), &e.name) ||
1011+ !ccs_parse_number_union(ccs_read_token(param), &e.number))
1012+ error = -EINVAL;
1013+ else
1014+ error = ccs_update_domain(&e.head, sizeof(e), param,
1015+ ccs_same_path_number_acl,
1016+ ccs_merge_path_number_acl);
1017+ ccs_put_name_union(&e.name);
1018+ ccs_put_number_union(&e.number);
1019+ return error;
1020+}
1021+
1022+/**
1023+ * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
1024+ *
1025+ * @type: Type of operation.
1026+ * @dir: Pointer to "struct inode". Maybe NULL.
1027+ * @dentry: Pointer to "struct dentry".
1028+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
1029+ * @number: Number.
1030+ *
1031+ * Returns 0 on success, negative value otherwise.
1032+ */
1033+static int ccs_path_number_perm(const u8 type, struct inode *dir,
1034+ struct dentry *dentry, struct vfsmount *vfsmnt,
1035+ unsigned long number)
1036+{
1037+ struct ccs_request_info r;
1038+ struct ccs_obj_info obj = {
1039+ .path1.dentry = dentry,
1040+ .path1.mnt = vfsmnt,
1041+ };
1042+ int error = 0;
1043+ struct ccs_path_info buf;
1044+ int idx;
1045+ if (!dentry)
1046+ return 0;
1047+ idx = ccs_read_lock();
1048+ if (ccs_init_request_info(&r, ccs_pn2mac[type]) == CCS_CONFIG_DISABLED)
1049+ goto out;
1050+ error = -ENOMEM;
1051+ if (!ccs_get_realpath(&buf, dentry, vfsmnt))
1052+ goto out;
1053+ r.obj = &obj;
1054+ if (type == CCS_TYPE_MKDIR)
1055+ ccs_add_slash(&buf);
1056+ r.param_type = CCS_TYPE_PATH_NUMBER_ACL;
1057+ r.param.path_number.operation = type;
1058+ r.param.path_number.filename = &buf;
1059+ r.param.path_number.number = number;
1060+ do {
1061+ ccs_check_acl(&r, ccs_check_path_number_acl);
1062+ error = ccs_audit_path_number_log(&r);
1063+ } while (error == CCS_RETRY_REQUEST);
1064+ kfree(buf.name);
1065+out:
1066+ ccs_read_unlock(idx);
1067+ if (r.mode != CCS_CONFIG_ENFORCING)
1068+ error = 0;
1069+ return error;
1070+}
1071+
1072+/**
1073+ * __ccs_ioctl_permission - Check permission for "ioctl".
1074+ *
1075+ * @filp: Pointer to "struct file".
1076+ * @cmd: Ioctl command number.
1077+ * @arg: Param for @cmd.
1078+ *
1079+ * Returns 0 on success, negative value otherwise.
1080+ */
1081+static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
1082+ unsigned long arg)
1083+{
1084+ return ccs_path_number_perm(CCS_TYPE_IOCTL, NULL, filp->f_dentry,
1085+ filp->f_vfsmnt, cmd);
1086+}
1087+
1088+/**
1089+ * __ccs_chmod_permission - Check permission for "chmod".
1090+ *
1091+ * @dentry: Pointer to "struct dentry".
1092+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
1093+ * @mode: Mode.
1094+ *
1095+ * Returns 0 on success, negative value otherwise.
1096+ */
1097+static int __ccs_chmod_permission(struct dentry *dentry,
1098+ struct vfsmount *vfsmnt, mode_t mode)
1099+{
1100+ if (mode == (mode_t) -1)
1101+ return 0;
1102+ return ccs_path_number_perm(CCS_TYPE_CHMOD, NULL, dentry, vfsmnt,
1103+ mode & S_IALLUGO);
1104+}
1105+
1106+/**
1107+ * __ccs_chown_permission - Check permission for "chown/chgrp".
1108+ *
1109+ * @dentry: Pointer to "struct dentry".
1110+ * @vfsmnt: Pointer to "struct vfsmount". Maybe NULL.
1111+ * @user: User ID.
1112+ * @group: Group ID.
1113+ *
1114+ * Returns 0 on success, negative value otherwise.
1115+ */
1116+static int __ccs_chown_permission(struct dentry *dentry,
1117+ struct vfsmount *vfsmnt, uid_t user,
1118+ gid_t group)
1119+{
1120+ int error = 0;
1121+ if (user == (uid_t) -1 && group == (gid_t) -1)
1122+ return 0;
1123+ if (user != (uid_t) -1)
1124+ error = ccs_path_number_perm(CCS_TYPE_CHOWN, NULL, dentry,
1125+ vfsmnt, user);
1126+ if (!error && group != (gid_t) -1)
1127+ error = ccs_path_number_perm(CCS_TYPE_CHGRP, NULL, dentry,
1128+ vfsmnt, group);
1129+ return error;
1130+}
1131+
1132+/**
1133+ * __ccs_fcntl_permission - Check permission for changing O_APPEND flag.
1134+ *
1135+ * @file: Pointer to "struct file".
1136+ * @cmd: Command number.
1137+ * @arg: Value for @cmd.
1138+ *
1139+ * Returns 0 on success, negative value otherwise.
1140+ */
1141+static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
1142+ unsigned long arg)
1143+{
1144+ if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
1145+ return 0;
1146+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
1147+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
1148+ O_WRONLY | (arg & O_APPEND));
1149+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
1150+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
1151+ O_WRONLY | (arg & O_APPEND));
1152+#else
1153+ return __ccs_open_permission(file->f_dentry, file->f_vfsmnt,
1154+ (O_WRONLY + 1) | (arg & O_APPEND));
1155+#endif
1156+}
1157+
1158+/**
1159+ * __ccs_pivot_root_permission - Check permission for pivot_root().
1160+ *
1161+ * @old_path: Pointer to "struct path".
1162+ * @new_path: Pointer to "struct path".
1163+ *
1164+ * Returns 0 on success, negative value otherwise.
1165+ */
1166+static int __ccs_pivot_root_permission(struct path *old_path,
1167+ struct path *new_path)
1168+{
1169+ return ccs_path2_perm(CCS_TYPE_PIVOT_ROOT, NULL, new_path->dentry,
1170+ new_path->mnt, NULL, old_path->dentry,
1171+ old_path->mnt);
1172+}
1173+
1174+/**
1175+ * __ccs_chroot_permission - Check permission for chroot().
1176+ *
1177+ * @path: Pointer to "struct path".
1178+ *
1179+ * Returns 0 on success, negative value otherwise.
1180+ */
1181+static int __ccs_chroot_permission(struct path *path)
1182+{
1183+ return ccs_path_perm(CCS_TYPE_CHROOT, NULL, path->dentry, path->mnt,
1184+ NULL);
1185+}
1186+
1187+/**
1188+ * __ccs_umount_permission - Check permission for unmount.
1189+ *
1190+ * @mnt: Pointer to "struct vfsmount".
1191+ * @flags: Unused.
1192+ *
1193+ * Returns 0 on success, negative value otherwise.
1194+ */
1195+static int __ccs_umount_permission(struct vfsmount *mnt, int flags)
1196+{
1197+ return ccs_path_perm(CCS_TYPE_UMOUNT, NULL, mnt->mnt_root, mnt, NULL);
1198+}
1199+
1200+/**
1201+ * ccs_write_file - Update file related list.
1202+ *
1203+ * @param: Pointer to "struct ccs_acl_param".
1204+ *
1205+ * Returns 0 on success, negative value otherwise.
1206+ */
1207+int ccs_write_file(struct ccs_acl_param *param)
1208+{
1209+ u16 perm = 0;
1210+ u8 type;
1211+ const char *operation = ccs_read_token(param);
1212+ for (type = 0; type < CCS_MAX_PATH_OPERATION; type++)
1213+ if (ccs_permstr(operation, ccs_path_keyword[type]))
1214+ perm |= 1 << type;
1215+ if (perm)
1216+ return ccs_update_path_acl(perm, param);
1217+ for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++)
1218+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pp2mac[type]]))
1219+ perm |= 1 << type;
1220+ if (perm)
1221+ return ccs_update_path2_acl(perm, param);
1222+ for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++)
1223+ if (ccs_permstr(operation, ccs_mac_keywords[ccs_pn2mac[type]]))
1224+ perm |= 1 << type;
1225+ if (perm)
1226+ return ccs_update_path_number_acl(perm, param);
1227+ for (type = 0; type < CCS_MAX_MKDEV_OPERATION; type++)
1228+ if (ccs_permstr(operation,
1229+ ccs_mac_keywords[ccs_pnnn2mac[type]]))
1230+ perm |= 1 << type;
1231+ if (perm)
1232+ return ccs_update_mkdev_acl(perm, param);
1233+ if (ccs_permstr(operation, ccs_mac_keywords[CCS_MAC_FILE_MOUNT]))
1234+ return ccs_update_mount_acl(param);
1235+ return -EINVAL;
1236+}
1237+
1238+/**
1239+ * __ccs_mknod_permission - Check permission for vfs_mknod().
1240+ *
1241+ * @dir: Pointer to "struct inode".
1242+ * @dentry: Pointer to "struct dentry".
1243+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1244+ * @mode: Device type and permission.
1245+ * @dev: Device number for block or character device.
1246+ *
1247+ * Returns 0 on success, negative value otherwise.
1248+ */
1249+static int __ccs_mknod_permission(struct inode *dir, struct dentry *dentry,
1250+ struct vfsmount *mnt,
1251+ const unsigned int mode, unsigned int dev)
1252+{
1253+ int error = 0;
1254+ const unsigned int perm = mode & S_IALLUGO;
1255+ switch (mode & S_IFMT) {
1256+ case S_IFCHR:
1257+ error = ccs_mkdev_perm(CCS_TYPE_MKCHAR, dir, dentry, mnt, perm,
1258+ dev);
1259+ break;
1260+ case S_IFBLK:
1261+ error = ccs_mkdev_perm(CCS_TYPE_MKBLOCK, dir, dentry, mnt,
1262+ perm, dev);
1263+ break;
1264+ case S_IFIFO:
1265+ error = ccs_path_number_perm(CCS_TYPE_MKFIFO, dir, dentry, mnt,
1266+ perm);
1267+ break;
1268+ case S_IFSOCK:
1269+ error = ccs_path_number_perm(CCS_TYPE_MKSOCK, dir, dentry, mnt,
1270+ perm);
1271+ break;
1272+ case 0:
1273+ case S_IFREG:
1274+ error = ccs_path_number_perm(CCS_TYPE_CREATE, dir, dentry, mnt,
1275+ perm);
1276+ break;
1277+ }
1278+ return error;
1279+}
1280+
1281+/**
1282+ * __ccs_mkdir_permission - Check permission for vfs_mkdir().
1283+ *
1284+ * @dir: Pointer to "struct inode".
1285+ * @dentry: Pointer to "struct dentry".
1286+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1287+ * @mode: Create mode.
1288+ *
1289+ * Returns 0 on success, negative value otherwise.
1290+ */
1291+static int __ccs_mkdir_permission(struct inode *dir, struct dentry *dentry,
1292+ struct vfsmount *mnt, unsigned int mode)
1293+{
1294+ return ccs_path_number_perm(CCS_TYPE_MKDIR, dir, dentry, mnt, mode);
1295+}
1296+
1297+/**
1298+ * __ccs_rmdir_permission - Check permission for vfs_rmdir().
1299+ *
1300+ * @dir: Pointer to "struct inode".
1301+ * @dentry: Pointer to "struct dentry".
1302+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1303+ *
1304+ * Returns 0 on success, negative value otherwise.
1305+ */
1306+static int __ccs_rmdir_permission(struct inode *dir, struct dentry *dentry,
1307+ struct vfsmount *mnt)
1308+{
1309+ return ccs_path_perm(CCS_TYPE_RMDIR, dir, dentry, mnt, NULL);
1310+}
1311+
1312+/**
1313+ * __ccs_unlink_permission - Check permission for vfs_unlink().
1314+ *
1315+ * @dir: Pointer to "struct inode".
1316+ * @dentry: Pointer to "struct dentry".
1317+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1318+ *
1319+ * Returns 0 on success, negative value otherwise.
1320+ */
1321+static int __ccs_unlink_permission(struct inode *dir, struct dentry *dentry,
1322+ struct vfsmount *mnt)
1323+{
1324+ return ccs_path_perm(CCS_TYPE_UNLINK, dir, dentry, mnt, NULL);
1325+}
1326+
1327+/**
1328+ * __ccs_getattr_permission - Check permission for vfs_getattr().
1329+ *
1330+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1331+ * @dentry: Pointer to "struct dentry".
1332+ *
1333+ * Returns 0 on success, negative value otherwise.
1334+ */
1335+static int __ccs_getattr_permission(struct vfsmount *mnt,
1336+ struct dentry *dentry)
1337+{
1338+ return ccs_path_perm(CCS_TYPE_GETATTR, NULL, dentry, mnt, NULL);
1339+}
1340+
1341+/**
1342+ * __ccs_symlink_permission - Check permission for vfs_symlink().
1343+ *
1344+ * @dir: Pointer to "struct inode".
1345+ * @dentry: Pointer to "struct dentry".
1346+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1347+ * @from: Content of symlink.
1348+ *
1349+ * Returns 0 on success, negative value otherwise.
1350+ */
1351+static int __ccs_symlink_permission(struct inode *dir, struct dentry *dentry,
1352+ struct vfsmount *mnt, const char *from)
1353+{
1354+ return ccs_path_perm(CCS_TYPE_SYMLINK, dir, dentry, mnt, from);
1355+}
1356+
1357+/**
1358+ * __ccs_truncate_permission - Check permission for notify_change().
1359+ *
1360+ * @dentry: Pointer to "struct dentry".
1361+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1362+ *
1363+ * Returns 0 on success, negative value otherwise.
1364+ */
1365+static int __ccs_truncate_permission(struct dentry *dentry,
1366+ struct vfsmount *mnt)
1367+{
1368+ return ccs_path_perm(CCS_TYPE_TRUNCATE, NULL, dentry, mnt, NULL);
1369+}
1370+
1371+/**
1372+ * __ccs_rename_permission - Check permission for vfs_rename().
1373+ *
1374+ * @old_dir: Pointer to "struct inode".
1375+ * @old_dentry: Pointer to "struct dentry".
1376+ * @new_dir: Pointer to "struct inode".
1377+ * @new_dentry: Pointer to "struct dentry".
1378+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1379+ *
1380+ * Returns 0 on success, negative value otherwise.
1381+ */
1382+static int __ccs_rename_permission(struct inode *old_dir,
1383+ struct dentry *old_dentry,
1384+ struct inode *new_dir,
1385+ struct dentry *new_dentry,
1386+ struct vfsmount *mnt)
1387+{
1388+ return ccs_path2_perm(CCS_TYPE_RENAME, old_dir, old_dentry, mnt,
1389+ new_dir, new_dentry, mnt);
1390+}
1391+
1392+/**
1393+ * __ccs_link_permission - Check permission for vfs_link().
1394+ *
1395+ * @old_dentry: Pointer to "struct dentry".
1396+ * @new_dir: Pointer to "struct inode".
1397+ * @new_dentry: Pointer to "struct dentry".
1398+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1399+ *
1400+ * Returns 0 on success, negative value otherwise.
1401+ */
1402+static int __ccs_link_permission(struct dentry *old_dentry,
1403+ struct inode *new_dir,
1404+ struct dentry *new_dentry,
1405+ struct vfsmount *mnt)
1406+{
1407+ return ccs_path2_perm(CCS_TYPE_LINK, NULL, old_dentry, mnt,
1408+ new_dir, new_dentry, mnt);
1409+}
1410+
1411+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1412+
1413+/**
1414+ * __ccs_open_exec_permission - Check permission for open_exec().
1415+ *
1416+ * @dentry: Pointer to "struct dentry".
1417+ * @mnt: Pointer to "struct vfsmount".
1418+ *
1419+ * Returns 0 on success, negative value otherwise.
1420+ */
1421+static int __ccs_open_exec_permission(struct dentry *dentry,
1422+ struct vfsmount *mnt)
1423+{
1424+ return (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE) ?
1425+ __ccs_open_permission(dentry, mnt, O_RDONLY + 1) : 0;
1426+}
1427+
1428+/**
1429+ * __ccs_uselib_permission - Check permission for sys_uselib().
1430+ *
1431+ * @dentry: Pointer to "struct dentry".
1432+ * @mnt: Pointer to "struct vfsmount".
1433+ *
1434+ * Returns 0 on success, negative value otherwise.
1435+ */
1436+static int __ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
1437+{
1438+ return __ccs_open_permission(dentry, mnt, O_RDONLY + 1);
1439+}
1440+
1441+#endif
1442+
1443+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
1444+
1445+/**
1446+ * __ccs_parse_table - Check permission for parse_table().
1447+ *
1448+ * @name: Pointer to "int __user".
1449+ * @nlen: Number of elements in @name.
1450+ * @oldval: Pointer to "void __user".
1451+ * @newval: Pointer to "void __user".
1452+ * @table: Pointer to "struct ctl_table".
1453+ *
1454+ * Returns 0 on success, negative value otherwise.
1455+ *
1456+ * Note that this function is racy because this function checks values in
1457+ * userspace memory which could be changed after permission check.
1458+ */
1459+static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
1460+ void __user *newval, struct ctl_table *table)
1461+{
1462+ int n;
1463+ int error = -ENOMEM;
1464+ int op = 0;
1465+ struct ccs_path_info buf;
1466+ char *buffer = NULL;
1467+ struct ccs_request_info r;
1468+ int idx;
1469+ if (oldval)
1470+ op |= 004;
1471+ if (newval)
1472+ op |= 002;
1473+ if (!op) /* Neither read nor write */
1474+ return 0;
1475+ idx = ccs_read_lock();
1476+ if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
1477+ == CCS_CONFIG_DISABLED) {
1478+ error = 0;
1479+ goto out;
1480+ }
1481+ buffer = kmalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1482+ if (!buffer)
1483+ goto out;
1484+ snprintf(buffer, PAGE_SIZE - 1, "proc:/sys");
1485+repeat:
1486+ if (!nlen) {
1487+ error = -ENOTDIR;
1488+ goto out;
1489+ }
1490+ if (get_user(n, name)) {
1491+ error = -EFAULT;
1492+ goto out;
1493+ }
1494+ for ( ; table->ctl_name
1495+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
1496+ || table->procname
1497+#endif
1498+ ; table++) {
1499+ int pos;
1500+ const char *cp;
1501+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
1502+ if (n != table->ctl_name && table->ctl_name != CTL_ANY)
1503+ continue;
1504+#else
1505+ if (!n || n != table->ctl_name)
1506+ continue;
1507+#endif
1508+ pos = strlen(buffer);
1509+ cp = table->procname;
1510+ error = -ENOMEM;
1511+ if (cp) {
1512+ int len = strlen(cp);
1513+ if (len + 2 > PAGE_SIZE - 1)
1514+ goto out;
1515+ buffer[pos++] = '/';
1516+ memmove(buffer + pos, cp, len + 1);
1517+ } else {
1518+ /* Assume nobody assigns "=\$=" for procname. */
1519+ snprintf(buffer + pos, PAGE_SIZE - pos - 1,
1520+ "/=%d=", table->ctl_name);
1521+ if (!memchr(buffer, '\0', PAGE_SIZE - 2))
1522+ goto out;
1523+ }
1524+ if (!table->child)
1525+ goto no_child;
1526+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
1527+ if (!table->strategy)
1528+ goto no_strategy;
1529+ /* printk("sysctl='%s'\n", buffer); */
1530+ buf.name = ccs_encode(buffer);
1531+ if (!buf.name)
1532+ goto out;
1533+ ccs_fill_path_info(&buf);
1534+ if (op & MAY_READ)
1535+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
1536+ else
1537+ error = 0;
1538+ if (!error && (op & MAY_WRITE))
1539+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
1540+ kfree(buf.name);
1541+ if (error)
1542+ goto out;
1543+no_strategy:
1544+#endif
1545+ name++;
1546+ nlen--;
1547+ table = table->child;
1548+ goto repeat;
1549+no_child:
1550+ /* printk("sysctl='%s'\n", buffer); */
1551+ buf.name = ccs_encode(buffer);
1552+ if (!buf.name)
1553+ goto out;
1554+ ccs_fill_path_info(&buf);
1555+ if (op & MAY_READ)
1556+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
1557+ else
1558+ error = 0;
1559+ if (!error && (op & MAY_WRITE))
1560+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
1561+ kfree(buf.name);
1562+ goto out;
1563+ }
1564+ error = -ENOTDIR;
1565+out:
1566+ ccs_read_unlock(idx);
1567+ kfree(buffer);
1568+ return error;
1569+}
1570+
1571+#endif
1572+
1573+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1574+
1575+/**
1576+ * ccs_old_pivot_root_permission - Check permission for pivot_root().
1577+ *
1578+ * @old_nd: Pointer to "struct nameidata".
1579+ * @new_nd: Pointer to "struct nameidata".
1580+ *
1581+ * Returns 0 on success, negative value otherwise.
1582+ */
1583+static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
1584+ struct nameidata *new_nd)
1585+{
1586+ struct path old_path = { old_nd->mnt, old_nd->dentry };
1587+ struct path new_path = { new_nd->mnt, new_nd->dentry };
1588+ return __ccs_pivot_root_permission(&old_path, &new_path);
1589+}
1590+
1591+/**
1592+ * ccs_old_chroot_permission - Check permission for chroot().
1593+ *
1594+ * @nd: Pointer to "struct nameidata".
1595+ *
1596+ * Returns 0 on success, negative value otherwise.
1597+ */
1598+static int ccs_old_chroot_permission(struct nameidata *nd)
1599+{
1600+ struct path path = { nd->mnt, nd->dentry };
1601+ return __ccs_chroot_permission(&path);
1602+}
1603+
1604+#endif
1605+
1606+/**
1607+ * ccs_file_init - Register file related hooks.
1608+ *
1609+ * Returns nothing.
1610+ */
1611+void __init ccs_file_init(void)
1612+{
1613+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1614+ ccsecurity_ops.save_open_mode = __ccs_save_open_mode;
1615+ ccsecurity_ops.clear_open_mode = __ccs_clear_open_mode;
1616+ ccsecurity_ops.open_permission = __ccs_open_permission;
1617+#else
1618+ ccsecurity_ops.open_permission = ccs_new_open_permission;
1619+#endif
1620+ ccsecurity_ops.fcntl_permission = __ccs_fcntl_permission;
1621+ ccsecurity_ops.ioctl_permission = __ccs_ioctl_permission;
1622+ ccsecurity_ops.chmod_permission = __ccs_chmod_permission;
1623+ ccsecurity_ops.chown_permission = __ccs_chown_permission;
1624+ ccsecurity_ops.getattr_permission = __ccs_getattr_permission;
1625+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1626+ ccsecurity_ops.pivot_root_permission = __ccs_pivot_root_permission;
1627+ ccsecurity_ops.chroot_permission = __ccs_chroot_permission;
1628+#else
1629+ ccsecurity_ops.pivot_root_permission = ccs_old_pivot_root_permission;
1630+ ccsecurity_ops.chroot_permission = ccs_old_chroot_permission;
1631+#endif
1632+ ccsecurity_ops.umount_permission = __ccs_umount_permission;
1633+ ccsecurity_ops.mknod_permission = __ccs_mknod_permission;
1634+ ccsecurity_ops.mkdir_permission = __ccs_mkdir_permission;
1635+ ccsecurity_ops.rmdir_permission = __ccs_rmdir_permission;
1636+ ccsecurity_ops.unlink_permission = __ccs_unlink_permission;
1637+ ccsecurity_ops.symlink_permission = __ccs_symlink_permission;
1638+ ccsecurity_ops.truncate_permission = __ccs_truncate_permission;
1639+ ccsecurity_ops.rename_permission = __ccs_rename_permission;
1640+ ccsecurity_ops.link_permission = __ccs_link_permission;
1641+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
1642+ ccsecurity_ops.open_exec_permission = __ccs_open_exec_permission;
1643+ ccsecurity_ops.uselib_permission = __ccs_uselib_permission;
1644+#endif
1645+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL))
1646+ ccsecurity_ops.parse_table = __ccs_parse_table;
1647+#endif
1648+};
--- tags/patches/1.0.12/policy_io.c (nonexistent)
+++ tags/patches/1.0.12/policy_io.c (revision 197)
@@ -0,0 +1,2871 @@
1+/*
2+ * security/ccsecurity/policy_io.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1+ 2011/04/11
7+ */
8+
9+#include "internal.h"
10+
11+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
12+
13+/**
14+ * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
15+ *
16+ * @wq: The waitqueue to wait on.
17+ * @condition: A C expression for the event to wait for.
18+ * @ret: Timeout, in jiffies.
19+ *
20+ * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
21+ * signal, and the remaining jiffies otherwise if the condition evaluated to
22+ * true before the timeout elapsed.
23+ *
24+ * This is for compatibility with older kernels.
25+ */
26+#define __wait_event_interruptible_timeout(wq, condition, ret) \
27+do { \
28+ wait_queue_t __wait; \
29+ init_waitqueue_entry(&__wait, current); \
30+ \
31+ add_wait_queue(&wq, &__wait); \
32+ for (;;) { \
33+ set_current_state(TASK_INTERRUPTIBLE); \
34+ if (condition) \
35+ break; \
36+ if (!signal_pending(current)) { \
37+ ret = schedule_timeout(ret); \
38+ if (!ret) \
39+ break; \
40+ continue; \
41+ } \
42+ ret = -ERESTARTSYS; \
43+ break; \
44+ } \
45+ current->state = TASK_RUNNING; \
46+ remove_wait_queue(&wq, &__wait); \
47+} while (0)
48+
49+/**
50+ * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
51+ *
52+ * @wq: The waitqueue to wait on.
53+ * @condition: A C expression for the event to wait for.
54+ * @timeout: Timeout, in jiffies.
55+ *
56+ * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
57+ * signal, and the remaining jiffies otherwise if the condition evaluated to
58+ * true before the timeout elapsed.
59+ *
60+ * This is for compatibility with older kernels.
61+ */
62+#define wait_event_interruptible_timeout(wq, condition, timeout) \
63+({ \
64+ long __ret = timeout; \
65+ if (!(condition)) \
66+ __wait_event_interruptible_timeout(wq, condition, __ret); \
67+ __ret; \
68+})
69+
70+#endif
71+
72+/**
73+ * list_for_each_cookie - iterate over a list with cookie.
74+ *
75+ * @pos: Pointer to "struct list_head".
76+ * @head: Pointer to "struct list_head".
77+ */
78+#define list_for_each_cookie(pos, head) \
79+ for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
80+ pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
81+
82+
83+/* Profile version. Currently only 20100903 is defined. */
84+static unsigned int ccs_profile_version;
85+
86+/* Profile table. Memory is allocated as needed. */
87+static struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];
88+
89+/* String table for operation mode. */
90+const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
91+ [CCS_CONFIG_DISABLED] = "disabled",
92+ [CCS_CONFIG_LEARNING] = "learning",
93+ [CCS_CONFIG_PERMISSIVE] = "permissive",
94+ [CCS_CONFIG_ENFORCING] = "enforcing"
95+};
96+
97+/* String table for /proc/ccs/profile interface. */
98+const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
99+ + CCS_MAX_MAC_CATEGORY_INDEX] = {
100+ /* CONFIG::file group */
101+ [CCS_MAC_FILE_EXECUTE] = "execute",
102+ [CCS_MAC_FILE_OPEN] = "open",
103+ [CCS_MAC_FILE_CREATE] = "create",
104+ [CCS_MAC_FILE_UNLINK] = "unlink",
105+ [CCS_MAC_FILE_GETATTR] = "getattr",
106+ [CCS_MAC_FILE_MKDIR] = "mkdir",
107+ [CCS_MAC_FILE_RMDIR] = "rmdir",
108+ [CCS_MAC_FILE_MKFIFO] = "mkfifo",
109+ [CCS_MAC_FILE_MKSOCK] = "mksock",
110+ [CCS_MAC_FILE_TRUNCATE] = "truncate",
111+ [CCS_MAC_FILE_SYMLINK] = "symlink",
112+ [CCS_MAC_FILE_MKBLOCK] = "mkblock",
113+ [CCS_MAC_FILE_MKCHAR] = "mkchar",
114+ [CCS_MAC_FILE_LINK] = "link",
115+ [CCS_MAC_FILE_RENAME] = "rename",
116+ [CCS_MAC_FILE_CHMOD] = "chmod",
117+ [CCS_MAC_FILE_CHOWN] = "chown",
118+ [CCS_MAC_FILE_CHGRP] = "chgrp",
119+ [CCS_MAC_FILE_IOCTL] = "ioctl",
120+ [CCS_MAC_FILE_CHROOT] = "chroot",
121+ [CCS_MAC_FILE_MOUNT] = "mount",
122+ [CCS_MAC_FILE_UMOUNT] = "unmount",
123+ [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
124+ /* CONFIG::misc group */
125+ [CCS_MAC_ENVIRON] = "env",
126+ /* CONFIG::network group */
127+ [CCS_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind",
128+ [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen",
129+ [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect",
130+ [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = "inet_stream_accept",
131+ [CCS_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind",
132+ [CCS_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
133+ [CCS_MAC_NETWORK_INET_DGRAM_RECV] = "inet_dgram_recv",
134+ [CCS_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
135+ [CCS_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
136+ [CCS_MAC_NETWORK_INET_RAW_RECV] = "inet_raw_recv",
137+ [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
138+ [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
139+ [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
140+ [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = "unix_stream_accept",
141+ [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind",
142+ [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send",
143+ [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = "unix_dgram_recv",
144+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
145+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
146+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
147+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = "unix_seqpacket_accept",
148+ /* CONFIG::ipc group */
149+ [CCS_MAC_SIGNAL] = "signal",
150+ /* CONFIG::capability group */
151+ [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = "use_route",
152+ [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
153+ [CCS_MAC_CAPABILITY_SYS_REBOOT] = "SYS_REBOOT",
154+ [CCS_MAC_CAPABILITY_SYS_VHANGUP] = "SYS_VHANGUP",
155+ [CCS_MAC_CAPABILITY_SYS_SETTIME] = "SYS_TIME",
156+ [CCS_MAC_CAPABILITY_SYS_NICE] = "SYS_NICE",
157+ [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
158+ [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
159+ [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
160+ [CCS_MAC_CAPABILITY_SYS_PTRACE] = "SYS_PTRACE",
161+ /* CONFIG group */
162+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE] = "file",
163+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK] = "network",
164+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC] = "misc",
165+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC] = "ipc",
166+ [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
167+};
168+
169+/* String table for path operation. */
170+const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
171+ [CCS_TYPE_EXECUTE] = "execute",
172+ [CCS_TYPE_READ] = "read",
173+ [CCS_TYPE_WRITE] = "write",
174+ [CCS_TYPE_APPEND] = "append",
175+ [CCS_TYPE_UNLINK] = "unlink",
176+ [CCS_TYPE_GETATTR] = "getattr",
177+ [CCS_TYPE_RMDIR] = "rmdir",
178+ [CCS_TYPE_TRUNCATE] = "truncate",
179+ [CCS_TYPE_SYMLINK] = "symlink",
180+ [CCS_TYPE_CHROOT] = "chroot",
181+ [CCS_TYPE_UMOUNT] = "unmount",
182+};
183+
184+/* String table for categories. */
185+static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
186+ [CCS_MAC_CATEGORY_FILE] = "file",
187+ [CCS_MAC_CATEGORY_NETWORK] = "network",
188+ [CCS_MAC_CATEGORY_MISC] = "misc",
189+ [CCS_MAC_CATEGORY_IPC] = "ipc",
190+ [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
191+};
192+
193+/* String table for conditions. */
194+const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
195+ [CCS_TASK_UID] = "task.uid",
196+ [CCS_TASK_EUID] = "task.euid",
197+ [CCS_TASK_SUID] = "task.suid",
198+ [CCS_TASK_FSUID] = "task.fsuid",
199+ [CCS_TASK_GID] = "task.gid",
200+ [CCS_TASK_EGID] = "task.egid",
201+ [CCS_TASK_SGID] = "task.sgid",
202+ [CCS_TASK_FSGID] = "task.fsgid",
203+ [CCS_TASK_PID] = "task.pid",
204+ [CCS_TASK_PPID] = "task.ppid",
205+ [CCS_EXEC_ARGC] = "exec.argc",
206+ [CCS_EXEC_ENVC] = "exec.envc",
207+ [CCS_TYPE_IS_SOCKET] = "socket",
208+ [CCS_TYPE_IS_SYMLINK] = "symlink",
209+ [CCS_TYPE_IS_FILE] = "file",
210+ [CCS_TYPE_IS_BLOCK_DEV] = "block",
211+ [CCS_TYPE_IS_DIRECTORY] = "directory",
212+ [CCS_TYPE_IS_CHAR_DEV] = "char",
213+ [CCS_TYPE_IS_FIFO] = "fifo",
214+ [CCS_MODE_SETUID] = "setuid",
215+ [CCS_MODE_SETGID] = "setgid",
216+ [CCS_MODE_STICKY] = "sticky",
217+ [CCS_MODE_OWNER_READ] = "owner_read",
218+ [CCS_MODE_OWNER_WRITE] = "owner_write",
219+ [CCS_MODE_OWNER_EXECUTE] = "owner_execute",
220+ [CCS_MODE_GROUP_READ] = "group_read",
221+ [CCS_MODE_GROUP_WRITE] = "group_write",
222+ [CCS_MODE_GROUP_EXECUTE] = "group_execute",
223+ [CCS_MODE_OTHERS_READ] = "others_read",
224+ [CCS_MODE_OTHERS_WRITE] = "others_write",
225+ [CCS_MODE_OTHERS_EXECUTE] = "others_execute",
226+ [CCS_TASK_TYPE] = "task.type",
227+ [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
228+ [CCS_EXEC_REALPATH] = "exec.realpath",
229+ [CCS_SYMLINK_TARGET] = "symlink.target",
230+ [CCS_PATH1_UID] = "path1.uid",
231+ [CCS_PATH1_GID] = "path1.gid",
232+ [CCS_PATH1_INO] = "path1.ino",
233+ [CCS_PATH1_MAJOR] = "path1.major",
234+ [CCS_PATH1_MINOR] = "path1.minor",
235+ [CCS_PATH1_PERM] = "path1.perm",
236+ [CCS_PATH1_TYPE] = "path1.type",
237+ [CCS_PATH1_DEV_MAJOR] = "path1.dev_major",
238+ [CCS_PATH1_DEV_MINOR] = "path1.dev_minor",
239+ [CCS_PATH2_UID] = "path2.uid",
240+ [CCS_PATH2_GID] = "path2.gid",
241+ [CCS_PATH2_INO] = "path2.ino",
242+ [CCS_PATH2_MAJOR] = "path2.major",
243+ [CCS_PATH2_MINOR] = "path2.minor",
244+ [CCS_PATH2_PERM] = "path2.perm",
245+ [CCS_PATH2_TYPE] = "path2.type",
246+ [CCS_PATH2_DEV_MAJOR] = "path2.dev_major",
247+ [CCS_PATH2_DEV_MINOR] = "path2.dev_minor",
248+ [CCS_PATH1_PARENT_UID] = "path1.parent.uid",
249+ [CCS_PATH1_PARENT_GID] = "path1.parent.gid",
250+ [CCS_PATH1_PARENT_INO] = "path1.parent.ino",
251+ [CCS_PATH1_PARENT_PERM] = "path1.parent.perm",
252+ [CCS_PATH2_PARENT_UID] = "path2.parent.uid",
253+ [CCS_PATH2_PARENT_GID] = "path2.parent.gid",
254+ [CCS_PATH2_PARENT_INO] = "path2.parent.ino",
255+ [CCS_PATH2_PARENT_PERM] = "path2.parent.perm",
256+};
257+
258+/* String table for PREFERENCE keyword. */
259+static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
260+ [CCS_PREF_MAX_AUDIT_LOG] = "max_audit_log",
261+ [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
262+ [CCS_PREF_ENFORCING_PENALTY] = "enforcing_penalty",
263+};
264+
265+/* Permit policy management by non-root user? */
266+static bool ccs_manage_by_non_root;
267+
268+/**
269+ * ccs_yesno - Return "yes" or "no".
270+ *
271+ * @value: Bool value.
272+ *
273+ * Returns "yes" if @value is not 0, "no" otherwise.
274+ */
275+const char *ccs_yesno(const unsigned int value)
276+{
277+ return value ? "yes" : "no";
278+}
279+
280+/* Prototype for ccs_addprintf(). */
281+static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
282+ __attribute__ ((format(printf, 3, 4)));
283+
284+/**
285+ * ccs_addprintf - strncat()-like-snprintf().
286+ *
287+ * @buffer: Buffer to write to. Must be '\0'-terminated.
288+ * @len: Size of @buffer.
289+ * @fmt: The printf()'s format string, followed by parameters.
290+ *
291+ * Returns nothing.
292+ */
293+static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
294+{
295+ va_list args;
296+ const int pos = strlen(buffer);
297+ va_start(args, fmt);
298+ vsnprintf(buffer + pos, len - pos - 1, fmt, args);
299+ va_end(args);
300+}
301+
302+/**
303+ * ccs_flush - Flush queued string to userspace's buffer.
304+ *
305+ * @head: Pointer to "struct ccs_io_buffer".
306+ *
307+ * Returns true if all data was flushed, false otherwise.
308+ */
309+static bool ccs_flush(struct ccs_io_buffer *head)
310+{
311+ while (head->r.w_pos) {
312+ const char *w = head->r.w[0];
313+ size_t len = strlen(w);
314+ if (len) {
315+ if (len > head->read_user_buf_avail)
316+ len = head->read_user_buf_avail;
317+ if (!len)
318+ return false;
319+ if (copy_to_user(head->read_user_buf, w, len))
320+ return false;
321+ head->read_user_buf_avail -= len;
322+ head->read_user_buf += len;
323+ w += len;
324+ }
325+ head->r.w[0] = w;
326+ if (*w)
327+ return false;
328+ /* Add '\0' for audit logs and query. */
329+ if (head->poll) {
330+ if (!head->read_user_buf_avail ||
331+ copy_to_user(head->read_user_buf, "", 1))
332+ return false;
333+ head->read_user_buf_avail--;
334+ head->read_user_buf++;
335+ }
336+ head->r.w_pos--;
337+ for (len = 0; len < head->r.w_pos; len++)
338+ head->r.w[len] = head->r.w[len + 1];
339+ }
340+ head->r.avail = 0;
341+ return true;
342+}
343+
344+/**
345+ * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
346+ *
347+ * @head: Pointer to "struct ccs_io_buffer".
348+ * @string: String to print.
349+ *
350+ * Returns nothing.
351+ *
352+ * Note that @string has to be kept valid until @head is kfree()d.
353+ * This means that char[] allocated on stack memory cannot be passed to
354+ * this function. Use ccs_io_printf() for char[] allocated on stack memory.
355+ */
356+static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
357+{
358+ if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
359+ head->r.w[head->r.w_pos++] = string;
360+ ccs_flush(head);
361+ } else
362+ printk(KERN_WARNING "Too many words in a line.\n");
363+}
364+
365+/* Prototype for ccs_io_printf(). */
366+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
367+ __attribute__ ((format(printf, 2, 3)));
368+
369+/**
370+ * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
371+ *
372+ * @head: Pointer to "struct ccs_io_buffer".
373+ * @fmt: The printf()'s format string, followed by parameters.
374+ *
375+ * Returns nothing.
376+ */
377+static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
378+{
379+ va_list args;
380+ size_t len;
381+ size_t pos = head->r.avail;
382+ int size = head->readbuf_size - pos;
383+ if (size <= 0)
384+ return;
385+ va_start(args, fmt);
386+ len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
387+ va_end(args);
388+ if (pos + len >= head->readbuf_size) {
389+ printk(KERN_WARNING "Too many words in a line.\n");
390+ return;
391+ }
392+ head->r.avail += len;
393+ ccs_set_string(head, head->read_buf + pos);
394+}
395+
396+/**
397+ * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
398+ *
399+ * @head: Pointer to "struct ccs_io_buffer".
400+ *
401+ * Returns nothing.
402+ */
403+static void ccs_set_space(struct ccs_io_buffer *head)
404+{
405+ ccs_set_string(head, " ");
406+}
407+
408+/**
409+ * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
410+ *
411+ * @head: Pointer to "struct ccs_io_buffer".
412+ *
413+ * Returns nothing.
414+ */
415+static bool ccs_set_lf(struct ccs_io_buffer *head)
416+{
417+ ccs_set_string(head, "\n");
418+ return !head->r.w_pos;
419+}
420+
421+/**
422+ * ccs_set_slash - Put a shash to "struct ccs_io_buffer" structure.
423+ *
424+ * @head: Pointer to "struct ccs_io_buffer".
425+ *
426+ * Returns nothing.
427+ */
428+static void ccs_set_slash(struct ccs_io_buffer *head)
429+{
430+ ccs_set_string(head, "/");
431+}
432+
433+/**
434+ * ccs_assign_profile - Create a new profile.
435+ *
436+ * @profile: Profile number to create.
437+ *
438+ * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
439+ */
440+static struct ccs_profile *ccs_assign_profile(const unsigned int profile)
441+{
442+ struct ccs_profile *ptr;
443+ struct ccs_profile *entry;
444+ if (profile >= CCS_MAX_PROFILES)
445+ return NULL;
446+ ptr = ccs_profile_ptr[profile];
447+ if (ptr)
448+ return ptr;
449+ entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
450+ if (mutex_lock_interruptible(&ccs_policy_lock))
451+ goto out;
452+ ptr = ccs_profile_ptr[profile];
453+ if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
454+ ptr = entry;
455+ ptr->default_config = CCS_CONFIG_DISABLED |
456+ CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
457+ memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
458+ sizeof(ptr->config));
459+ ptr->pref[CCS_PREF_MAX_AUDIT_LOG] =
460+ CONFIG_CCSECURITY_MAX_AUDIT_LOG;
461+ ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
462+ CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
463+ mb(); /* Avoid out-of-order execution. */
464+ ccs_profile_ptr[profile] = ptr;
465+ entry = NULL;
466+ }
467+ mutex_unlock(&ccs_policy_lock);
468+out:
469+ kfree(entry);
470+ return ptr;
471+}
472+
473+/**
474+ * ccs_check_profile - Check all profiles currently assigned to domains are defined.
475+ *
476+ * Returns nothing.
477+ */
478+static void ccs_check_profile(void)
479+{
480+ struct ccs_domain_info *domain;
481+ const int idx = ccs_read_lock();
482+ ccs_policy_loaded = true;
483+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
484+ const u8 profile = domain->profile;
485+ if (ccs_profile_ptr[profile])
486+ continue;
487+ printk(KERN_ERR "Profile %u must be defined before using it.\n",
488+ profile);
489+ printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
490+ "for more information.\n");
491+ panic("Profile %u (used by '%s') not defined.\n",
492+ profile, domain->domainname->name);
493+ }
494+ ccs_read_unlock(idx);
495+ if (ccs_profile_version != 20100903) {
496+ printk(KERN_ERR "Userland tools must be installed for "
497+ "TOMOYO 1.8, and policy must be initialized.\n");
498+ printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
499+ "for more information.\n");
500+ panic("Profile version %u is not supported.\n",
501+ ccs_profile_version);
502+ }
503+ printk(KERN_INFO "CCSecurity: 1.8.1+ 2011/04/11\n");
504+ printk(KERN_INFO "Mandatory Access Control activated.\n");
505+}
506+
507+/**
508+ * ccs_profile - Find a profile.
509+ *
510+ * @profile: Profile number to find.
511+ *
512+ * Returns pointer to "struct ccs_profile".
513+ */
514+struct ccs_profile *ccs_profile(const u8 profile)
515+{
516+ static struct ccs_profile ccs_null_profile;
517+ struct ccs_profile *ptr = ccs_profile_ptr[profile];
518+ if (!ptr)
519+ ptr = &ccs_null_profile;
520+ return ptr;
521+}
522+
523+/**
524+ * ccs_find_yesno - Find values for specified keyword.
525+ *
526+ * @string: String to check.
527+ * @find: Name of keyword.
528+ *
529+ * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
530+ */
531+static s8 ccs_find_yesno(const char *string, const char *find)
532+{
533+ const char *cp = strstr(string, find);
534+ if (cp) {
535+ cp += strlen(find);
536+ if (!strncmp(cp, "=yes", 4))
537+ return 1;
538+ else if (!strncmp(cp, "=no", 3))
539+ return 0;
540+ }
541+ return -1;
542+}
543+
544+/**
545+ * ccs_set_uint - Set value for specified preference.
546+ *
547+ * @i: Pointer to "unsigned int".
548+ * @string: String to check.
549+ * @find: Name of keyword.
550+ *
551+ * Returns nothing.
552+ */
553+static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
554+{
555+ const char *cp = strstr(string, find);
556+ if (cp)
557+ sscanf(cp + strlen(find), "=%u", i);
558+}
559+
560+/**
561+ * ccs_set_mode - Set mode for specified profile.
562+ *
563+ * @name: Name of functionality.
564+ * @value: Mode for @name.
565+ * @profile: Pointer to "struct ccs_profile".
566+ *
567+ * Returns 0 on success, negative value otherwise.
568+ */
569+static int ccs_set_mode(char *name, const char *value,
570+ struct ccs_profile *profile)
571+{
572+ u8 i;
573+ u8 config;
574+ if (!strcmp(name, "CONFIG")) {
575+ i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
576+ config = profile->default_config;
577+ } else if (ccs_str_starts(&name, "CONFIG::")) {
578+ config = 0;
579+ for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
580+ i++) {
581+ int len = 0;
582+ if (i < CCS_MAX_MAC_INDEX) {
583+ const u8 c = ccs_index2category[i];
584+ const char *category =
585+ ccs_category_keywords[c];
586+ len = strlen(category);
587+ if (strncmp(name, category, len) ||
588+ name[len++] != ':' || name[len++] != ':')
589+ continue;
590+ }
591+ if (strcmp(name + len, ccs_mac_keywords[i]))
592+ continue;
593+ config = profile->config[i];
594+ break;
595+ }
596+ if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
597+ return -EINVAL;
598+ } else {
599+ return -EINVAL;
600+ }
601+ if (strstr(value, "use_default")) {
602+ config = CCS_CONFIG_USE_DEFAULT;
603+ } else {
604+ u8 mode;
605+ for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
606+ if (strstr(value, ccs_mode[mode]))
607+ /*
608+ * Update lower 3 bits in order to distinguish
609+ * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
610+ */
611+ config = (config & ~7) | mode;
612+ if (config != CCS_CONFIG_USE_DEFAULT) {
613+ switch (ccs_find_yesno(value, "grant_log")) {
614+ case 1:
615+ config |= CCS_CONFIG_WANT_GRANT_LOG;
616+ break;
617+ case 0:
618+ config &= ~CCS_CONFIG_WANT_GRANT_LOG;
619+ break;
620+ }
621+ switch (ccs_find_yesno(value, "reject_log")) {
622+ case 1:
623+ config |= CCS_CONFIG_WANT_REJECT_LOG;
624+ break;
625+ case 0:
626+ config &= ~CCS_CONFIG_WANT_REJECT_LOG;
627+ break;
628+ }
629+ }
630+ }
631+ if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
632+ profile->config[i] = config;
633+ else if (config != CCS_CONFIG_USE_DEFAULT)
634+ profile->default_config = config;
635+ return 0;
636+}
637+
638+/**
639+ * ccs_write_profile - Write profile table.
640+ *
641+ * @head: Pointer to "struct ccs_io_buffer".
642+ *
643+ * Returns 0 on success, negative value otherwise.
644+ */
645+static int ccs_write_profile(struct ccs_io_buffer *head)
646+{
647+ char *data = head->write_buf;
648+ unsigned int i;
649+ char *cp;
650+ struct ccs_profile *profile;
651+ if (sscanf(data, "PROFILE_VERSION=%u", &ccs_profile_version) == 1)
652+ return 0;
653+ i = simple_strtoul(data, &cp, 10);
654+ if (*cp != '-')
655+ return -EINVAL;
656+ data = cp + 1;
657+ profile = ccs_assign_profile(i);
658+ if (!profile)
659+ return -EINVAL;
660+ cp = strchr(data, '=');
661+ if (!cp)
662+ return -EINVAL;
663+ *cp++ = '\0';
664+ if (!strcmp(data, "COMMENT")) {
665+ static DEFINE_SPINLOCK(lock);
666+ const struct ccs_path_info *new_comment = ccs_get_name(cp);
667+ const struct ccs_path_info *old_comment;
668+ if (!new_comment)
669+ return -ENOMEM;
670+ spin_lock(&lock);
671+ old_comment = profile->comment;
672+ profile->comment = new_comment;
673+ spin_unlock(&lock);
674+ ccs_put_name(old_comment);
675+ return 0;
676+ }
677+ if (!strcmp(data, "PREFERENCE")) {
678+ for (i = 0; i < CCS_MAX_PREF; i++)
679+ ccs_set_uint(&profile->pref[i], cp,
680+ ccs_pref_keywords[i]);
681+ return 0;
682+ }
683+ return ccs_set_mode(data, cp, profile);
684+}
685+
686+/**
687+ * ccs_print_config - Print mode for specified functionality.
688+ *
689+ * @head: Pointer to "struct ccs_io_buffer".
690+ * @config: Mode for that functionality.
691+ *
692+ * Returns nothing.
693+ *
694+ * Caller prints functionality's name.
695+ */
696+static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)
697+{
698+ ccs_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
699+ ccs_mode[config & 3],
700+ ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),
701+ ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));
702+}
703+
704+/**
705+ * ccs_read_profile - Read profile table.
706+ *
707+ * @head: Pointer to "struct ccs_io_buffer".
708+ *
709+ * Returns nothing.
710+ */
711+static void ccs_read_profile(struct ccs_io_buffer *head)
712+{
713+ u8 index;
714+ const struct ccs_profile *profile;
715+next:
716+ index = head->r.index;
717+ profile = ccs_profile_ptr[index];
718+ switch (head->r.step) {
719+ case 0:
720+ ccs_io_printf(head, "PROFILE_VERSION=%u\n", 20100903);
721+ head->r.step++;
722+ break;
723+ case 1:
724+ for ( ; head->r.index < CCS_MAX_PROFILES;
725+ head->r.index++)
726+ if (ccs_profile_ptr[head->r.index])
727+ break;
728+ if (head->r.index == CCS_MAX_PROFILES)
729+ return;
730+ head->r.step++;
731+ break;
732+ case 2:
733+ {
734+ u8 i;
735+ const struct ccs_path_info *comment = profile->comment;
736+ ccs_io_printf(head, "%u-COMMENT=", index);
737+ ccs_set_string(head, comment ? comment->name : "");
738+ ccs_set_lf(head);
739+ ccs_io_printf(head, "%u-PREFERENCE={ ", index);
740+ for (i = 0; i < CCS_MAX_PREF; i++)
741+ ccs_io_printf(head, "%s=%u ",
742+ ccs_pref_keywords[i],
743+ profile->pref[i]);
744+ ccs_set_string(head, " }\n");
745+ head->r.step++;
746+ }
747+ break;
748+ case 3:
749+ {
750+ ccs_io_printf(head, "%u-%s", index, "CONFIG");
751+ ccs_print_config(head, profile->default_config);
752+ head->r.bit = 0;
753+ head->r.step++;
754+ }
755+ break;
756+ case 4:
757+ for ( ; head->r.bit < CCS_MAX_MAC_INDEX
758+ + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
759+ const u8 i = head->r.bit;
760+ const u8 config = profile->config[i];
761+ if (config == CCS_CONFIG_USE_DEFAULT)
762+ continue;
763+ if (i < CCS_MAX_MAC_INDEX)
764+ ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
765+ ccs_category_keywords
766+ [ccs_index2category[i]],
767+ ccs_mac_keywords[i]);
768+ else
769+ ccs_io_printf(head, "%u-CONFIG::%s", index,
770+ ccs_mac_keywords[i]);
771+ ccs_print_config(head, config);
772+ head->r.bit++;
773+ break;
774+ }
775+ if (head->r.bit == CCS_MAX_MAC_INDEX
776+ + CCS_MAX_MAC_CATEGORY_INDEX) {
777+ head->r.index++;
778+ head->r.step = 1;
779+ }
780+ break;
781+ }
782+ if (ccs_flush(head))
783+ goto next;
784+}
785+
786+/**
787+ * ccs_same_manager - Check for duplicated "struct ccs_manager" entry.
788+ *
789+ * @a: Pointer to "struct ccs_acl_head".
790+ * @b: Pointer to "struct ccs_acl_head".
791+ *
792+ * Returns true if @a == @b, false otherwise.
793+ */
794+static bool ccs_same_manager(const struct ccs_acl_head *a,
795+ const struct ccs_acl_head *b)
796+{
797+ return container_of(a, struct ccs_manager, head)->manager
798+ == container_of(b, struct ccs_manager, head)->manager;
799+}
800+
801+/**
802+ * ccs_update_manager_entry - Add a manager entry.
803+ *
804+ * @manager: The path to manager or the domainnamme.
805+ * @is_delete: True if it is a delete request.
806+ *
807+ * Returns 0 on success, negative value otherwise.
808+ */
809+static int ccs_update_manager_entry(const char *manager, const bool is_delete)
810+{
811+ struct ccs_manager e = { };
812+ int error = is_delete ? -ENOENT : -ENOMEM;
813+ if (ccs_domain_def(manager)) {
814+ if (!ccs_correct_domain(manager))
815+ return -EINVAL;
816+ e.is_domain = true;
817+ } else {
818+ if (!ccs_correct_path(manager))
819+ return -EINVAL;
820+ }
821+ e.manager = ccs_get_name(manager);
822+ if (!e.manager)
823+ return error;
824+ error = ccs_update_policy(&e.head, sizeof(e), is_delete,
825+ &ccs_policy_list[CCS_ID_MANAGER],
826+ ccs_same_manager);
827+ ccs_put_name(e.manager);
828+ return error;
829+}
830+
831+/**
832+ * ccs_write_manager - Write manager policy.
833+ *
834+ * @head: Pointer to "struct ccs_io_buffer".
835+ *
836+ * Returns 0 on success, negative value otherwise.
837+ */
838+static int ccs_write_manager(struct ccs_io_buffer *head)
839+{
840+ char *data = head->write_buf;
841+ bool is_delete = ccs_str_starts(&data, "delete ");
842+ if (!strcmp(data, "manage_by_non_root")) {
843+ ccs_manage_by_non_root = !is_delete;
844+ return 0;
845+ }
846+ return ccs_update_manager_entry(data, is_delete);
847+}
848+
849+/**
850+ * ccs_read_manager - Read manager policy.
851+ *
852+ * @head: Pointer to "struct ccs_io_buffer".
853+ *
854+ * Returns nothing.
855+ *
856+ * Caller holds ccs_read_lock().
857+ */
858+static void ccs_read_manager(struct ccs_io_buffer *head)
859+{
860+ if (head->r.eof)
861+ return;
862+ list_for_each_cookie(head->r.acl, &ccs_policy_list[CCS_ID_MANAGER]) {
863+ struct ccs_manager *ptr =
864+ list_entry(head->r.acl, typeof(*ptr), head.list);
865+ if (ptr->head.is_deleted)
866+ continue;
867+ if (!ccs_flush(head))
868+ return;
869+ ccs_set_string(head, ptr->manager->name);
870+ ccs_set_lf(head);
871+ }
872+ head->r.eof = true;
873+}
874+
875+/**
876+ * ccs_manager - Check whether the current process is a policy manager.
877+ *
878+ * Returns true if the current process is permitted to modify policy
879+ * via /proc/ccs/ interface.
880+ *
881+ * Caller holds ccs_read_lock().
882+ */
883+static bool ccs_manager(void)
884+{
885+ struct ccs_manager *ptr;
886+ const char *exe;
887+ struct ccs_security *task = ccs_current_security();
888+ const struct ccs_path_info *domainname
889+ = ccs_current_domain()->domainname;
890+ bool found = false;
891+ if (!ccs_policy_loaded)
892+ return true;
893+ if (task->ccs_flags & CCS_TASK_IS_MANAGER)
894+ return true;
895+ if (!ccs_manage_by_non_root && (current_uid() || current_euid()))
896+ return false;
897+ exe = ccs_get_exe();
898+ list_for_each_entry_srcu(ptr, &ccs_policy_list[CCS_ID_MANAGER],
899+ head.list, &ccs_ss) {
900+ if (ptr->head.is_deleted)
901+ continue;
902+ if (ptr->is_domain) {
903+ if (ccs_pathcmp(domainname, ptr->manager))
904+ continue;
905+ } else {
906+ if (!exe || strcmp(exe, ptr->manager->name))
907+ continue;
908+ }
909+ /* Set manager flag. */
910+ task->ccs_flags |= CCS_TASK_IS_MANAGER;
911+ found = true;
912+ break;
913+ }
914+ if (!found) { /* Reduce error messages. */
915+ static pid_t ccs_last_pid;
916+ const pid_t pid = current->pid;
917+ if (ccs_last_pid != pid) {
918+ printk(KERN_WARNING "%s ( %s ) is not permitted to "
919+ "update policies.\n", domainname->name, exe);
920+ ccs_last_pid = pid;
921+ }
922+ }
923+ kfree(exe);
924+ return found;
925+}
926+
927+/**
928+ * ccs_select_one - Parse select command.
929+ *
930+ * @head: Pointer to "struct ccs_io_buffer".
931+ * @data: String to parse.
932+ *
933+ * Returns true on success, false otherwise.
934+ *
935+ * Caller holds ccs_read_lock().
936+ */
937+static bool ccs_select_one(struct ccs_io_buffer *head, const char *data)
938+{
939+ unsigned int pid;
940+ struct ccs_domain_info *domain = NULL;
941+ bool global_pid = false;
942+ if (!strcmp(data, "transition_only")) {
943+ head->r.print_transition_related_only = true;
944+ return true;
945+ }
946+ if (sscanf(data, "pid=%u", &pid) == 1 ||
947+ (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
948+ struct task_struct *p;
949+ ccs_tasklist_lock();
950+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
951+ if (global_pid)
952+ p = ccsecurity_exports.find_task_by_pid_ns(pid,
953+ &init_pid_ns);
954+ else
955+ p = ccsecurity_exports.find_task_by_vpid(pid);
956+#else
957+ p = find_task_by_pid(pid);
958+#endif
959+ if (p)
960+ domain = ccs_task_domain(p);
961+ ccs_tasklist_unlock();
962+ } else if (!strncmp(data, "domain=", 7)) {
963+ if (ccs_domain_def(data + 7))
964+ domain = ccs_find_domain(data + 7);
965+ } else
966+ return false;
967+ head->w.domain = domain;
968+ /* Accessing read_buf is safe because head->io_sem is held. */
969+ if (!head->read_buf)
970+ return true; /* Do nothing if open(O_WRONLY). */
971+ memset(&head->r, 0, sizeof(head->r));
972+ head->r.print_this_domain_only = true;
973+ if (domain)
974+ head->r.domain = &domain->list;
975+ else
976+ head->r.eof = true;
977+ ccs_io_printf(head, "# select %s\n", data);
978+ if (domain && domain->is_deleted)
979+ ccs_set_string(head, "# This is a deleted domain.\n");
980+ return true;
981+}
982+
983+/**
984+ * ccs_same_handler_acl - Check for duplicated "struct ccs_handler_acl" entry.
985+ *
986+ * @a: Pointer to "struct ccs_acl_info".
987+ * @b: Pointer to "struct ccs_acl_info".
988+ *
989+ * Returns true if @a == @b, false otherwise.
990+ */
991+static bool ccs_same_handler_acl(const struct ccs_acl_info *a,
992+ const struct ccs_acl_info *b)
993+{
994+ const struct ccs_handler_acl *p1 = container_of(a, typeof(*p1), head);
995+ const struct ccs_handler_acl *p2 = container_of(b, typeof(*p2), head);
996+ return p1->handler == p2->handler;
997+}
998+
999+/**
1000+ * ccs_same_task_acl - Check for duplicated "struct ccs_task_acl" entry.
1001+ *
1002+ * @a: Pointer to "struct ccs_acl_info".
1003+ * @b: Pointer to "struct ccs_acl_info".
1004+ *
1005+ * Returns true if @a == @b, false otherwise.
1006+ */
1007+static bool ccs_same_task_acl(const struct ccs_acl_info *a,
1008+ const struct ccs_acl_info *b)
1009+{
1010+ const struct ccs_task_acl *p1 = container_of(a, typeof(*p1), head);
1011+ const struct ccs_task_acl *p2 = container_of(b, typeof(*p2), head);
1012+ return p1->domainname == p2->domainname;
1013+}
1014+
1015+/**
1016+ * ccs_write_task - Update task related list.
1017+ *
1018+ * @param: Pointer to "struct ccs_acl_param".
1019+ *
1020+ * Returns 0 on success, negative value otherwise.
1021+ */
1022+static int ccs_write_task(struct ccs_acl_param *param)
1023+{
1024+ int error;
1025+ const bool is_auto = ccs_str_starts(&param->data,
1026+ "auto_domain_transition ");
1027+ if (!is_auto && !ccs_str_starts(&param->data,
1028+ "manual_domain_transition ")) {
1029+ struct ccs_handler_acl e = { };
1030+ char *handler;
1031+ if (ccs_str_starts(&param->data, "auto_execute_handler "))
1032+ e.head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
1033+ else if (ccs_str_starts(&param->data,
1034+ "denied_execute_handler "))
1035+ e.head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
1036+ else
1037+ return -EINVAL;
1038+ handler = ccs_read_token(param);
1039+ if (!ccs_correct_path(handler))
1040+ return -EINVAL;
1041+ e.handler = ccs_get_name(handler);
1042+ if (!e.handler)
1043+ return -ENOMEM;
1044+ if (e.handler->is_patterned)
1045+ error = -EINVAL; /* No patterns allowed. */
1046+ else
1047+ error = ccs_update_domain(&e.head, sizeof(e), param,
1048+ ccs_same_handler_acl, NULL);
1049+ ccs_put_name(e.handler);
1050+ } else {
1051+ struct ccs_task_acl e = {
1052+ .head.type = is_auto ?
1053+ CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL,
1054+ .domainname = ccs_get_domainname(param),
1055+ };
1056+ if (!e.domainname)
1057+ error = -EINVAL;
1058+ else
1059+ error = ccs_update_domain(&e.head, sizeof(e), param,
1060+ ccs_same_task_acl, NULL);
1061+ ccs_put_name(e.domainname);
1062+ }
1063+ return error;
1064+}
1065+
1066+/**
1067+ * ccs_write_domain2 - Write domain policy.
1068+ *
1069+ * @data: Policy to be interpreted.
1070+ * @domain: Pointer to "struct ccs_domain_info".
1071+ * @is_delete: True if it is a delete request.
1072+ *
1073+ * Returns 0 on success, negative value otherwise.
1074+ */
1075+static int ccs_write_domain2(char *data, struct ccs_domain_info *domain,
1076+ const bool is_delete)
1077+{
1078+ struct ccs_acl_param param = {
1079+ .data = data,
1080+ .domain = domain,
1081+ .is_delete = is_delete,
1082+ };
1083+ static const struct {
1084+ const char *keyword;
1085+ int (*write) (struct ccs_acl_param *);
1086+ } ccs_callback[7] = {
1087+ { "file ", ccs_write_file },
1088+ { "network inet ", ccs_write_inet_network },
1089+ { "network unix ", ccs_write_unix_network },
1090+ { "misc ", ccs_write_misc },
1091+ { "capability ", ccs_write_capability },
1092+ { "ipc ", ccs_write_ipc },
1093+ { "task ", ccs_write_task },
1094+ };
1095+ u8 i;
1096+ for (i = 0; i < 7; i++) {
1097+ if (!ccs_str_starts(&param.data, ccs_callback[i].keyword))
1098+ continue;
1099+ return ccs_callback[i].write(&param);
1100+ }
1101+ return -EINVAL;
1102+}
1103+
1104+/* String table for domain flags. */
1105+const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
1106+ [CCS_DIF_QUOTA_WARNED] = "quota_exceeded\n",
1107+ [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
1108+};
1109+
1110+/**
1111+ * ccs_write_domain - Write domain policy.
1112+ *
1113+ * @head: Pointer to "struct ccs_io_buffer".
1114+ *
1115+ * Returns 0 on success, negative value otherwise.
1116+ */
1117+static int ccs_write_domain(struct ccs_io_buffer *head)
1118+{
1119+ char *data = head->write_buf;
1120+ struct ccs_domain_info *domain = head->w.domain;
1121+ bool is_delete = false;
1122+ bool is_select = false;
1123+ unsigned int profile;
1124+ if (ccs_str_starts(&data, "delete "))
1125+ is_delete = true;
1126+ else if (ccs_str_starts(&data, "select "))
1127+ is_select = true;
1128+ if (is_select && ccs_select_one(head, data))
1129+ return -EAGAIN;
1130+ /* Don't allow updating policies by non manager programs. */
1131+ if (!ccs_manager())
1132+ return -EPERM;
1133+ if (ccs_domain_def(data)) {
1134+ domain = NULL;
1135+ if (is_delete)
1136+ ccs_delete_domain(data);
1137+ else if (is_select)
1138+ domain = ccs_find_domain(data);
1139+ else
1140+ domain = ccs_assign_domain(data, 0, 0, false);
1141+ head->w.domain = domain;
1142+ return 0;
1143+ }
1144+ if (!domain)
1145+ return -EINVAL;
1146+
1147+ if (sscanf(data, "use_profile %u\n", &profile) == 1
1148+ && profile < CCS_MAX_PROFILES) {
1149+ if (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile])
1150+ if (!is_delete)
1151+ domain->profile = (u8) profile;
1152+ return 0;
1153+ }
1154+ if (sscanf(data, "use_group %u\n", &profile) == 1
1155+ && profile < CCS_MAX_ACL_GROUPS) {
1156+ if (!is_delete)
1157+ domain->group = (u8) profile;
1158+ return 0;
1159+ }
1160+ for (profile = 0; profile < CCS_MAX_DOMAIN_INFO_FLAGS; profile++) {
1161+ const char *cp = ccs_dif[profile];
1162+ if (strncmp(data, cp, strlen(cp) - 1))
1163+ continue;
1164+ domain->flags[profile] = !is_delete;
1165+ return 0;
1166+ }
1167+ return ccs_write_domain2(data, domain, is_delete);
1168+}
1169+
1170+/**
1171+ * ccs_print_name_union - Print a ccs_name_union.
1172+ *
1173+ * @head: Pointer to "struct ccs_io_buffer".
1174+ * @ptr: Pointer to "struct ccs_name_union".
1175+ *
1176+ * Returns nothing.
1177+ */
1178+static void ccs_print_name_union(struct ccs_io_buffer *head,
1179+ const struct ccs_name_union *ptr)
1180+{
1181+ const bool cond = head->r.print_cond_part;
1182+ if (!cond)
1183+ ccs_set_space(head);
1184+ if (ptr->is_group) {
1185+ ccs_set_string(head, "@");
1186+ ccs_set_string(head, ptr->group->group_name->name);
1187+ } else {
1188+ if (cond)
1189+ ccs_set_string(head, "\"");
1190+ ccs_set_string(head, ptr->filename->name);
1191+ if (cond)
1192+ ccs_set_string(head, "\"");
1193+ }
1194+}
1195+
1196+/**
1197+ * ccs_print_number_union - Print a ccs_number_union.
1198+ *
1199+ * @head: Pointer to "struct ccs_io_buffer".
1200+ * @ptr: Pointer to "struct ccs_number_union".
1201+ *
1202+ * Returns nothing.
1203+ */
1204+static void ccs_print_number_union(struct ccs_io_buffer *head,
1205+ const struct ccs_number_union *ptr)
1206+{
1207+ if (!head->r.print_cond_part)
1208+ ccs_set_space(head);
1209+ if (ptr->is_group) {
1210+ ccs_set_string(head, "@");
1211+ ccs_set_string(head, ptr->group->group_name->name);
1212+ } else {
1213+ int i;
1214+ unsigned long min = ptr->values[0];
1215+ const unsigned long max = ptr->values[1];
1216+ u8 min_type = ptr->value_type[0];
1217+ const u8 max_type = ptr->value_type[1];
1218+ char buffer[128];
1219+ buffer[0] = '\0';
1220+ for (i = 0; i < 2; i++) {
1221+ switch (min_type) {
1222+ case CCS_VALUE_TYPE_HEXADECIMAL:
1223+ ccs_addprintf(buffer, sizeof(buffer), "0x%lX",
1224+ min);
1225+ break;
1226+ case CCS_VALUE_TYPE_OCTAL:
1227+ ccs_addprintf(buffer, sizeof(buffer), "0%lo",
1228+ min);
1229+ break;
1230+ default:
1231+ ccs_addprintf(buffer, sizeof(buffer), "%lu",
1232+ min);
1233+ break;
1234+ }
1235+ if (min == max && min_type == max_type)
1236+ break;
1237+ ccs_addprintf(buffer, sizeof(buffer), "-");
1238+ min_type = max_type;
1239+ min = max;
1240+ }
1241+ ccs_io_printf(head, "%s", buffer);
1242+ }
1243+}
1244+
1245+/**
1246+ * ccs_print_condition - Print condition part.
1247+ *
1248+ * @head: Pointer to "struct ccs_io_buffer".
1249+ * @cond: Pointer to "struct ccs_condition".
1250+ *
1251+ * Returns true on success, false otherwise.
1252+ */
1253+static bool ccs_print_condition(struct ccs_io_buffer *head,
1254+ const struct ccs_condition *cond)
1255+{
1256+ switch (head->r.cond_step) {
1257+ case 0:
1258+ head->r.cond_index = 0;
1259+ head->r.cond_step++;
1260+ /* fall through */
1261+ case 1:
1262+ {
1263+ const u16 condc = cond->condc;
1264+ const struct ccs_condition_element *condp =
1265+ (typeof(condp)) (cond + 1);
1266+ const struct ccs_number_union *numbers_p =
1267+ (typeof(numbers_p)) (condp + condc);
1268+ const struct ccs_name_union *names_p =
1269+ (typeof(names_p))
1270+ (numbers_p + cond->numbers_count);
1271+ const struct ccs_argv *argv =
1272+ (typeof(argv)) (names_p + cond->names_count);
1273+ const struct ccs_envp *envp =
1274+ (typeof(envp)) (argv + cond->argc);
1275+ u16 skip;
1276+ for (skip = 0; skip < head->r.cond_index; skip++) {
1277+ const u8 left = condp->left;
1278+ const u8 right = condp->right;
1279+ condp++;
1280+ switch (left) {
1281+ case CCS_ARGV_ENTRY:
1282+ argv++;
1283+ continue;
1284+ case CCS_ENVP_ENTRY:
1285+ envp++;
1286+ continue;
1287+ case CCS_NUMBER_UNION:
1288+ numbers_p++;
1289+ break;
1290+ }
1291+ switch (right) {
1292+ case CCS_NAME_UNION:
1293+ names_p++;
1294+ break;
1295+ case CCS_NUMBER_UNION:
1296+ numbers_p++;
1297+ break;
1298+ }
1299+ }
1300+ while (head->r.cond_index < condc) {
1301+ const u8 match = condp->equals;
1302+ const u8 left = condp->left;
1303+ const u8 right = condp->right;
1304+ if (!ccs_flush(head))
1305+ return false;
1306+ condp++;
1307+ head->r.cond_index++;
1308+ ccs_set_space(head);
1309+ switch (left) {
1310+ case CCS_ARGV_ENTRY:
1311+ ccs_io_printf(head,
1312+ "exec.argv[%u]%s\"%s\"",
1313+ argv->index,
1314+ argv->is_not ?
1315+ "!=" : "=",
1316+ argv->value->name);
1317+ argv++;
1318+ continue;
1319+ case CCS_ENVP_ENTRY:
1320+ ccs_io_printf(head,
1321+ "exec.envp[\"%s\"]%s",
1322+ envp->name->name,
1323+ envp->is_not ?
1324+ "!=" : "=");
1325+ if (envp->value) {
1326+ ccs_set_string(head, "\"");
1327+ ccs_set_string(head, envp->
1328+ value->name);
1329+ ccs_set_string(head, "\"");
1330+ } else {
1331+ ccs_set_string(head, "NULL");
1332+ }
1333+ envp++;
1334+ continue;
1335+ case CCS_NUMBER_UNION:
1336+ ccs_print_number_union(head,
1337+ numbers_p++);
1338+ break;
1339+ default:
1340+ ccs_set_string(head,
1341+ ccs_condition_keyword[left]);
1342+ break;
1343+ }
1344+ ccs_set_string(head, match ? "=" : "!=");
1345+ switch (right) {
1346+ case CCS_NAME_UNION:
1347+ ccs_print_name_union(head, names_p++);
1348+ break;
1349+ case CCS_NUMBER_UNION:
1350+ ccs_print_number_union(head,
1351+ numbers_p++);
1352+ break;
1353+ default:
1354+ ccs_set_string(head,
1355+ ccs_condition_keyword[right]);
1356+ break;
1357+ }
1358+ }
1359+ }
1360+ head->r.cond_step++;
1361+ /* fall through */
1362+ case 2:
1363+ if (!ccs_flush(head))
1364+ break;
1365+ head->r.cond_step++;
1366+ /* fall through */
1367+ case 3:
1368+ if (cond->grant_log != CCS_GRANTLOG_AUTO)
1369+ ccs_io_printf(head, " grant_log=%s",
1370+ ccs_yesno(cond->grant_log ==
1371+ CCS_GRANTLOG_YES));
1372+ if (cond->transit) {
1373+ ccs_set_string(head, " auto_domain_transition=\"");
1374+ ccs_set_string(head, cond->transit->name);
1375+ ccs_set_string(head, "\"");
1376+ }
1377+ ccs_set_lf(head);
1378+ return true;
1379+ }
1380+ return false;
1381+}
1382+
1383+/**
1384+ * ccs_set_group - Print "acl_group " header keyword and category name.
1385+ *
1386+ * @head: Pointer to "struct ccs_io_buffer".
1387+ * @category: Category name.
1388+ *
1389+ * Returns nothing.
1390+ */
1391+static void ccs_set_group(struct ccs_io_buffer *head, const char *category)
1392+{
1393+ if (head->type == CCS_EXCEPTIONPOLICY)
1394+ ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index);
1395+ ccs_set_string(head, category);
1396+}
1397+
1398+/**
1399+ * ccs_print_entry - Print an ACL entry.
1400+ *
1401+ * @head: Pointer to "struct ccs_io_buffer".
1402+ * @acl: Pointer to an ACL entry.
1403+ *
1404+ * Returns true on success, false otherwise.
1405+ */
1406+static bool ccs_print_entry(struct ccs_io_buffer *head,
1407+ const struct ccs_acl_info *acl)
1408+{
1409+ const u8 acl_type = acl->type;
1410+ const bool may_trigger_transition = acl->cond && acl->cond->transit;
1411+ bool first = true;
1412+ u8 bit;
1413+ if (head->r.print_cond_part)
1414+ goto print_cond_part;
1415+ if (acl->is_deleted)
1416+ return true;
1417+ if (!ccs_flush(head))
1418+ return false;
1419+ else if (acl_type == CCS_TYPE_PATH_ACL) {
1420+ struct ccs_path_acl *ptr
1421+ = container_of(acl, typeof(*ptr), head);
1422+ const u16 perm = ptr->perm;
1423+ for (bit = 0; bit < CCS_MAX_PATH_OPERATION; bit++) {
1424+ if (!(perm & (1 << bit)))
1425+ continue;
1426+ if (head->r.print_transition_related_only &&
1427+ bit != CCS_TYPE_EXECUTE && !may_trigger_transition)
1428+ continue;
1429+ if (first) {
1430+ ccs_set_group(head, "file ");
1431+ first = false;
1432+ } else {
1433+ ccs_set_slash(head);
1434+ }
1435+ ccs_set_string(head, ccs_path_keyword[bit]);
1436+ }
1437+ if (first)
1438+ return true;
1439+ ccs_print_name_union(head, &ptr->name);
1440+ } else if (acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
1441+ acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {
1442+ struct ccs_handler_acl *ptr
1443+ = container_of(acl, typeof(*ptr), head);
1444+ ccs_set_group(head, "task ");
1445+ ccs_set_string(head, acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER
1446+ ? "auto_execute_handler " :
1447+ "denied_execute_handler ");
1448+ ccs_set_string(head, ptr->handler->name);
1449+ } else if (acl_type == CCS_TYPE_AUTO_TASK_ACL ||
1450+ acl_type == CCS_TYPE_MANUAL_TASK_ACL) {
1451+ struct ccs_task_acl *ptr =
1452+ container_of(acl, typeof(*ptr), head);
1453+ ccs_set_group(head, "task ");
1454+ ccs_set_string(head, acl_type == CCS_TYPE_AUTO_TASK_ACL ?
1455+ "auto_domain_transition " :
1456+ "manual_domain_transition ");
1457+ ccs_set_string(head, ptr->domainname->name);
1458+ } else if (head->r.print_transition_related_only &&
1459+ !may_trigger_transition) {
1460+ return true;
1461+ } else if (acl_type == CCS_TYPE_MKDEV_ACL) {
1462+ struct ccs_mkdev_acl *ptr =
1463+ container_of(acl, typeof(*ptr), head);
1464+ const u8 perm = ptr->perm;
1465+ for (bit = 0; bit < CCS_MAX_MKDEV_OPERATION; bit++) {
1466+ if (!(perm & (1 << bit)))
1467+ continue;
1468+ if (first) {
1469+ ccs_set_group(head, "file ");
1470+ first = false;
1471+ } else {
1472+ ccs_set_slash(head);
1473+ }
1474+ ccs_set_string(head, ccs_mac_keywords
1475+ [ccs_pnnn2mac[bit]]);
1476+ }
1477+ if (first)
1478+ return true;
1479+ ccs_print_name_union(head, &ptr->name);
1480+ ccs_print_number_union(head, &ptr->mode);
1481+ ccs_print_number_union(head, &ptr->major);
1482+ ccs_print_number_union(head, &ptr->minor);
1483+ } else if (acl_type == CCS_TYPE_PATH2_ACL) {
1484+ struct ccs_path2_acl *ptr =
1485+ container_of(acl, typeof(*ptr), head);
1486+ const u8 perm = ptr->perm;
1487+ for (bit = 0; bit < CCS_MAX_PATH2_OPERATION; bit++) {
1488+ if (!(perm & (1 << bit)))
1489+ continue;
1490+ if (first) {
1491+ ccs_set_group(head, "file ");
1492+ first = false;
1493+ } else {
1494+ ccs_set_slash(head);
1495+ }
1496+ ccs_set_string(head, ccs_mac_keywords
1497+ [ccs_pp2mac[bit]]);
1498+ }
1499+ if (first)
1500+ return true;
1501+ ccs_print_name_union(head, &ptr->name1);
1502+ ccs_print_name_union(head, &ptr->name2);
1503+ } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {
1504+ struct ccs_path_number_acl *ptr =
1505+ container_of(acl, typeof(*ptr), head);
1506+ const u8 perm = ptr->perm;
1507+ for (bit = 0; bit < CCS_MAX_PATH_NUMBER_OPERATION; bit++) {
1508+ if (!(perm & (1 << bit)))
1509+ continue;
1510+ if (first) {
1511+ ccs_set_group(head, "file ");
1512+ first = false;
1513+ } else {
1514+ ccs_set_slash(head);
1515+ }
1516+ ccs_set_string(head, ccs_mac_keywords
1517+ [ccs_pn2mac[bit]]);
1518+ }
1519+ if (first)
1520+ return true;
1521+ ccs_print_name_union(head, &ptr->name);
1522+ ccs_print_number_union(head, &ptr->number);
1523+ } else if (acl_type == CCS_TYPE_ENV_ACL) {
1524+ struct ccs_env_acl *ptr =
1525+ container_of(acl, typeof(*ptr), head);
1526+ ccs_set_group(head, "misc env ");
1527+ ccs_set_string(head, ptr->env->name);
1528+ } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {
1529+ struct ccs_capability_acl *ptr =
1530+ container_of(acl, typeof(*ptr), head);
1531+ ccs_set_group(head, "capability ");
1532+ ccs_set_string(head, ccs_mac_keywords
1533+ [ccs_c2mac[ptr->operation]]);
1534+ } else if (acl_type == CCS_TYPE_INET_ACL) {
1535+ struct ccs_inet_acl *ptr =
1536+ container_of(acl, typeof(*ptr), head);
1537+ const u8 perm = ptr->perm;
1538+ for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
1539+ if (!(perm & (1 << bit)))
1540+ continue;
1541+ if (first) {
1542+ ccs_set_group(head, "network inet ");
1543+ ccs_set_string(head, ccs_proto_keyword
1544+ [ptr->protocol]);
1545+ ccs_set_space(head);
1546+ first = false;
1547+ } else {
1548+ ccs_set_slash(head);
1549+ }
1550+ ccs_set_string(head, ccs_socket_keyword[bit]);
1551+ }
1552+ if (first)
1553+ return true;
1554+ ccs_set_space(head);
1555+ switch (ptr->address_type) {
1556+ char buf[128];
1557+ case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
1558+ ccs_set_string(head, "@");
1559+ ccs_set_string(head,
1560+ ptr->address.group->group_name->name);
1561+ break;
1562+ case CCS_IP_ADDRESS_TYPE_IPv4:
1563+ ccs_print_ipv4(buf, sizeof(buf), ptr->address.ipv4.min,
1564+ ptr->address.ipv4.max);
1565+ ccs_io_printf(head, "%s", buf);
1566+ break;
1567+ case CCS_IP_ADDRESS_TYPE_IPv6:
1568+ ccs_print_ipv6(buf, sizeof(buf), ptr->address.ipv6.min,
1569+ ptr->address.ipv6.max);
1570+ ccs_io_printf(head, "%s", buf);
1571+ break;
1572+ }
1573+ ccs_print_number_union(head, &ptr->port);
1574+ } else if (acl_type == CCS_TYPE_UNIX_ACL) {
1575+ struct ccs_unix_acl *ptr =
1576+ container_of(acl, typeof(*ptr), head);
1577+ const u8 perm = ptr->perm;
1578+ for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
1579+ if (!(perm & (1 << bit)))
1580+ continue;
1581+ if (first) {
1582+ ccs_set_group(head, "network unix ");
1583+ ccs_set_string(head, ccs_proto_keyword
1584+ [ptr->protocol]);
1585+ ccs_set_space(head);
1586+ first = false;
1587+ } else {
1588+ ccs_set_slash(head);
1589+ }
1590+ ccs_set_string(head, ccs_socket_keyword[bit]);
1591+ }
1592+ if (first)
1593+ return true;
1594+ ccs_print_name_union(head, &ptr->name);
1595+ } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {
1596+ struct ccs_signal_acl *ptr =
1597+ container_of(acl, typeof(*ptr), head);
1598+ ccs_set_group(head, "ipc signal ");
1599+ ccs_io_printf(head, "%u ", ptr->sig);
1600+ ccs_set_string(head, ptr->domainname->name);
1601+ } else if (acl_type == CCS_TYPE_MOUNT_ACL) {
1602+ struct ccs_mount_acl *ptr =
1603+ container_of(acl, typeof(*ptr), head);
1604+ ccs_set_group(head, "file mount");
1605+ ccs_print_name_union(head, &ptr->dev_name);
1606+ ccs_print_name_union(head, &ptr->dir_name);
1607+ ccs_print_name_union(head, &ptr->fs_type);
1608+ ccs_print_number_union(head, &ptr->flags);
1609+ }
1610+ if (acl->cond) {
1611+ head->r.print_cond_part = true;
1612+ head->r.cond_step = 0;
1613+ if (!ccs_flush(head))
1614+ return false;
1615+print_cond_part:
1616+ if (!ccs_print_condition(head, acl->cond))
1617+ return false;
1618+ head->r.print_cond_part = false;
1619+ } else {
1620+ ccs_set_lf(head);
1621+ }
1622+ return true;
1623+}
1624+
1625+/**
1626+ * ccs_read_domain2 - Read domain policy.
1627+ *
1628+ * @head: Pointer to "struct ccs_io_buffer".
1629+ * @domain: Pointer to "struct ccs_domain_info".
1630+ * @index: Index number.
1631+ *
1632+ * Returns true on success, false otherwise.
1633+ *
1634+ * Caller holds ccs_read_lock().
1635+ */
1636+static bool ccs_read_domain2(struct ccs_io_buffer *head,
1637+ struct ccs_domain_info *domain,
1638+ const u8 index)
1639+{
1640+ list_for_each_cookie(head->r.acl, &domain->acl_info_list[index]) {
1641+ struct ccs_acl_info *ptr =
1642+ list_entry(head->r.acl, typeof(*ptr), list);
1643+ if (!ccs_print_entry(head, ptr))
1644+ return false;
1645+ }
1646+ head->r.acl = NULL;
1647+ return true;
1648+}
1649+
1650+/**
1651+ * ccs_read_domain - Read domain policy.
1652+ *
1653+ * @head: Pointer to "struct ccs_io_buffer".
1654+ *
1655+ * Returns nothing.
1656+ *
1657+ * Caller holds ccs_read_lock().
1658+ */
1659+static void ccs_read_domain(struct ccs_io_buffer *head)
1660+{
1661+ if (head->r.eof)
1662+ return;
1663+ list_for_each_cookie(head->r.domain, &ccs_domain_list) {
1664+ struct ccs_domain_info *domain =
1665+ list_entry(head->r.domain, typeof(*domain), list);
1666+ switch (head->r.step) {
1667+ u8 i;
1668+ case 0:
1669+ if (domain->is_deleted &&
1670+ !head->r.print_this_domain_only)
1671+ continue;
1672+ /* Print domainname and flags. */
1673+ ccs_set_string(head, domain->domainname->name);
1674+ ccs_set_lf(head);
1675+ ccs_io_printf(head, "use_profile %u\n",
1676+ domain->profile);
1677+ ccs_io_printf(head, "use_group %u\n", domain->group);
1678+ for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)
1679+ if (domain->flags[i])
1680+ ccs_set_string(head, ccs_dif[i]);
1681+ head->r.step++;
1682+ ccs_set_lf(head);
1683+ /* fall through */
1684+ case 1:
1685+ if (!ccs_read_domain2(head, domain, 0))
1686+ return;
1687+ head->r.step++;
1688+ /* fall through */
1689+ case 2:
1690+ if (!ccs_read_domain2(head, domain, 1))
1691+ return;
1692+ head->r.step++;
1693+ if (!ccs_set_lf(head))
1694+ return;
1695+ /* fall through */
1696+ case 3:
1697+ head->r.step = 0;
1698+ if (head->r.print_this_domain_only)
1699+ goto done;
1700+ }
1701+ }
1702+done:
1703+ head->r.eof = true;
1704+}
1705+
1706+/**
1707+ * ccs_write_domain_profile - Assign profile for specified domain.
1708+ *
1709+ * @head: Pointer to "struct ccs_io_buffer".
1710+ *
1711+ * Returns 0 on success, -EINVAL otherwise.
1712+ *
1713+ * This is equivalent to doing
1714+ *
1715+ * ( echo "select " $domainname; echo "use_profile " $profile ) |
1716+ * /usr/sbin/ccs-loadpolicy -d
1717+ *
1718+ * Caller holds ccs_read_lock().
1719+ */
1720+static int ccs_write_domain_profile(struct ccs_io_buffer *head)
1721+{
1722+ char *data = head->write_buf;
1723+ char *cp = strchr(data, ' ');
1724+ struct ccs_domain_info *domain;
1725+ unsigned int profile;
1726+ if (!cp)
1727+ return -EINVAL;
1728+ *cp = '\0';
1729+ profile = simple_strtoul(data, NULL, 10);
1730+ if (profile >= CCS_MAX_PROFILES)
1731+ return -EINVAL;
1732+ domain = ccs_find_domain(cp + 1);
1733+ if (domain && (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile]))
1734+ domain->profile = (u8) profile;
1735+ return 0;
1736+}
1737+
1738+/**
1739+ * ccs_read_domain_profile - Read only domainname and profile.
1740+ *
1741+ * @head: Pointer to "struct ccs_io_buffer".
1742+ *
1743+ * Returns nothing.
1744+ *
1745+ * This is equivalent to doing
1746+ *
1747+ * grep -A 1 '^<kernel>' /proc/ccs/domain_policy |
1748+ * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
1749+ * domainname = $0; } else if ( $1 == "use_profile" ) {
1750+ * print $2 " " domainname; domainname = ""; } } ; '
1751+ *
1752+ * Caller holds ccs_read_lock().
1753+ */
1754+static void ccs_read_domain_profile(struct ccs_io_buffer *head)
1755+{
1756+ if (head->r.eof)
1757+ return;
1758+ list_for_each_cookie(head->r.domain, &ccs_domain_list) {
1759+ struct ccs_domain_info *domain =
1760+ list_entry(head->r.domain, typeof(*domain), list);
1761+ if (domain->is_deleted)
1762+ continue;
1763+ if (!ccs_flush(head))
1764+ return;
1765+ ccs_io_printf(head, "%u ", domain->profile);
1766+ ccs_set_string(head, domain->domainname->name);
1767+ ccs_set_lf(head);
1768+ }
1769+ head->r.eof = true;
1770+}
1771+
1772+/**
1773+ * ccs_write_pid - Specify PID to obtain domainname.
1774+ *
1775+ * @head: Pointer to "struct ccs_io_buffer".
1776+ *
1777+ * Returns 0.
1778+ */
1779+static int ccs_write_pid(struct ccs_io_buffer *head)
1780+{
1781+ head->r.eof = false;
1782+ return 0;
1783+}
1784+
1785+/**
1786+ * ccs_read_pid - Read information of a process.
1787+ *
1788+ * @head: Pointer to "struct ccs_io_buffer".
1789+ *
1790+ * Returns the domainname which the specified PID is in or
1791+ * process information of the specified PID on success,
1792+ * empty string otherwise.
1793+ *
1794+ * Caller holds ccs_read_lock().
1795+ */
1796+static void ccs_read_pid(struct ccs_io_buffer *head)
1797+{
1798+ char *buf = head->write_buf;
1799+ bool task_info = false;
1800+ bool global_pid = false;
1801+ unsigned int pid;
1802+ struct task_struct *p;
1803+ struct ccs_domain_info *domain = NULL;
1804+ u32 ccs_flags = 0;
1805+ /* Accessing write_buf is safe because head->io_sem is held. */
1806+ if (!buf) {
1807+ head->r.eof = true;
1808+ return; /* Do nothing if open(O_RDONLY). */
1809+ }
1810+ if (head->r.w_pos || head->r.eof)
1811+ return;
1812+ head->r.eof = true;
1813+ if (ccs_str_starts(&buf, "info "))
1814+ task_info = true;
1815+ if (ccs_str_starts(&buf, "global-pid "))
1816+ global_pid = true;
1817+ pid = (unsigned int) simple_strtoul(buf, NULL, 10);
1818+ ccs_tasklist_lock();
1819+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1820+ if (global_pid)
1821+ p = ccsecurity_exports.find_task_by_pid_ns(pid, &init_pid_ns);
1822+ else
1823+ p = ccsecurity_exports.find_task_by_vpid(pid);
1824+#else
1825+ p = find_task_by_pid(pid);
1826+#endif
1827+ if (p) {
1828+ domain = ccs_task_domain(p);
1829+ ccs_flags = ccs_task_flags(p);
1830+ }
1831+ ccs_tasklist_unlock();
1832+ if (!domain)
1833+ return;
1834+ if (!task_info) {
1835+ ccs_io_printf(head, "%u %u ", pid, domain->profile);
1836+ ccs_set_string(head, domain->domainname->name);
1837+ } else {
1838+ ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
1839+ ccs_yesno(ccs_flags &
1840+ CCS_TASK_IS_MANAGER),
1841+ ccs_yesno(ccs_flags &
1842+ CCS_TASK_IS_EXECUTE_HANDLER));
1843+ }
1844+}
1845+
1846+/* String table for domain transition control keywords. */
1847+static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
1848+ [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
1849+ [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
1850+ [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
1851+ [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
1852+};
1853+
1854+/* String table for grouping keywords. */
1855+static const char * const ccs_group_name[CCS_MAX_GROUP] = {
1856+ [CCS_PATH_GROUP] = "path_group ",
1857+ [CCS_NUMBER_GROUP] = "number_group ",
1858+ [CCS_ADDRESS_GROUP] = "address_group ",
1859+};
1860+
1861+/**
1862+ * ccs_write_exception - Write exception policy.
1863+ *
1864+ * @head: Pointer to "struct ccs_io_buffer".
1865+ *
1866+ * Returns 0 on success, negative value otherwise.
1867+ */
1868+static int ccs_write_exception(struct ccs_io_buffer *head)
1869+{
1870+ char *data = head->write_buf;
1871+ const bool is_delete = ccs_str_starts(&data, "delete ");
1872+ u8 i;
1873+ static const struct {
1874+ const char *keyword;
1875+ int (*write) (char *, const bool);
1876+ } ccs_callback[2] = {
1877+ { "aggregator ", ccs_write_aggregator },
1878+ { "deny_autobind ", ccs_write_reserved_port },
1879+ };
1880+ if (!is_delete && ccs_str_starts(&data, "select ") &&
1881+ !strcmp(data, "transition_only")) {
1882+ head->r.print_transition_related_only = true;
1883+ return -EAGAIN;
1884+ }
1885+ /* Don't allow updating policies by non manager programs. */
1886+ if (!ccs_manager())
1887+ return -EPERM;
1888+ for (i = 0; i < 2; i++)
1889+ if (ccs_str_starts(&data, ccs_callback[i].keyword))
1890+ return ccs_callback[i].write(data, is_delete);
1891+ for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)
1892+ if (ccs_str_starts(&data, ccs_transition_type[i]))
1893+ return ccs_write_transition_control(data, is_delete,
1894+ i);
1895+ for (i = 0; i < CCS_MAX_GROUP; i++)
1896+ if (ccs_str_starts(&data, ccs_group_name[i]))
1897+ return ccs_write_group(data, is_delete, i);
1898+ if (ccs_str_starts(&data, "acl_group ")) {
1899+ unsigned int group;
1900+ if (sscanf(data, "%u", &group) == 1 &&
1901+ group < CCS_MAX_ACL_GROUPS) {
1902+ data = strchr(data, ' ');
1903+ if (data)
1904+ return ccs_write_domain2(data + 1,
1905+ &ccs_acl_group[group],
1906+ is_delete);
1907+ }
1908+ }
1909+ return -EINVAL;
1910+}
1911+
1912+/**
1913+ * ccs_read_group - Read "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
1914+ *
1915+ * @head: Pointer to "struct ccs_io_buffer".
1916+ * @idx: Index number.
1917+ *
1918+ * Returns true on success, false otherwise.
1919+ *
1920+ * Caller holds ccs_read_lock().
1921+ */
1922+static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)
1923+{
1924+ list_for_each_cookie(head->r.group, &ccs_group_list[idx]) {
1925+ struct ccs_group *group =
1926+ list_entry(head->r.group, typeof(*group), head.list);
1927+ list_for_each_cookie(head->r.acl, &group->member_list) {
1928+ struct ccs_acl_head *ptr =
1929+ list_entry(head->r.acl, typeof(*ptr), list);
1930+ if (ptr->is_deleted)
1931+ continue;
1932+ if (!ccs_flush(head))
1933+ return false;
1934+ ccs_set_string(head, ccs_group_name[idx]);
1935+ ccs_set_string(head, group->group_name->name);
1936+ if (idx == CCS_PATH_GROUP) {
1937+ ccs_set_space(head);
1938+ ccs_set_string(head, container_of
1939+ (ptr, struct ccs_path_group,
1940+ head)->member_name->name);
1941+ } else if (idx == CCS_NUMBER_GROUP) {
1942+ ccs_print_number_union(head, &container_of
1943+ (ptr, struct ccs_number_group,
1944+ head)->number);
1945+ } else if (idx == CCS_ADDRESS_GROUP) {
1946+ char buffer[128];
1947+ struct ccs_address_group *member =
1948+ container_of(ptr, typeof(*member),
1949+ head);
1950+ if (member->is_ipv6)
1951+ ccs_print_ipv6(buffer, sizeof(buffer),
1952+ member->min.ipv6,
1953+ member->max.ipv6);
1954+ else
1955+ ccs_print_ipv4(buffer, sizeof(buffer),
1956+ member->min.ipv4,
1957+ member->max.ipv4);
1958+ ccs_io_printf(head, " %s", buffer);
1959+ }
1960+ ccs_set_lf(head);
1961+ }
1962+ head->r.acl = NULL;
1963+ }
1964+ head->r.group = NULL;
1965+ return true;
1966+}
1967+
1968+/**
1969+ * ccs_read_policy - Read "struct ccs_..._entry" list.
1970+ *
1971+ * @head: Pointer to "struct ccs_io_buffer".
1972+ * @idx: Index number.
1973+ *
1974+ * Returns true on success, false otherwise.
1975+ *
1976+ * Caller holds ccs_read_lock().
1977+ */
1978+static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)
1979+{
1980+ list_for_each_cookie(head->r.acl, &ccs_policy_list[idx]) {
1981+ struct ccs_acl_head *acl =
1982+ container_of(head->r.acl, typeof(*acl), list);
1983+ if (acl->is_deleted)
1984+ continue;
1985+ if (head->r.print_transition_related_only &&
1986+ idx != CCS_ID_TRANSITION_CONTROL)
1987+ continue;
1988+ if (!ccs_flush(head))
1989+ return false;
1990+ switch (idx) {
1991+ case CCS_ID_TRANSITION_CONTROL:
1992+ {
1993+ struct ccs_transition_control *ptr =
1994+ container_of(acl, typeof(*ptr), head);
1995+ ccs_set_string(head,
1996+ ccs_transition_type[ptr->type]);
1997+ ccs_set_string(head, ptr->program ?
1998+ ptr->program->name : "any");
1999+ ccs_set_string(head, " from ");
2000+ ccs_set_string(head, ptr->domainname ?
2001+ ptr->domainname->name : "any");
2002+ }
2003+ break;
2004+ case CCS_ID_AGGREGATOR:
2005+ {
2006+ struct ccs_aggregator *ptr =
2007+ container_of(acl, typeof(*ptr), head);
2008+ ccs_set_string(head, "aggregator ");
2009+ ccs_set_string(head, ptr->original_name->name);
2010+ ccs_set_space(head);
2011+ ccs_set_string(head,
2012+ ptr->aggregated_name->name);
2013+ }
2014+ break;
2015+ case CCS_ID_RESERVEDPORT:
2016+ {
2017+ struct ccs_reserved *ptr =
2018+ container_of(acl, typeof(*ptr), head);
2019+ const u16 min_port = ptr->min_port;
2020+ const u16 max_port = ptr->max_port;
2021+ ccs_set_string(head, "deny_autobind ");
2022+ ccs_io_printf(head, "%u", min_port);
2023+ if (min_port != max_port)
2024+ ccs_io_printf(head, "-%u", max_port);
2025+ }
2026+ break;
2027+ default:
2028+ continue;
2029+ }
2030+ ccs_set_lf(head);
2031+ }
2032+ head->r.acl = NULL;
2033+ return true;
2034+}
2035+
2036+/**
2037+ * ccs_read_exception - Read exception policy.
2038+ *
2039+ * @head: Pointer to "struct ccs_io_buffer".
2040+ *
2041+ * Returns nothing.
2042+ *
2043+ * Caller holds ccs_read_lock().
2044+ */
2045+static void ccs_read_exception(struct ccs_io_buffer *head)
2046+{
2047+ if (head->r.eof)
2048+ return;
2049+ while (head->r.step < CCS_MAX_POLICY &&
2050+ ccs_read_policy(head, head->r.step))
2051+ head->r.step++;
2052+ if (head->r.step < CCS_MAX_POLICY)
2053+ return;
2054+ while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP &&
2055+ ccs_read_group(head, head->r.step - CCS_MAX_POLICY))
2056+ head->r.step++;
2057+ if (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP)
2058+ return;
2059+ while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP
2060+ + CCS_MAX_ACL_GROUPS * 2) {
2061+ head->r.acl_group_index = (head->r.step - CCS_MAX_POLICY
2062+ - CCS_MAX_GROUP) / 2;
2063+ if (!ccs_read_domain2(head,
2064+ &ccs_acl_group[head->r.acl_group_index],
2065+ head->r.step & 1))
2066+ return;
2067+ head->r.step++;
2068+ }
2069+ head->r.eof = true;
2070+}
2071+
2072+/* Wait queue for kernel -> userspace notification. */
2073+static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
2074+/* Wait queue for userspace -> kernel notification. */
2075+static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
2076+
2077+/* Structure for query. */
2078+struct ccs_query {
2079+ struct list_head list;
2080+ char *query;
2081+ size_t query_len;
2082+ unsigned int serial;
2083+ u8 timer;
2084+ u8 answer;
2085+ u8 retry;
2086+};
2087+
2088+/* The list for "struct ccs_query". */
2089+static LIST_HEAD(ccs_query_list);
2090+
2091+/* Lock for manipulating ccs_query_list. */
2092+static DEFINE_SPINLOCK(ccs_query_list_lock);
2093+
2094+/* Number of "struct file" referring /proc/ccs/query interface. */
2095+static atomic_t ccs_query_observers = ATOMIC_INIT(0);
2096+
2097+/**
2098+ * ccs_truncate - Truncate a line.
2099+ *
2100+ * @str: String to truncate.
2101+ *
2102+ * Returns length of truncated @str.
2103+ */
2104+static int ccs_truncate(char *str)
2105+{
2106+ char *start = str;
2107+ while (*(unsigned char *) str > (unsigned char) ' ')
2108+ str++;
2109+ *str = '\0';
2110+ return strlen(start) + 1;
2111+}
2112+
2113+/**
2114+ * ccs_add_entry - Add an ACL to current thread's domain. Used by learning mode.
2115+ *
2116+ * @header: Lines containing ACL.
2117+ *
2118+ * Returns nothing.
2119+ */
2120+static void ccs_add_entry(char *header)
2121+{
2122+ char *buffer;
2123+ char *realpath = NULL;
2124+ char *argv0 = NULL;
2125+ char *symlink = NULL;
2126+ char *handler;
2127+ char *cp = strchr(header, '\n');
2128+ int len;
2129+ if (!cp)
2130+ return;
2131+ cp = strchr(cp + 1, '\n');
2132+ if (!cp)
2133+ return;
2134+ *cp++ = '\0';
2135+ len = strlen(cp) + 1;
2136+ /* strstr() will return NULL if ordering is wrong. */
2137+ if (*cp == 'f') {
2138+ argv0 = strstr(header, " argv[]={ \"");
2139+ if (argv0) {
2140+ argv0 += 10;
2141+ len += ccs_truncate(argv0) + 14;
2142+ }
2143+ realpath = strstr(header, " exec={ realpath=\"");
2144+ if (realpath) {
2145+ realpath += 8;
2146+ len += ccs_truncate(realpath) + 6;
2147+ }
2148+ symlink = strstr(header, " symlink.target=\"");
2149+ if (symlink)
2150+ len += ccs_truncate(symlink + 1) + 1;
2151+ }
2152+ handler = strstr(header, "type=execute_handler");
2153+ if (handler)
2154+ len += ccs_truncate(handler) + 6;
2155+ buffer = kmalloc(len, CCS_GFP_FLAGS);
2156+ if (!buffer)
2157+ return;
2158+ snprintf(buffer, len - 1, "%s", cp);
2159+ if (handler)
2160+ ccs_addprintf(buffer, len, " task.%s", handler);
2161+ if (realpath)
2162+ ccs_addprintf(buffer, len, " exec.%s", realpath);
2163+ if (argv0)
2164+ ccs_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
2165+ if (symlink)
2166+ ccs_addprintf(buffer, len, "%s", symlink);
2167+ ccs_normalize_line(buffer);
2168+ if (!ccs_write_domain2(buffer, ccs_current_domain(), false))
2169+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
2170+ kfree(buffer);
2171+}
2172+
2173+/**
2174+ * ccs_supervisor - Ask for the supervisor's decision.
2175+ *
2176+ * @r: Pointer to "struct ccs_request_info".
2177+ * @fmt: The printf()'s format string, followed by parameters.
2178+ *
2179+ * Returns 0 if the supervisor decided to permit the access request which
2180+ * violated the policy in enforcing mode, CCS_RETRY_REQUEST if the supervisor
2181+ * decided to retry the access request which violated the policy in enforcing
2182+ * mode, 0 if it is not in enforcing mode, -EPERM otherwise.
2183+ */
2184+int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
2185+{
2186+ va_list args;
2187+ int error;
2188+ int len;
2189+ static unsigned int ccs_serial;
2190+ struct ccs_query entry = { };
2191+ bool quota_exceeded = false;
2192+ va_start(args, fmt);
2193+ len = vsnprintf((char *) &len, 1, fmt, args) + 1;
2194+ va_end(args);
2195+ /* Write /proc/ccs/audit. */
2196+ va_start(args, fmt);
2197+ ccs_write_log2(r, len, fmt, args);
2198+ va_end(args);
2199+ /* Nothing more to do if granted. */
2200+ if (r->granted)
2201+ return 0;
2202+ if (r->mode)
2203+ ccs_update_stat(r->mode);
2204+ switch (r->mode) {
2205+ int i;
2206+ struct ccs_profile *p;
2207+ case CCS_CONFIG_ENFORCING:
2208+ error = -EPERM;
2209+ if (atomic_read(&ccs_query_observers))
2210+ break;
2211+ if (r->dont_sleep_on_enforce_error)
2212+ goto out;
2213+ p = ccs_profile(r->profile);
2214+ /* Check enforcing_penalty parameter. */
2215+ for (i = 0; i < p->pref[CCS_PREF_ENFORCING_PENALTY]; i++) {
2216+ set_current_state(TASK_INTERRUPTIBLE);
2217+ schedule_timeout(HZ / 10);
2218+ }
2219+ goto out;
2220+ case CCS_CONFIG_LEARNING:
2221+ error = 0;
2222+ /* Check mac_learning_entry parameter. */
2223+ if (ccs_domain_quota_ok(r))
2224+ break;
2225+ /* fall through */
2226+ default:
2227+ return 0;
2228+ }
2229+ /* Get message. */
2230+ va_start(args, fmt);
2231+ entry.query = ccs_init_log(r, len, fmt, args);
2232+ va_end(args);
2233+ if (!entry.query)
2234+ goto out;
2235+ entry.query_len = strlen(entry.query) + 1;
2236+ if (!error) {
2237+ ccs_add_entry(entry.query);
2238+ goto out;
2239+ }
2240+ len = ccs_round2(entry.query_len);
2241+ spin_lock(&ccs_query_list_lock);
2242+ if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
2243+ ccs_memory_used[CCS_MEMORY_QUERY] + len
2244+ >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
2245+ quota_exceeded = true;
2246+ } else {
2247+ entry.serial = ccs_serial++;
2248+ entry.retry = r->retry;
2249+ ccs_memory_used[CCS_MEMORY_QUERY] += len;
2250+ list_add_tail(&entry.list, &ccs_query_list);
2251+ }
2252+ spin_unlock(&ccs_query_list_lock);
2253+ if (quota_exceeded)
2254+ goto out;
2255+ /* Give 10 seconds for supervisor's opinion. */
2256+ while (entry.timer < 10) {
2257+ wake_up_all(&ccs_query_wait);
2258+ if (wait_event_interruptible_timeout
2259+ (ccs_answer_wait, entry.answer ||
2260+ !atomic_read(&ccs_query_observers), HZ))
2261+ break;
2262+ else
2263+ entry.timer++;
2264+ }
2265+ spin_lock(&ccs_query_list_lock);
2266+ list_del(&entry.list);
2267+ ccs_memory_used[CCS_MEMORY_QUERY] -= len;
2268+ spin_unlock(&ccs_query_list_lock);
2269+ switch (entry.answer) {
2270+ case 3: /* Asked to retry by administrator. */
2271+ error = CCS_RETRY_REQUEST;
2272+ r->retry++;
2273+ break;
2274+ case 1:
2275+ /* Granted by administrator. */
2276+ error = 0;
2277+ break;
2278+ default:
2279+ /* Timed out or rejected by administrator. */
2280+ break;
2281+ }
2282+out:
2283+ kfree(entry.query);
2284+ return error;
2285+}
2286+
2287+/**
2288+ * ccs_poll_query - poll() for /proc/ccs/query.
2289+ *
2290+ * @file: Pointer to "struct file".
2291+ * @wait: Pointer to "poll_table".
2292+ *
2293+ * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
2294+ *
2295+ * Waits for access requests which violated policy in enforcing mode.
2296+ */
2297+static int ccs_poll_query(struct file *file, poll_table *wait)
2298+{
2299+ struct list_head *tmp;
2300+ bool found = false;
2301+ u8 i;
2302+ for (i = 0; i < 2; i++) {
2303+ spin_lock(&ccs_query_list_lock);
2304+ list_for_each(tmp, &ccs_query_list) {
2305+ struct ccs_query *ptr =
2306+ list_entry(tmp, typeof(*ptr), list);
2307+ if (ptr->answer)
2308+ continue;
2309+ found = true;
2310+ break;
2311+ }
2312+ spin_unlock(&ccs_query_list_lock);
2313+ if (found)
2314+ return POLLIN | POLLRDNORM;
2315+ if (i)
2316+ break;
2317+ poll_wait(file, &ccs_query_wait, wait);
2318+ }
2319+ return 0;
2320+}
2321+
2322+/**
2323+ * ccs_read_query - Read access requests which violated policy in enforcing mode.
2324+ *
2325+ * @head: Pointer to "struct ccs_io_buffer".
2326+ *
2327+ * Returns nothing.
2328+ */
2329+static void ccs_read_query(struct ccs_io_buffer *head)
2330+{
2331+ struct list_head *tmp;
2332+ unsigned int pos = 0;
2333+ size_t len = 0;
2334+ char *buf;
2335+ if (head->r.w_pos)
2336+ return;
2337+ kfree(head->read_buf);
2338+ head->read_buf = NULL;
2339+ spin_lock(&ccs_query_list_lock);
2340+ list_for_each(tmp, &ccs_query_list) {
2341+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2342+ if (ptr->answer)
2343+ continue;
2344+ if (pos++ != head->r.query_index)
2345+ continue;
2346+ len = ptr->query_len;
2347+ break;
2348+ }
2349+ spin_unlock(&ccs_query_list_lock);
2350+ if (!len) {
2351+ head->r.query_index = 0;
2352+ return;
2353+ }
2354+ buf = kzalloc(len + 32, CCS_GFP_FLAGS);
2355+ if (!buf)
2356+ return;
2357+ pos = 0;
2358+ spin_lock(&ccs_query_list_lock);
2359+ list_for_each(tmp, &ccs_query_list) {
2360+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2361+ if (ptr->answer)
2362+ continue;
2363+ if (pos++ != head->r.query_index)
2364+ continue;
2365+ /*
2366+ * Some query can be skipped because ccs_query_list
2367+ * can change, but I don't care.
2368+ */
2369+ if (len == ptr->query_len)
2370+ snprintf(buf, len + 32, "Q%u-%hu\n%s", ptr->serial,
2371+ ptr->retry, ptr->query);
2372+ break;
2373+ }
2374+ spin_unlock(&ccs_query_list_lock);
2375+ if (buf[0]) {
2376+ head->read_buf = buf;
2377+ head->r.w[head->r.w_pos++] = buf;
2378+ head->r.query_index++;
2379+ } else {
2380+ kfree(buf);
2381+ }
2382+}
2383+
2384+/**
2385+ * ccs_write_answer - Write the supervisor's decision.
2386+ *
2387+ * @head: Pointer to "struct ccs_io_buffer".
2388+ *
2389+ * Returns 0 on success, -EINVAL otherwise.
2390+ */
2391+static int ccs_write_answer(struct ccs_io_buffer *head)
2392+{
2393+ char *data = head->write_buf;
2394+ struct list_head *tmp;
2395+ unsigned int serial;
2396+ unsigned int answer;
2397+ spin_lock(&ccs_query_list_lock);
2398+ list_for_each(tmp, &ccs_query_list) {
2399+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2400+ ptr->timer = 0;
2401+ }
2402+ spin_unlock(&ccs_query_list_lock);
2403+ if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
2404+ return -EINVAL;
2405+ spin_lock(&ccs_query_list_lock);
2406+ list_for_each(tmp, &ccs_query_list) {
2407+ struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2408+ if (ptr->serial != serial)
2409+ continue;
2410+ if (!ptr->answer)
2411+ ptr->answer = (u8) answer;
2412+ break;
2413+ }
2414+ spin_unlock(&ccs_query_list_lock);
2415+ wake_up_all(&ccs_answer_wait);
2416+ return 0;
2417+}
2418+
2419+/**
2420+ * ccs_read_version - Get version.
2421+ *
2422+ * @head: Pointer to "struct ccs_io_buffer".
2423+ *
2424+ * Returns nothing.
2425+ */
2426+static void ccs_read_version(struct ccs_io_buffer *head)
2427+{
2428+ if (head->r.eof)
2429+ return;
2430+ ccs_set_string(head, "1.8.1");
2431+ head->r.eof = true;
2432+}
2433+
2434+/* String table for /proc/ccs/stat interface. */
2435+static const char * const ccs_policy_headers[CCS_MAX_POLICY_STAT] = {
2436+ [CCS_STAT_POLICY_UPDATES] = "update:",
2437+ [CCS_STAT_POLICY_LEARNING] = "violation in learning mode:",
2438+ [CCS_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
2439+ [CCS_STAT_POLICY_ENFORCING] = "violation in enforcing mode:",
2440+};
2441+
2442+/* String table for /proc/ccs/stat interface. */
2443+static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
2444+ [CCS_MEMORY_POLICY] = "policy:",
2445+ [CCS_MEMORY_AUDIT] = "audit log:",
2446+ [CCS_MEMORY_QUERY] = "query message:",
2447+};
2448+
2449+/* Timestamp counter for last updated. */
2450+static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
2451+/* Counter for number of updates. */
2452+static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
2453+
2454+/**
2455+ * ccs_update_stat - Update statistic counters.
2456+ *
2457+ * @index: Index for policy type.
2458+ *
2459+ * Returns nothing.
2460+ */
2461+void ccs_update_stat(const u8 index)
2462+{
2463+ struct timeval tv;
2464+ do_gettimeofday(&tv);
2465+ /*
2466+ * I don't use atomic operations because race condition is not fatal.
2467+ */
2468+ ccs_stat_updated[index]++;
2469+ ccs_stat_modified[index] = tv.tv_sec;
2470+}
2471+
2472+/**
2473+ * ccs_read_stat - Read statistic data.
2474+ *
2475+ * @head: Pointer to "struct ccs_io_buffer".
2476+ *
2477+ * Returns nothing.
2478+ */
2479+static void ccs_read_stat(struct ccs_io_buffer *head)
2480+{
2481+ u8 i;
2482+ unsigned int total = 0;
2483+ if (head->r.eof)
2484+ return;
2485+ for (i = 0; i < CCS_MAX_POLICY_STAT; i++) {
2486+ ccs_io_printf(head, "Policy %-30s %10u", ccs_policy_headers[i],
2487+ ccs_stat_updated[i]);
2488+ if (ccs_stat_modified[i]) {
2489+ struct ccs_time stamp;
2490+ ccs_convert_time(ccs_stat_modified[i], &stamp);
2491+ ccs_io_printf(head, " (Last: %04u/%02u/%02u "
2492+ "%02u:%02u:%02u)",
2493+ stamp.year, stamp.month, stamp.day,
2494+ stamp.hour, stamp.min, stamp.sec);
2495+ }
2496+ ccs_set_lf(head);
2497+ }
2498+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++) {
2499+ unsigned int used = ccs_memory_used[i];
2500+ total += used;
2501+ ccs_io_printf(head, "Memory used by %-22s %10u",
2502+ ccs_memory_headers[i], used);
2503+ used = ccs_memory_quota[i];
2504+ if (used)
2505+ ccs_io_printf(head, " (Quota: %10u)", used);
2506+ ccs_set_lf(head);
2507+ }
2508+ ccs_io_printf(head, "Total memory used: %10u\n",
2509+ total);
2510+ head->r.eof = true;
2511+}
2512+
2513+/**
2514+ * ccs_write_stat - Set memory quota.
2515+ *
2516+ * @head: Pointer to "struct ccs_io_buffer".
2517+ *
2518+ * Returns 0.
2519+ */
2520+static int ccs_write_stat(struct ccs_io_buffer *head)
2521+{
2522+ char *data = head->write_buf;
2523+ u8 i;
2524+ if (ccs_str_starts(&data, "Memory used by "))
2525+ for (i = 0; i < CCS_MAX_MEMORY_STAT; i++)
2526+ if (ccs_str_starts(&data, ccs_memory_headers[i]))
2527+ sscanf(data, "%u", &ccs_memory_quota[i]);
2528+ return 0;
2529+}
2530+
2531+/**
2532+ * ccs_open_control - open() for /proc/ccs/ interface.
2533+ *
2534+ * @type: Type of interface.
2535+ * @file: Pointer to "struct file".
2536+ *
2537+ * Returns 0 on success, negative value otherwise.
2538+ */
2539+int ccs_open_control(const u8 type, struct file *file)
2540+{
2541+ struct ccs_io_buffer *head = kzalloc(sizeof(*head), CCS_GFP_FLAGS);
2542+ if (!head)
2543+ return -ENOMEM;
2544+ mutex_init(&head->io_sem);
2545+ head->type = type;
2546+ switch (type) {
2547+ case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */
2548+ head->write = ccs_write_domain;
2549+ head->read = ccs_read_domain;
2550+ break;
2551+ case CCS_EXCEPTIONPOLICY: /* /proc/ccs/exception_policy */
2552+ head->write = ccs_write_exception;
2553+ head->read = ccs_read_exception;
2554+ break;
2555+ case CCS_AUDIT: /* /proc/ccs/audit */
2556+ head->poll = ccs_poll_log;
2557+ head->read = ccs_read_log;
2558+ break;
2559+ case CCS_DOMAIN_STATUS: /* /proc/ccs/.domain_status */
2560+ head->write = ccs_write_domain_profile;
2561+ head->read = ccs_read_domain_profile;
2562+ break;
2563+ case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */
2564+ /* Allow execute_handler to read process's status. */
2565+ if (!(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
2566+ kfree(head);
2567+ return -EPERM;
2568+ }
2569+ /* fall through */
2570+ case CCS_PROCESS_STATUS: /* /proc/ccs/.process_status */
2571+ head->write = ccs_write_pid;
2572+ head->read = ccs_read_pid;
2573+ break;
2574+ case CCS_VERSION: /* /proc/ccs/version */
2575+ head->read = ccs_read_version;
2576+ head->readbuf_size = 128;
2577+ break;
2578+ case CCS_STAT: /* /proc/ccs/stat */
2579+ head->write = ccs_write_stat;
2580+ head->read = ccs_read_stat;
2581+ head->readbuf_size = 1024;
2582+ break;
2583+ case CCS_PROFILE: /* /proc/ccs/profile */
2584+ head->write = ccs_write_profile;
2585+ head->read = ccs_read_profile;
2586+ break;
2587+ case CCS_QUERY: /* /proc/ccs/query */
2588+ head->poll = ccs_poll_query;
2589+ head->write = ccs_write_answer;
2590+ head->read = ccs_read_query;
2591+ break;
2592+ case CCS_MANAGER: /* /proc/ccs/manager */
2593+ head->write = ccs_write_manager;
2594+ head->read = ccs_read_manager;
2595+ break;
2596+ }
2597+ if (!(file->f_mode & FMODE_READ)) {
2598+ /*
2599+ * No need to allocate read_buf since it is not opened
2600+ * for reading.
2601+ */
2602+ head->read = NULL;
2603+ head->poll = NULL;
2604+ } else if (!head->poll) {
2605+ /* Don't allocate read_buf for poll() access. */
2606+ if (!head->readbuf_size)
2607+ head->readbuf_size = 4096;
2608+ head->read_buf = kzalloc(head->readbuf_size, CCS_GFP_FLAGS);
2609+ if (!head->read_buf) {
2610+ kfree(head);
2611+ return -ENOMEM;
2612+ }
2613+ }
2614+ if (!(file->f_mode & FMODE_WRITE)) {
2615+ /*
2616+ * No need to allocate write_buf since it is not opened
2617+ * for writing.
2618+ */
2619+ head->write = NULL;
2620+ } else if (head->write) {
2621+ head->writebuf_size = 4096;
2622+ head->write_buf = kzalloc(head->writebuf_size, CCS_GFP_FLAGS);
2623+ if (!head->write_buf) {
2624+ kfree(head->read_buf);
2625+ kfree(head);
2626+ return -ENOMEM;
2627+ }
2628+ }
2629+ /*
2630+ * If the file is /proc/ccs/query, increment the observer counter.
2631+ * The obserber counter is used by ccs_supervisor() to see if
2632+ * there is some process monitoring /proc/ccs/query.
2633+ */
2634+ if (type == CCS_QUERY)
2635+ atomic_inc(&ccs_query_observers);
2636+ file->private_data = head;
2637+ ccs_notify_gc(head, true);
2638+ return 0;
2639+}
2640+
2641+/**
2642+ * ccs_poll_control - poll() for /proc/ccs/ interface.
2643+ *
2644+ * @file: Pointer to "struct file".
2645+ * @wait: Pointer to "poll_table".
2646+ *
2647+ * Returns return value of poll().
2648+ *
2649+ * Waits for read readiness.
2650+ * /proc/ccs/query is handled by /usr/sbin/ccs-queryd and
2651+ * /proc/ccs/audit is handled by /usr/sbin/ccs-auditd.
2652+ */
2653+int ccs_poll_control(struct file *file, poll_table *wait)
2654+{
2655+ struct ccs_io_buffer *head = file->private_data;
2656+ if (!head->poll)
2657+ return -ENOSYS;
2658+ return head->poll(file, wait);
2659+}
2660+
2661+/**
2662+ * ccs_read_control - read() for /proc/ccs/ interface.
2663+ *
2664+ * @file: Pointer to "struct file".
2665+ * @buffer: Poiner to buffer to write to.
2666+ * @buffer_len: Size of @buffer.
2667+ *
2668+ * Returns bytes read on success, negative value otherwise.
2669+ */
2670+ssize_t ccs_read_control(struct file *file, char __user *buffer,
2671+ const size_t buffer_len)
2672+{
2673+ int len;
2674+ struct ccs_io_buffer *head = file->private_data;
2675+ int idx;
2676+ if (!head->read)
2677+ return -ENOSYS;
2678+ if (!access_ok(VERIFY_WRITE, buffer, buffer_len))
2679+ return -EFAULT;
2680+ if (mutex_lock_interruptible(&head->io_sem))
2681+ return -EINTR;
2682+ head->read_user_buf = buffer;
2683+ head->read_user_buf_avail = buffer_len;
2684+ idx = ccs_read_lock();
2685+ if (ccs_flush(head))
2686+ /* Call the policy handler. */
2687+ head->read(head);
2688+ ccs_flush(head);
2689+ ccs_read_unlock(idx);
2690+ len = head->read_user_buf - buffer;
2691+ mutex_unlock(&head->io_sem);
2692+ return len;
2693+}
2694+
2695+/**
2696+ * ccs_write_control - write() for /proc/ccs/ interface.
2697+ *
2698+ * @file: Pointer to "struct file".
2699+ * @buffer: Pointer to buffer to read from.
2700+ * @buffer_len: Size of @buffer.
2701+ *
2702+ * Returns @buffer_len on success, negative value otherwise.
2703+ */
2704+ssize_t ccs_write_control(struct file *file, const char __user *buffer,
2705+ const size_t buffer_len)
2706+{
2707+ struct ccs_io_buffer *head = file->private_data;
2708+ int error = buffer_len;
2709+ size_t avail_len = buffer_len;
2710+ char *cp0 = head->write_buf;
2711+ int idx;
2712+ if (!head->write)
2713+ return -ENOSYS;
2714+ if (!access_ok(VERIFY_READ, buffer, buffer_len))
2715+ return -EFAULT;
2716+ if (mutex_lock_interruptible(&head->io_sem))
2717+ return -EINTR;
2718+ idx = ccs_read_lock();
2719+ /* Don't allow updating policies by non manager programs. */
2720+ if (head->write != ccs_write_pid && head->write != ccs_write_domain &&
2721+ head->write != ccs_write_exception && !ccs_manager()) {
2722+ ccs_read_unlock(idx);
2723+ mutex_unlock(&head->io_sem);
2724+ return -EPERM;
2725+ }
2726+ /* Read a line and dispatch it to the policy handler. */
2727+ while (avail_len > 0) {
2728+ char c;
2729+ if (head->w.avail >= head->writebuf_size - 1) {
2730+ const int len = head->writebuf_size * 2;
2731+ char *cp = kzalloc(len, CCS_GFP_FLAGS);
2732+ if (!cp) {
2733+ error = -ENOMEM;
2734+ break;
2735+ }
2736+ memmove(cp, cp0, head->w.avail);
2737+ kfree(cp0);
2738+ head->write_buf = cp;
2739+ cp0 = cp;
2740+ head->writebuf_size = len;
2741+ }
2742+ if (get_user(c, buffer)) {
2743+ error = -EFAULT;
2744+ break;
2745+ }
2746+ buffer++;
2747+ avail_len--;
2748+ cp0[head->w.avail++] = c;
2749+ if (c != '\n')
2750+ continue;
2751+ cp0[head->w.avail - 1] = '\0';
2752+ head->w.avail = 0;
2753+ ccs_normalize_line(cp0);
2754+ {
2755+ const int ret = head->write(head);
2756+ if (ret == -EPERM) {
2757+ error = -EPERM;
2758+ break;
2759+ }
2760+ if (ret)
2761+ continue;
2762+ }
2763+ switch (head->type) {
2764+ case CCS_DOMAINPOLICY:
2765+ case CCS_EXCEPTIONPOLICY:
2766+ case CCS_DOMAIN_STATUS:
2767+ case CCS_STAT:
2768+ case CCS_PROFILE:
2769+ case CCS_MANAGER:
2770+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
2771+ break;
2772+ default:
2773+ break;
2774+ }
2775+ }
2776+ ccs_read_unlock(idx);
2777+ mutex_unlock(&head->io_sem);
2778+ return error;
2779+}
2780+
2781+/**
2782+ * ccs_close_control - close() for /proc/ccs/ interface.
2783+ *
2784+ * @file: Pointer to "struct file".
2785+ *
2786+ * Returns 0.
2787+ */
2788+int ccs_close_control(struct file *file)
2789+{
2790+ struct ccs_io_buffer *head = file->private_data;
2791+ file->private_data = NULL;
2792+ /*
2793+ * If the file is /proc/ccs/query, decrement the observer counter.
2794+ */
2795+ if (head->type == CCS_QUERY &&
2796+ atomic_dec_and_test(&ccs_query_observers))
2797+ wake_up_all(&ccs_answer_wait);
2798+ ccs_notify_gc(head, false);
2799+ return 0;
2800+}
2801+
2802+/**
2803+ * ccs_policy_io_init - Register hooks for policy I/O.
2804+ *
2805+ * Returns nothing.
2806+ */
2807+void __init ccs_policy_io_init(void)
2808+{
2809+ ccsecurity_ops.check_profile = ccs_check_profile;
2810+}
2811+
2812+#ifdef CONFIG_CCSECURITY_USE_BUILTIN_POLICY
2813+/**
2814+ * ccs_load_builtin_policy - Load built-in policy.
2815+ *
2816+ * Returns nothing.
2817+ */
2818+void __init ccs_load_builtin_policy(void)
2819+{
2820+ /*
2821+ * This include file is manually created and contains built-in policy
2822+ * named "ccs_builtin_profile", "ccs_builtin_exception_policy",
2823+ * "ccs_builtin_domain_policy", "ccs_builtin_manager",
2824+ * "ccs_builtin_stat" in the form of "static char [] __initdata".
2825+ */
2826+#include "builtin-policy.h"
2827+ struct ccs_io_buffer head;
2828+ u8 i;
2829+ const int idx = ccs_read_lock();
2830+ for (i = 0; i < 5; i++) {
2831+ char *start = "";
2832+ memset(&head, 0, sizeof(head));
2833+ switch (i) {
2834+ case 0:
2835+ start = ccs_builtin_profile;
2836+ head.write = ccs_write_profile;
2837+ break;
2838+ case 1:
2839+ start = ccs_builtin_exception_policy;
2840+ head.write = ccs_write_exception;
2841+ break;
2842+ case 2:
2843+ start = ccs_builtin_domain_policy;
2844+ head.write = ccs_write_domain;
2845+ break;
2846+ case 3:
2847+ start = ccs_builtin_manager;
2848+ head.write = ccs_write_manager;
2849+ break;
2850+ case 4:
2851+ start = ccs_builtin_stat;
2852+ head.write = ccs_write_stat;
2853+ break;
2854+ }
2855+ while (1) {
2856+ char *end = strchr(start, '\n');
2857+ if (!end)
2858+ break;
2859+ *end = '\0';
2860+ ccs_normalize_line(start);
2861+ head.write_buf = start;
2862+ head.write(&head);
2863+ start = end + 1;
2864+ }
2865+ }
2866+ ccs_read_unlock(idx);
2867+#ifdef CONFIG_CCSECURITY_ACTIVATE_FROM_THE_BEGINNING
2868+ ccs_check_profile();
2869+#endif
2870+}
2871+#endif
--- tags/patches/1.0.12/lsm.c (nonexistent)
+++ tags/patches/1.0.12/lsm.c (revision 197)
@@ -0,0 +1,2846 @@
1+/*
2+ * lsm.c
3+ *
4+ * Copyright (C) 2010-2011 Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
5+ *
6+ * Version: 1.0.12 2011/04/11
7+ */
8+
9+#include "internal.h"
10+#include <linux/security.h>
11+#include <linux/namei.h>
12+
13+/* Prototype definition. */
14+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
15+static void ccs_task_security_gc(void);
16+static int ccs_copy_cred_security(const struct cred *new,
17+ const struct cred *old, gfp_t gfp);
18+static struct ccs_security *ccs_find_cred_security(const struct cred *cred);
19+static void (*ccs___put_task_struct) (struct task_struct *t);
20+#endif
21+
22+/* Dummy security context for avoiding NULL pointer dereference. */
23+static struct ccs_security ccs_oom_security = {
24+ .ccs_domain_info = &ccs_kernel_domain
25+};
26+
27+/* Dummy security context for avoiding NULL pointer dereference. */
28+static struct ccs_security ccs_default_security = {
29+ .ccs_domain_info = &ccs_kernel_domain
30+};
31+
32+/* For exporting variables and functions. */
33+struct ccsecurity_exports ccsecurity_exports;
34+/* Members are updated by loadable kernel module. */
35+struct ccsecurity_operations ccsecurity_ops;
36+
37+/* Function pointers originally registered by register_security(). */
38+static struct security_operations original_security_ops /* = *security_ops; */;
39+
40+/*
41+ * AppArmor patch added "struct vfsmount *" to security_inode_\*() hooks.
42+ * Detect it by checking whether D_PATH_DISCONNECT is defined or not.
43+ * Also, there may be other kernels with "struct vfsmount *" added.
44+ * If you got build failure, check security_inode_\*() hooks in
45+ * include/linux/security.h.
46+ */
47+#if defined(D_PATH_DISCONNECT)
48+#define CCS_INODE_HOOK_HAS_MNT
49+#elif defined(CONFIG_SUSE_KERNEL) && LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 25)
50+#define CCS_INODE_HOOK_HAS_MNT
51+#elif defined(CONFIG_SECURITY_APPARMOR) && LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 24)
52+#define CCS_INODE_HOOK_HAS_MNT
53+#endif
54+
55+/**
56+ * ccs_add_task_security - Add "struct ccs_security" to list.
57+ *
58+ * @ptr: Pointer to "struct ccs_security".
59+ * @list: Pointer to "struct list_head".
60+ *
61+ * Returns nothing.
62+ */
63+static void ccs_add_task_security(struct ccs_security *ptr,
64+ struct list_head *list)
65+{
66+ unsigned long flags;
67+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
68+ list_add_rcu(&ptr->list, list);
69+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
70+}
71+
72+
73+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
74+
75+/**
76+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
77+ *
78+ * @rcu: Pointer to "struct rcu_head".
79+ *
80+ * Returns nothing.
81+ */
82+static void ccs_rcu_free(struct rcu_head *rcu)
83+{
84+ struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
85+ struct ccs_execve *ee = ptr->ee;
86+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
87+ /*
88+ * If this security context was used by "struct task_struct" and
89+ * remembers "struct cred" in "struct linux_binprm", it indicates that
90+ * that "struct task_struct" exited immediately after do_execve() has
91+ * failed.
92+ */
93+ if (ptr->task && ptr->cred) {
94+ /*
95+ printk(KERN_DEBUG
96+ "Dropping refcount on \"struct cred\" in "
97+ "\"struct linux_binprm\" because some "
98+ "\"struct task_struct\" has exit()ed immediately after "
99+ "do_execve() has failed.\n");
100+ */
101+ put_cred(ptr->cred);
102+ }
103+#endif
104+ if (ee) {
105+ /*
106+ printk(KERN_DEBUG
107+ "Releasing memory in \"struct ccs_execve\" because "
108+ "some \"struct task_struct\" has exit()ed immediately "
109+ "after do_execve() has failed.\n");
110+ */
111+ kfree(ee->handler_path);
112+ kfree(ee->tmp);
113+ kfree(ee->dump.data);
114+ kfree(ee);
115+ }
116+ kfree(ptr);
117+}
118+
119+#else
120+
121+/**
122+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
123+ *
124+ * @arg: Pointer to "void".
125+ *
126+ * Returns nothing.
127+ */
128+static void ccs_rcu_free(void *arg)
129+{
130+ struct ccs_security *ptr = arg;
131+ struct ccs_execve *ee = ptr->ee;
132+ if (ee) {
133+ kfree(ee->handler_path);
134+ kfree(ee->tmp);
135+ kfree(ee->dump.data);
136+ kfree(ee);
137+ }
138+ kfree(ptr);
139+}
140+
141+#endif
142+
143+/**
144+ * ccs_del_security - Release "struct ccs_security".
145+ *
146+ * @ptr: Pointer to "struct ccs_security".
147+ *
148+ * Returns nothing.
149+ */
150+static void ccs_del_security(struct ccs_security *ptr)
151+{
152+ unsigned long flags;
153+ if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
154+ return;
155+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
156+ list_del_rcu(&ptr->list);
157+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
158+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
159+ call_rcu(&ptr->rcu, ccs_rcu_free);
160+#else
161+ call_rcu(&ptr->rcu, ccs_rcu_free, ptr);
162+#endif
163+}
164+
165+/**
166+ * ccs_clear_execve - Release memory used by do_execve().
167+ *
168+ * @ret: 0 if do_execve() succeeded, negative value otherwise.
169+ * @security: Pointer to "struct ccs_security".
170+ *
171+ * Returns nothing.
172+ */
173+static void ccs_clear_execve(int ret, struct ccs_security *security)
174+{
175+ struct ccs_execve *ee;
176+ if (security == &ccs_default_security || security == &ccs_oom_security)
177+ return;
178+ ee = security->ee;
179+ security->ee = NULL;
180+ if (!ee)
181+ return;
182+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
183+ /*
184+ * Drop refcount on "struct cred" in "struct linux_binprm" and forget
185+ * it.
186+ */
187+ put_cred(security->cred);
188+ security->cred = NULL;
189+#endif
190+ ee->reader_idx = ccs_read_lock();
191+ ccs_finish_execve(ret, ee);
192+}
193+
194+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
195+
196+/*
197+ * List of "struct ccs_security" for "struct cred".
198+ *
199+ * Since the number of "struct cred" is nearly equals to the number of
200+ * "struct task_struct", we allocate hash tables like ccs_task_security_list.
201+ */
202+static struct list_head ccs_cred_security_list[CCS_MAX_TASK_SECURITY_HASH];
203+
204+/**
205+ * ccs_add_cred_security - Add "struct ccs_security" to list.
206+ *
207+ * @ptr: Pointer to "struct ccs_security".
208+ *
209+ * Returns nothing.
210+ */
211+static void ccs_add_cred_security(struct ccs_security *ptr)
212+{
213+ unsigned long flags;
214+ struct list_head *list = &ccs_cred_security_list
215+ [hash_ptr((void *) ptr->cred, CCS_TASK_SECURITY_HASH_BITS)];
216+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
217+ list_add_rcu(&ptr->list, list);
218+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
219+}
220+
221+/**
222+ * ccs_task_create - Make snapshot of security context for new task.
223+ *
224+ * @clone_flags: Flags passed to clone().
225+ *
226+ * Returns 0 on success, negative value otherwise.
227+ */
228+static int ccs_task_create(unsigned long clone_flags)
229+{
230+ int rc;
231+ struct ccs_security *old_security;
232+ struct ccs_security *new_security;
233+ struct cred *cred = prepare_creds();
234+ if (!cred)
235+ return -ENOMEM;
236+ while (!original_security_ops.task_create);
237+ rc = original_security_ops.task_create(clone_flags);
238+ if (rc) {
239+ abort_creds(cred);
240+ return rc;
241+ }
242+ old_security = ccs_find_task_security(current);
243+ new_security = ccs_find_cred_security(cred);
244+ new_security->ccs_domain_info = old_security->ccs_domain_info;
245+ new_security->ccs_flags = old_security->ccs_flags;
246+ return commit_creds(cred);
247+}
248+
249+/**
250+ * ccs_cred_prepare - Allocate memory for new credentials.
251+ *
252+ * @new: Pointer to "struct cred".
253+ * @old: Pointer to "struct cred".
254+ * @gfp: Memory allocation flags.
255+ *
256+ * Returns 0 on success, negative value otherwise.
257+ */
258+static int ccs_cred_prepare(struct cred *new, const struct cred *old,
259+ gfp_t gfp)
260+{
261+ int rc = ccs_copy_cred_security(new, old, gfp);
262+ if (rc)
263+ return rc;
264+ if (gfp == GFP_KERNEL)
265+ ccs_task_security_gc();
266+ while (!original_security_ops.cred_prepare);
267+ rc = original_security_ops.cred_prepare(new, old, gfp);
268+ if (rc)
269+ ccs_del_security(ccs_find_cred_security(new));
270+ return rc;
271+}
272+
273+/**
274+ * ccs_cred_free - Release memory used by credentials.
275+ *
276+ * @cred: Pointer to "struct cred".
277+ *
278+ * Returns nothing.
279+ */
280+static void ccs_cred_free(struct cred *cred)
281+{
282+ while (!original_security_ops.cred_free);
283+ original_security_ops.cred_free(cred);
284+ ccs_del_security(ccs_find_cred_security(cred));
285+}
286+
287+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
288+
289+/**
290+ * ccs_alloc_cred_security - Allocate memory for new credentials.
291+ *
292+ * @cred: Pointer to "struct cred".
293+ * @gfp: Memory allocation flags.
294+ *
295+ * Returns 0 on success, negative value otherwise.
296+ */
297+static int ccs_alloc_cred_security(const struct cred *cred, gfp_t gfp)
298+{
299+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
300+ gfp);
301+ if (!new_security)
302+ return -ENOMEM;
303+ new_security->cred = cred;
304+ ccs_add_cred_security(new_security);
305+ return 0;
306+}
307+
308+/**
309+ * ccs_cred_alloc_blank - Allocate memory for new credentials.
310+ *
311+ * @new: Pointer to "struct cred".
312+ * @gfp: Memory allocation flags.
313+ *
314+ * Returns 0 on success, negative value otherwise.
315+ */
316+static int ccs_cred_alloc_blank(struct cred *new, gfp_t gfp)
317+{
318+ int rc = ccs_alloc_cred_security(new, gfp);
319+ if (rc)
320+ return rc;
321+ while (!original_security_ops.cred_alloc_blank);
322+ rc = original_security_ops.cred_alloc_blank(new, gfp);
323+ if (rc)
324+ ccs_del_security(ccs_find_cred_security(new));
325+ return rc;
326+}
327+
328+/**
329+ * ccs_cred_transfer - Transfer "struct ccs_security" between credentials.
330+ *
331+ * @new: Pointer to "struct cred".
332+ * @old: Pointer to "struct cred".
333+ *
334+ * Returns nothing.
335+ */
336+static void ccs_cred_transfer(struct cred *new, const struct cred *old)
337+{
338+ struct ccs_security *new_security;
339+ struct ccs_security *old_security;
340+ while (!original_security_ops.cred_transfer);
341+ original_security_ops.cred_transfer(new, old);
342+ new_security = ccs_find_cred_security(new);
343+ old_security = ccs_find_cred_security(old);
344+ if (new_security == &ccs_default_security ||
345+ new_security == &ccs_oom_security ||
346+ old_security == &ccs_default_security ||
347+ old_security == &ccs_oom_security)
348+ return;
349+ new_security->ccs_flags = old_security->ccs_flags;
350+ new_security->ccs_domain_info = old_security->ccs_domain_info;
351+}
352+
353+#endif
354+
355+#else
356+
357+/**
358+ * ccs_copy_task_security - Allocate memory for new tasks.
359+ *
360+ * @task: Pointer to "struct task_struct".
361+ *
362+ * Returns 0 on success, negative value otherwise.
363+ */
364+static int ccs_copy_task_security(struct task_struct *task)
365+{
366+ struct ccs_security *old_security = ccs_current_security();
367+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
368+ GFP_KERNEL);
369+ struct list_head *list = &ccs_task_security_list
370+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
371+ if (!new_security)
372+ return -ENOMEM;
373+ *new_security = *old_security;
374+ new_security->task = task;
375+ ccs_add_task_security(new_security, list);
376+ return 0;
377+}
378+
379+/**
380+ * ccs_task_alloc_security - Allocate memory for new tasks.
381+ *
382+ * @p: Pointer to "struct task_struct".
383+ *
384+ * Returns 0 on success, negative value otherwise.
385+ */
386+static int ccs_task_alloc_security(struct task_struct *p)
387+{
388+ int rc = ccs_copy_task_security(p);
389+ if (rc)
390+ return rc;
391+ while (!original_security_ops.task_alloc_security);
392+ rc = original_security_ops.task_alloc_security(p);
393+ if (rc)
394+ ccs_del_security(ccs_find_task_security(p));
395+ return rc;
396+}
397+
398+/**
399+ * ccs_task_free_security - Release memory for "struct task_struct".
400+ *
401+ * @p: Pointer to "struct task_struct".
402+ *
403+ * Returns nothing.
404+ */
405+static void ccs_task_free_security(struct task_struct *p)
406+{
407+ while (!original_security_ops.task_free_security);
408+ original_security_ops.task_free_security(p);
409+ ccs_del_security(ccs_find_task_security(p));
410+}
411+
412+/**
413+ * ccs_bprm_free_security - Release memory for "struct linux_binprm".
414+ *
415+ * @bprm: Pointer to "struct linux_binprm".
416+ *
417+ * Returns nothing.
418+ */
419+static void ccs_bprm_free_security(struct linux_binprm *bprm)
420+{
421+ while (!original_security_ops.bprm_free_security);
422+ original_security_ops.bprm_free_security(bprm);
423+ /*
424+ * If do_execve() succeeded,
425+ * ccs_clear_execve(0, ccs_current_security());
426+ * is called before calling below one.
427+ * Thus, below call becomes no-op if do_execve() succeeded.
428+ */
429+ ccs_clear_execve(-1, ccs_current_security());
430+}
431+
432+#endif
433+
434+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6)
435+
436+/**
437+ * ccs_bprm_compute_creds - A hook which is called when do_execve() succeeded.
438+ *
439+ * @bprm: Pointer to "struct linux_binprm".
440+ *
441+ * Returns nothing.
442+ */
443+static void ccs_bprm_compute_creds(struct linux_binprm *bprm)
444+{
445+ while (!original_security_ops.bprm_compute_creds);
446+ original_security_ops.bprm_compute_creds(bprm);
447+ ccs_clear_execve(0, ccs_current_security());
448+}
449+
450+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
451+
452+/**
453+ * ccs_bprm_apply_creds - A hook which is called when do_execve() succeeded.
454+ *
455+ * @bprm: Pointer to "struct linux_binprm".
456+ * @unsafe: Unsafe flag.
457+ *
458+ * Returns nothing.
459+ */
460+static void ccs_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
461+{
462+ while (!original_security_ops.bprm_apply_creds);
463+ original_security_ops.bprm_apply_creds(bprm, unsafe);
464+ ccs_clear_execve(0, ccs_current_security());
465+}
466+
467+#else
468+
469+/**
470+ * ccs_bprm_committing_creds - A hook which is called when do_execve() succeeded.
471+ *
472+ * @bprm: Pointer to "struct linux_binprm".
473+ *
474+ * Returns nothing.
475+ */
476+static void ccs_bprm_committing_creds(struct linux_binprm *bprm)
477+{
478+ struct ccs_security *old_security;
479+ struct ccs_security *new_security;
480+ while (!original_security_ops.bprm_committing_creds);
481+ original_security_ops.bprm_committing_creds(bprm);
482+ old_security = ccs_current_security();
483+ if (old_security == &ccs_default_security ||
484+ old_security == &ccs_oom_security)
485+ return;
486+ ccs_clear_execve(0, old_security);
487+ /* Update current task's cred's domain for future fork(). */
488+ new_security = ccs_find_cred_security(bprm->cred);
489+ new_security->ccs_flags = old_security->ccs_flags;
490+ new_security->ccs_domain_info = old_security->ccs_domain_info;
491+}
492+
493+#endif
494+
495+/**
496+ * ccs_bprm_check_security - Check permission for execve().
497+ *
498+ * @bprm: Pointer to "struct linux_binprm".
499+ *
500+ * Returns 0 on success, negative value otherwise.
501+ */
502+static int ccs_bprm_check_security(struct linux_binprm *bprm)
503+{
504+ struct ccs_security *security = ccs_current_security();
505+ if (security == &ccs_default_security || security == &ccs_oom_security)
506+ return -ENOMEM;
507+ if (!security->ee) {
508+ int rc;
509+ if (!ccs_policy_loaded)
510+ ccs_load_policy(bprm->filename);
511+ rc = ccs_start_execve(bprm, &security->ee);
512+ if (security->ee) {
513+ ccs_read_unlock(security->ee->reader_idx);
514+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
515+ /*
516+ * Get refcount on "struct cred" in
517+ * "struct linux_binprm" and remember it.
518+ */
519+ get_cred(bprm->cred);
520+ security->cred = bprm->cred;
521+#endif
522+ }
523+ if (rc)
524+ return rc;
525+ }
526+ while (!original_security_ops.bprm_check_security);
527+ return original_security_ops.bprm_check_security(bprm);
528+}
529+
530+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
531+
532+/**
533+ * ccs_open - Check permission for open().
534+ *
535+ * @f: Pointer to "struct file".
536+ *
537+ * Returns 0 on success, negative value otherwise.
538+ */
539+static int ccs_open(struct file *f)
540+{
541+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
542+ return ccs_open_permission(f);
543+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 6
544+ return ccs_open_permission(f->f_path.dentry, f->f_path.mnt,
545+ f->f_flags);
546+#else
547+ return ccs_open_permission(f->f_path.dentry, f->f_path.mnt,
548+ f->f_flags + 1);
549+#endif
550+}
551+
552+#endif
553+
554+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
555+
556+/**
557+ * ccs_dentry_open - Check permission for open().
558+ *
559+ * @f: Pointer to "struct file".
560+ * @cred: Pointer to "struct cred".
561+ *
562+ * Returns 0 on success, negative value otherwise.
563+ */
564+static int ccs_dentry_open(struct file *f, const struct cred *cred)
565+{
566+ int rc = ccs_open(f);
567+ if (rc)
568+ return rc;
569+ while (!original_security_ops.dentry_open);
570+ return original_security_ops.dentry_open(f, cred);
571+}
572+
573+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
574+
575+/**
576+ * ccs_dentry_open - Check permission for open().
577+ *
578+ * @f: Pointer to "struct file".
579+ *
580+ * Returns 0 on success, negative value otherwise.
581+ */
582+static int ccs_dentry_open(struct file *f)
583+{
584+ int rc = ccs_open(f);
585+ if (rc)
586+ return rc;
587+ while (!original_security_ops.dentry_open);
588+ return original_security_ops.dentry_open(f);
589+}
590+
591+#else
592+
593+/**
594+ * ccs_open - Check permission for open().
595+ *
596+ * @inode: Pointer to "struct inode".
597+ * @mask: Open mode.
598+ * @nd: Pointer to "struct nameidata".
599+ *
600+ * Returns 0 on success, negative value otherwise.
601+ */
602+static int ccs_open(struct inode *inode, int mask, struct nameidata *nd)
603+{
604+ int flags;
605+ if (!nd || !nd->dentry)
606+ return 0;
607+ /* open_exec() passes MAY_EXEC . */
608+ if (mask == MAY_EXEC && inode && S_ISREG(inode->i_mode) &&
609+ (ccs_current_flags() & CCS_TASK_IS_IN_EXECVE))
610+ mask = MAY_READ;
611+ /*
612+ * This flags value is passed to ACC_MODE().
613+ * ccs_open_permission() for older versions uses old ACC_MODE().
614+ */
615+ switch (mask & (MAY_READ | MAY_WRITE)) {
616+ case MAY_READ:
617+ flags = 01;
618+ break;
619+ case MAY_WRITE:
620+ flags = 02;
621+ break;
622+ case MAY_READ | MAY_WRITE:
623+ flags = 03;
624+ break;
625+ default:
626+ return 0;
627+ }
628+ return ccs_open_permission(nd->dentry, nd->mnt, flags);
629+}
630+
631+/**
632+ * ccs_inode_permission - Check permission for open().
633+ *
634+ * @inode: Pointer to "struct inode".
635+ * @mask: Open mode.
636+ * @nd: Pointer to "struct nameidata".
637+ *
638+ * Returns 0 on success, negative value otherwise.
639+ *
640+ * Note that this hook is called from permission(), and may not be called for
641+ * open(). Maybe it is better to use security_file_permission().
642+ */
643+static int ccs_inode_permission(struct inode *inode, int mask,
644+ struct nameidata *nd)
645+{
646+ int rc = ccs_open(inode, mask, nd);
647+ if (rc)
648+ return rc;
649+ while (!original_security_ops.inode_permission);
650+ return original_security_ops.inode_permission(inode, mask, nd);
651+}
652+
653+#endif
654+
655+#if defined(CONFIG_SECURITY_PATH)
656+
657+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
658+
659+/**
660+ * ccs_path_chown - Check permission for chown()/chgrp().
661+ *
662+ * @path: Pointer to "struct path".
663+ * @user: User ID.
664+ * @group: Group ID.
665+ *
666+ * Returns 0 on success, negative value otherwise.
667+ */
668+static int ccs_path_chown(struct path *path, uid_t user, gid_t group)
669+{
670+ int rc = ccs_chown_permission(path->dentry, path->mnt, user, group);
671+ if (rc)
672+ return rc;
673+ while (!original_security_ops.path_chown);
674+ return original_security_ops.path_chown(path, user, group);
675+}
676+
677+/**
678+ * ccs_path_chmod - Check permission for chmod().
679+ *
680+ * @dentry: Pointer to "struct dentry".
681+ * @vfsmnt: Pointer to "struct vfsmount".
682+ * @mode: Mode.
683+ *
684+ * Returns 0 on success, negative value otherwise.
685+ */
686+static int ccs_path_chmod(struct dentry *dentry, struct vfsmount *vfsmnt,
687+ mode_t mode)
688+{
689+ int rc = ccs_chmod_permission(dentry, vfsmnt, mode);
690+ if (rc)
691+ return rc;
692+ while (!original_security_ops.path_chmod);
693+ return original_security_ops.path_chmod(dentry, vfsmnt, mode);
694+}
695+
696+/**
697+ * ccs_path_chroot - Check permission for chroot().
698+ *
699+ * @path: Pointer to "struct path".
700+ *
701+ * Returns 0 on success, negative value otherwise.
702+ */
703+static int ccs_path_chroot(struct path *path)
704+{
705+ int rc = ccs_chroot_permission(path);
706+ if (rc)
707+ return rc;
708+ while (!original_security_ops.path_chroot);
709+ return original_security_ops.path_chroot(path);
710+}
711+
712+#endif
713+
714+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
715+
716+/**
717+ * ccs_path_truncate - Check permission for truncate().
718+ *
719+ * @path: Pointer to "struct path".
720+ *
721+ * Returns 0 on success, negative value otherwise.
722+ */
723+static int ccs_path_truncate(struct path *path)
724+{
725+ int rc = ccs_truncate_permission(path->dentry, path->mnt);
726+ if (rc)
727+ return rc;
728+ while (!original_security_ops.path_truncate);
729+ return original_security_ops.path_truncate(path);
730+}
731+
732+#else
733+
734+/**
735+ * ccs_path_truncate - Check permission for truncate().
736+ *
737+ * @path: Pointer to "struct path".
738+ * @length: New length.
739+ * @time_attrs: New time attributes.
740+ *
741+ * Returns 0 on success, negative value otherwise.
742+ */
743+static int ccs_path_truncate(struct path *path, loff_t length,
744+ unsigned int time_attrs)
745+{
746+ int rc = ccs_truncate_permission(path->dentry, path->mnt);
747+ if (rc)
748+ return rc;
749+ while (!original_security_ops.path_truncate);
750+ return original_security_ops.path_truncate(path, length, time_attrs);
751+}
752+
753+#endif
754+
755+#endif
756+
757+#ifdef CCS_INODE_HOOK_HAS_MNT
758+
759+/**
760+ * ccs_inode_setattr - Check permission for chown()/chgrp()/chmod()/truncate().
761+ *
762+ * @dentry: Pointer to "struct dentry".
763+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
764+ * @attr: Pointer to "struct iattr".
765+ *
766+ * Returns 0 on success, negative value otherwise.
767+ */
768+static int ccs_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
769+ struct iattr *attr)
770+{
771+ int rc = 0;
772+#if !defined(CONFIG_SECURITY_PATH) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
773+ if (attr->ia_valid & ATTR_UID)
774+ rc = ccs_chown_permission(dentry, mnt, attr->ia_uid, -1);
775+ if (!rc && (attr->ia_valid & ATTR_GID))
776+ rc = ccs_chown_permission(dentry, mnt, -1, attr->ia_gid);
777+ if (!rc && (attr->ia_valid & ATTR_MODE))
778+ rc = ccs_chmod_permission(dentry, mnt, attr->ia_mode);
779+#endif
780+#if !defined(CONFIG_SECURITY_PATH)
781+ if (!rc && (attr->ia_valid & ATTR_SIZE))
782+ rc = ccs_truncate_permission(dentry, mnt);
783+#endif
784+ if (rc)
785+ return rc;
786+ while (!original_security_ops.inode_setattr);
787+ return original_security_ops.inode_setattr(dentry, mnt, attr);
788+}
789+
790+#else
791+
792+/**
793+ * ccs_inode_setattr - Check permission for chown()/chgrp()/chmod()/truncate().
794+ *
795+ * @dentry: Pointer to "struct dentry".
796+ * @attr: Pointer to "struct iattr".
797+ *
798+ * Returns 0 on success, negative value otherwise.
799+ */
800+static int ccs_inode_setattr(struct dentry *dentry, struct iattr *attr)
801+{
802+ int rc = 0;
803+#if !defined(CONFIG_SECURITY_PATH) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
804+ if (attr->ia_valid & ATTR_UID)
805+ rc = ccs_chown_permission(dentry, NULL, attr->ia_uid, -1);
806+ if (!rc && (attr->ia_valid & ATTR_GID))
807+ rc = ccs_chown_permission(dentry, NULL, -1, attr->ia_gid);
808+ if (!rc && (attr->ia_valid & ATTR_MODE))
809+ rc = ccs_chmod_permission(dentry, NULL, attr->ia_mode);
810+#endif
811+#if !defined(CONFIG_SECURITY_PATH)
812+ if (!rc && (attr->ia_valid & ATTR_SIZE))
813+ rc = ccs_truncate_permission(dentry, NULL);
814+#endif
815+ if (rc)
816+ return rc;
817+ while (!original_security_ops.inode_setattr);
818+ return original_security_ops.inode_setattr(dentry, attr);
819+}
820+
821+#endif
822+
823+/**
824+ * ccs_inode_getattr - Check permission for stat().
825+ *
826+ * @mnt: Pointer to "struct vfsmount".
827+ * @dentry: Pointer to "struct dentry".
828+ *
829+ * Returns 0 on success, negative value otherwise.
830+ */
831+static int ccs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
832+{
833+ int rc = ccs_getattr_permission(mnt, dentry);
834+ if (rc)
835+ return rc;
836+ while (!original_security_ops.inode_getattr);
837+ return original_security_ops.inode_getattr(mnt, dentry);
838+}
839+
840+#if defined(CONFIG_SECURITY_PATH)
841+
842+/**
843+ * ccs_path_mknod - Check permission for mknod().
844+ *
845+ * @dir: Pointer to "struct path".
846+ * @dentry: Pointer to "struct dentry".
847+ * @mode: Create mode.
848+ * @dev: Device major/minor number.
849+ *
850+ * Returns 0 on success, negative value otherwise.
851+ */
852+static int ccs_path_mknod(struct path *dir, struct dentry *dentry, int mode,
853+ unsigned int dev)
854+{
855+ int rc = ccs_mknod_permission(dir->dentry->d_inode, dentry, dir->mnt,
856+ mode, dev);
857+ if (rc)
858+ return rc;
859+ while (!original_security_ops.path_mknod);
860+ return original_security_ops.path_mknod(dir, dentry, mode, dev);
861+}
862+
863+/**
864+ * ccs_path_mkdir - Check permission for mkdir().
865+ *
866+ * @dir: Pointer to "struct path".
867+ * @dentry: Pointer to "struct dentry".
868+ * @mode: Create mode.
869+ *
870+ * Returns 0 on success, negative value otherwise.
871+ */
872+static int ccs_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
873+{
874+ int rc = ccs_mkdir_permission(dir->dentry->d_inode, dentry, dir->mnt,
875+ mode);
876+ if (rc)
877+ return rc;
878+ while (!original_security_ops.path_mkdir);
879+ return original_security_ops.path_mkdir(dir, dentry, mode);
880+}
881+
882+/**
883+ * ccs_path_rmdir - Check permission for rmdir().
884+ *
885+ * @dir: Pointer to "struct path".
886+ * @dentry: Pointer to "struct dentry".
887+ *
888+ * Returns 0 on success, negative value otherwise.
889+ */
890+static int ccs_path_rmdir(struct path *dir, struct dentry *dentry)
891+{
892+ int rc = ccs_rmdir_permission(dir->dentry->d_inode, dentry, dir->mnt);
893+ if (rc)
894+ return rc;
895+ while (!original_security_ops.path_rmdir);
896+ return original_security_ops.path_rmdir(dir, dentry);
897+}
898+
899+/**
900+ * ccs_path_unlink - Check permission for unlink().
901+ *
902+ * @dir: Pointer to "struct path".
903+ * @dentry: Pointer to "struct dentry".
904+ *
905+ * Returns 0 on success, negative value otherwise.
906+ */
907+static int ccs_path_unlink(struct path *dir, struct dentry *dentry)
908+{
909+ int rc = ccs_unlink_permission(dir->dentry->d_inode, dentry, dir->mnt);
910+ if (rc)
911+ return rc;
912+ while (!original_security_ops.path_unlink);
913+ return original_security_ops.path_unlink(dir, dentry);
914+}
915+
916+/**
917+ * ccs_path_symlink - Check permission for symlink().
918+ *
919+ * @dir: Pointer to "struct path".
920+ * @dentry: Pointer to "struct dentry".
921+ * @old_name: Content of symbolic link.
922+ *
923+ * Returns 0 on success, negative value otherwise.
924+ */
925+static int ccs_path_symlink(struct path *dir, struct dentry *dentry,
926+ const char *old_name)
927+{
928+ int rc = ccs_symlink_permission(dir->dentry->d_inode, dentry, dir->mnt,
929+ old_name);
930+ if (rc)
931+ return rc;
932+ while (!original_security_ops.path_symlink);
933+ return original_security_ops.path_symlink(dir, dentry, old_name);
934+}
935+
936+/**
937+ * ccs_path_rename - Check permission for rename().
938+ *
939+ * @old_dir: Pointer to "struct path".
940+ * @old_dentry: Pointer to "struct dentry".
941+ * @new_dir: Pointer to "struct path".
942+ * @new_dentry: Pointer to "struct dentry".
943+ *
944+ * Returns 0 on success, negative value otherwise.
945+ */
946+static int ccs_path_rename(struct path *old_dir, struct dentry *old_dentry,
947+ struct path *new_dir, struct dentry *new_dentry)
948+{
949+ int rc = ccs_rename_permission(old_dir->dentry->d_inode, old_dentry,
950+ new_dir->dentry->d_inode, new_dentry,
951+ old_dir->mnt);
952+ if (rc)
953+ return rc;
954+ while (!original_security_ops.path_rename);
955+ return original_security_ops.path_rename(old_dir, old_dentry, new_dir,
956+ new_dentry);
957+}
958+
959+/**
960+ * ccs_path_link - Check permission for link().
961+ *
962+ * @old_dentry: Pointer to "struct dentry".
963+ * @new_dir: Pointer to "struct path".
964+ * @new_dentry: Pointer to "struct dentry".
965+ *
966+ * Returns 0 on success, negative value otherwise.
967+ */
968+static int ccs_path_link(struct dentry *old_dentry, struct path *new_dir,
969+ struct dentry *new_dentry)
970+{
971+ int rc = ccs_link_permission(old_dentry, new_dir->dentry->d_inode,
972+ new_dentry, new_dir->mnt);
973+ if (rc)
974+ return rc;
975+ while (!original_security_ops.path_link);
976+ return original_security_ops.path_link(old_dentry, new_dir,
977+ new_dentry);
978+}
979+
980+#elif defined(CCS_INODE_HOOK_HAS_MNT)
981+
982+/**
983+ * ccs_inode_mknod - Check permission for mknod().
984+ *
985+ * @dir: Pointer to "struct inode".
986+ * @dentry: Pointer to "struct dentry".
987+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
988+ * @mode: Create mode.
989+ * @dev: Device major/minor number.
990+ *
991+ * Returns 0 on success, negative value otherwise.
992+ */
993+static int ccs_inode_mknod(struct inode *dir, struct dentry *dentry,
994+ struct vfsmount *mnt, int mode, dev_t dev)
995+{
996+ int rc = ccs_mknod_permission(dir, dentry, mnt, mode, dev);
997+ if (rc)
998+ return rc;
999+ while (!original_security_ops.inode_mknod);
1000+ return original_security_ops.inode_mknod(dir, dentry, mnt, mode, dev);
1001+}
1002+
1003+/**
1004+ * ccs_inode_mkdir - Check permission for mkdir().
1005+ *
1006+ * @dir: Pointer to "struct inode".
1007+ * @dentry: Pointer to "struct dentry".
1008+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1009+ * @mode: Create mode.
1010+ *
1011+ * Returns 0 on success, negative value otherwise.
1012+ */
1013+static int ccs_inode_mkdir(struct inode *dir, struct dentry *dentry,
1014+ struct vfsmount *mnt, int mode)
1015+{
1016+ int rc = ccs_mkdir_permission(dir, dentry, mnt, mode);
1017+ if (rc)
1018+ return rc;
1019+ while (!original_security_ops.inode_mkdir);
1020+ return original_security_ops.inode_mkdir(dir, dentry, mnt, mode);
1021+}
1022+
1023+/**
1024+ * ccs_inode_rmdir - Check permission for rmdir().
1025+ *
1026+ * @dir: Pointer to "struct inode".
1027+ * @dentry: Pointer to "struct dentry".
1028+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1029+ *
1030+ * Returns 0 on success, negative value otherwise.
1031+ */
1032+static int ccs_inode_rmdir(struct inode *dir, struct dentry *dentry,
1033+ struct vfsmount *mnt)
1034+{
1035+ int rc = ccs_rmdir_permission(dir, dentry, mnt);
1036+ if (rc)
1037+ return rc;
1038+ while (!original_security_ops.inode_rmdir);
1039+ return original_security_ops.inode_rmdir(dir, dentry, mnt);
1040+}
1041+
1042+/**
1043+ * ccs_inode_unlink - Check permission for unlink().
1044+ *
1045+ * @dir: Pointer to "struct inode".
1046+ * @dentry: Pointer to "struct dentry".
1047+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1048+ *
1049+ * Returns 0 on success, negative value otherwise.
1050+ */
1051+static int ccs_inode_unlink(struct inode *dir, struct dentry *dentry,
1052+ struct vfsmount *mnt)
1053+{
1054+ int rc = ccs_unlink_permission(dir, dentry, mnt);
1055+ if (rc)
1056+ return rc;
1057+ while (!original_security_ops.inode_unlink);
1058+ return original_security_ops.inode_unlink(dir, dentry, mnt);
1059+}
1060+
1061+/**
1062+ * ccs_inode_symlink - Check permission for symlink().
1063+ *
1064+ * @dir: Pointer to "struct inode".
1065+ * @dentry: Pointer to "struct dentry".
1066+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1067+ * @old_name: Content of symbolic link.
1068+ *
1069+ * Returns 0 on success, negative value otherwise.
1070+ */
1071+static int ccs_inode_symlink(struct inode *dir, struct dentry *dentry,
1072+ struct vfsmount *mnt, const char *old_name)
1073+{
1074+ int rc = ccs_symlink_permission(dir, dentry, mnt, old_name);
1075+ if (rc)
1076+ return rc;
1077+ while (!original_security_ops.inode_symlink);
1078+ return original_security_ops.inode_symlink(dir, dentry, mnt, old_name);
1079+}
1080+
1081+/**
1082+ * ccs_inode_rename - Check permission for rename().
1083+ *
1084+ * @old_dir: Pointer to "struct inode".
1085+ * @old_dentry: Pointer to "struct dentry".
1086+ * @old_mnt: Pointer to "struct vfsmount". Maybe NULL.
1087+ * @new_dir: Pointer to "struct inode".
1088+ * @new_dentry: Pointer to "struct dentry".
1089+ * @new_mnt: Pointer to "struct vfsmount". Maybe NULL.
1090+ *
1091+ * Returns 0 on success, negative value otherwise.
1092+ */
1093+static int ccs_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
1094+ struct vfsmount *old_mnt, struct inode *new_dir,
1095+ struct dentry *new_dentry,
1096+ struct vfsmount *new_mnt)
1097+{
1098+ int rc = ccs_rename_permission(old_dir, old_dentry, new_dir,
1099+ new_dentry, new_mnt);
1100+ if (rc)
1101+ return rc;
1102+ while (!original_security_ops.inode_rename);
1103+ return original_security_ops.inode_rename(old_dir, old_dentry, old_mnt,
1104+ new_dir, new_dentry,
1105+ new_mnt);
1106+}
1107+
1108+/**
1109+ * ccs_inode_link - Check permission for link().
1110+ *
1111+ * @old_dentry: Pointer to "struct dentry".
1112+ * @old_mnt: Pointer to "struct vfsmount". Maybe NULL.
1113+ * @dir: Pointer to "struct inode".
1114+ * @new_dentry: Pointer to "struct dentry".
1115+ * @new_mnt: Pointer to "struct vfsmount". Maybe NULL.
1116+ *
1117+ * Returns 0 on success, negative value otherwise.
1118+ */
1119+static int ccs_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
1120+ struct inode *dir, struct dentry *new_dentry,
1121+ struct vfsmount *new_mnt)
1122+{
1123+ int rc = ccs_link_permission(old_dentry, dir, new_dentry, new_mnt);
1124+ if (rc)
1125+ return rc;
1126+ while (!original_security_ops.inode_link);
1127+ return original_security_ops.inode_link(old_dentry, old_mnt, dir,
1128+ new_dentry, new_mnt);
1129+}
1130+
1131+/**
1132+ * ccs_inode_create - Check permission for creat().
1133+ *
1134+ * @dir: Pointer to "struct inode".
1135+ * @dentry: Pointer to "struct dentry".
1136+ * @mnt: Pointer to "struct vfsmount". Maybe NULL.
1137+ * @mode: Create mode.
1138+ *
1139+ * Returns 0 on success, negative value otherwise.
1140+ */
1141+static int ccs_inode_create(struct inode *dir, struct dentry *dentry,
1142+ struct vfsmount *mnt, int mode)
1143+{
1144+ int rc = ccs_mknod_permission(dir, dentry, mnt, mode, 0);
1145+ if (rc)
1146+ return rc;
1147+ while (!original_security_ops.inode_create);
1148+ return original_security_ops.inode_create(dir, dentry, mnt, mode);
1149+}
1150+
1151+#else
1152+
1153+/**
1154+ * ccs_inode_mknod - Check permission for mknod().
1155+ *
1156+ * @dir: Pointer to "struct inode".
1157+ * @dentry: Pointer to "struct dentry".
1158+ * @mode: Create mode.
1159+ * @dev: Device major/minor number.
1160+ *
1161+ * Returns 0 on success, negative value otherwise.
1162+ */
1163+static int ccs_inode_mknod(struct inode *dir, struct dentry *dentry, int mode,
1164+ dev_t dev)
1165+{
1166+ int rc = ccs_mknod_permission(dir, dentry, NULL, mode, dev);
1167+ if (rc)
1168+ return rc;
1169+ while (!original_security_ops.inode_mknod);
1170+ return original_security_ops.inode_mknod(dir, dentry, mode, dev);
1171+}
1172+
1173+/**
1174+ * ccs_inode_mkdir - Check permission for mkdir().
1175+ *
1176+ * @dir: Pointer to "struct inode".
1177+ * @dentry: Pointer to "struct dentry".
1178+ * @mode: Create mode.
1179+ *
1180+ * Returns 0 on success, negative value otherwise.
1181+ */
1182+static int ccs_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1183+{
1184+ int rc = ccs_mkdir_permission(dir, dentry, NULL, mode);
1185+ if (rc)
1186+ return rc;
1187+ while (!original_security_ops.inode_mkdir);
1188+ return original_security_ops.inode_mkdir(dir, dentry, mode);
1189+}
1190+
1191+/**
1192+ * ccs_inode_rmdir - Check permission for rmdir().
1193+ *
1194+ * @dir: Pointer to "struct inode".
1195+ * @dentry: Pointer to "struct dentry".
1196+ *
1197+ * Returns 0 on success, negative value otherwise.
1198+ */
1199+static int ccs_inode_rmdir(struct inode *dir, struct dentry *dentry)
1200+{
1201+ int rc = ccs_rmdir_permission(dir, dentry, NULL);
1202+ if (rc)
1203+ return rc;
1204+ while (!original_security_ops.inode_rmdir);
1205+ return original_security_ops.inode_rmdir(dir, dentry);
1206+}
1207+
1208+/**
1209+ * ccs_inode_unlink - Check permission for unlink().
1210+ *
1211+ * @dir: Pointer to "struct inode".
1212+ * @dentry: Pointer to "struct dentry".
1213+ *
1214+ * Returns 0 on success, negative value otherwise.
1215+ */
1216+static int ccs_inode_unlink(struct inode *dir, struct dentry *dentry)
1217+{
1218+ int rc = ccs_unlink_permission(dir, dentry, NULL);
1219+ if (rc)
1220+ return rc;
1221+ while (!original_security_ops.inode_unlink);
1222+ return original_security_ops.inode_unlink(dir, dentry);
1223+}
1224+
1225+/**
1226+ * ccs_inode_symlink - Check permission for symlink().
1227+ *
1228+ * @dir: Pointer to "struct inode".
1229+ * @dentry: Pointer to "struct dentry".
1230+ * @old_name: Content of symbolic link.
1231+ *
1232+ * Returns 0 on success, negative value otherwise.
1233+ */
1234+static int ccs_inode_symlink(struct inode *dir, struct dentry *dentry,
1235+ const char *old_name)
1236+{
1237+ int rc = ccs_symlink_permission(dir, dentry, NULL, old_name);
1238+ if (rc)
1239+ return rc;
1240+ while (!original_security_ops.inode_symlink);
1241+ return original_security_ops.inode_symlink(dir, dentry, old_name);
1242+}
1243+
1244+/**
1245+ * ccs_inode_rename - Check permission for rename().
1246+ *
1247+ * @old_dir: Pointer to "struct inode".
1248+ * @old_dentry: Pointer to "struct dentry".
1249+ * @new_dir: Pointer to "struct inode".
1250+ * @new_dentry: Pointer to "struct dentry".
1251+ *
1252+ * Returns 0 on success, negative value otherwise.
1253+ */
1254+static int ccs_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
1255+ struct inode *new_dir, struct dentry *new_dentry)
1256+{
1257+ int rc = ccs_rename_permission(old_dir, old_dentry, new_dir,
1258+ new_dentry, NULL);
1259+ if (rc)
1260+ return rc;
1261+ while (!original_security_ops.inode_rename);
1262+ return original_security_ops.inode_rename(old_dir, old_dentry, new_dir,
1263+ new_dentry);
1264+}
1265+
1266+/**
1267+ * ccs_inode_link - Check permission for link().
1268+ *
1269+ * @old_dentry: Pointer to "struct dentry".
1270+ * @dir: Pointer to "struct inode".
1271+ * @new_dentry: Pointer to "struct dentry".
1272+ *
1273+ * Returns 0 on success, negative value otherwise.
1274+ */
1275+static int ccs_inode_link(struct dentry *old_dentry, struct inode *dir,
1276+ struct dentry *new_dentry)
1277+{
1278+ int rc = ccs_link_permission(old_dentry, dir, new_dentry, NULL);
1279+ if (rc)
1280+ return rc;
1281+ while (!original_security_ops.inode_link);
1282+ return original_security_ops.inode_link(old_dentry, dir, new_dentry);
1283+}
1284+
1285+/**
1286+ * ccs_inode_create - Check permission for creat().
1287+ *
1288+ * @dir: Pointer to "struct inode".
1289+ * @dentry: Pointer to "struct dentry".
1290+ * @mode: Create mode.
1291+ *
1292+ * Returns 0 on success, negative value otherwise.
1293+ */
1294+static int ccs_inode_create(struct inode *dir, struct dentry *dentry,
1295+ int mode)
1296+{
1297+ int rc = ccs_mknod_permission(dir, dentry, NULL, mode, 0);
1298+ if (rc)
1299+ return rc;
1300+ while (!original_security_ops.inode_create);
1301+ return original_security_ops.inode_create(dir, dentry, mode);
1302+}
1303+
1304+#endif
1305+
1306+#ifdef CONFIG_SECURITY_NETWORK
1307+
1308+#include <net/sock.h>
1309+
1310+/* Structure for remembering an accept()ed socket's status. */
1311+struct ccs_socket_tag {
1312+ struct list_head list;
1313+ struct inode *inode;
1314+ int status;
1315+ struct rcu_head rcu;
1316+};
1317+
1318+/*
1319+ * List for managing accept()ed sockets.
1320+ * Since we don't need to keep an accept()ed socket into this list after
1321+ * once the permission was granted, the number of entries in this list is
1322+ * likely small. Therefore, we don't use hash tables.
1323+ */
1324+static LIST_HEAD(ccs_accepted_socket_list);
1325+/* Lock for protecting ccs_accepted_socket_list . */
1326+static DEFINE_SPINLOCK(ccs_accepted_socket_list_lock);
1327+
1328+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
1329+
1330+/**
1331+ * ccs_socket_rcu_free - RCU callback for releasing "struct ccs_socket_tag".
1332+ *
1333+ * @rcu: Pointer to "struct rcu_head".
1334+ *
1335+ * Returns nothing.
1336+ */
1337+static void ccs_socket_rcu_free(struct rcu_head *rcu)
1338+{
1339+ struct ccs_socket_tag *ptr = container_of(rcu, typeof(*ptr), rcu);
1340+ kfree(ptr);
1341+}
1342+
1343+#else
1344+
1345+/**
1346+ * ccs_socket_rcu_free - RCU callback for releasing "struct ccs_socket_tag".
1347+ *
1348+ * @arg: Pointer to "void".
1349+ *
1350+ * Returns nothing.
1351+ */
1352+static void ccs_socket_rcu_free(void *arg)
1353+{
1354+ struct ccs_socket_tag *ptr = arg;
1355+ kfree(ptr);
1356+}
1357+
1358+#endif
1359+
1360+/**
1361+ * ccs_update_socket_tag - Update tag associated with accept()ed sockets.
1362+ *
1363+ * @inode: Pointer to "struct inode".
1364+ * @status: New status.
1365+ *
1366+ * Returns nothing.
1367+ *
1368+ * If @status == 0, memory for that socket will be released after RCU grace
1369+ * period.
1370+ */
1371+static void ccs_update_socket_tag(struct inode *inode, int status)
1372+{
1373+ struct ccs_socket_tag *ptr;
1374+ /*
1375+ * Protect whole section because multiple threads may call this
1376+ * function with same "sock" via ccs_validate_socket().
1377+ */
1378+ spin_lock(&ccs_accepted_socket_list_lock);
1379+ rcu_read_lock();
1380+ list_for_each_entry_rcu(ptr, &ccs_accepted_socket_list, list) {
1381+ if (ptr->inode != inode)
1382+ continue;
1383+ ptr->status = status;
1384+ if (status)
1385+ break;
1386+ list_del_rcu(&ptr->list);
1387+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
1388+ call_rcu(&ptr->rcu, ccs_socket_rcu_free);
1389+#else
1390+ call_rcu(&ptr->rcu, ccs_socket_rcu_free, ptr);
1391+#endif
1392+ break;
1393+ }
1394+ rcu_read_unlock();
1395+ spin_unlock(&ccs_accepted_socket_list_lock);
1396+}
1397+
1398+/**
1399+ * ccs_validate_socket - Check post accept() permission if needed.
1400+ *
1401+ * @sock: Pointer to "struct socket".
1402+ *
1403+ * Returns 0 on success, negative value otherwise.
1404+ */
1405+static int ccs_validate_socket(struct socket *sock)
1406+{
1407+ struct inode *inode = SOCK_INODE(sock);
1408+ struct ccs_socket_tag *ptr;
1409+ int ret = 0;
1410+ rcu_read_lock();
1411+ list_for_each_entry_rcu(ptr, &ccs_accepted_socket_list, list) {
1412+ if (ptr->inode != inode)
1413+ continue;
1414+ ret = ptr->status;
1415+ break;
1416+ }
1417+ rcu_read_unlock();
1418+ if (ret <= 0)
1419+ /*
1420+ * This socket is not an accept()ed socket or this socket is
1421+ * an accept()ed socket and post accept() permission is done.
1422+ */
1423+ return ret;
1424+ /*
1425+ * Check post accept() permission now.
1426+ *
1427+ * Strictly speaking, we need to pass both listen()ing socket and
1428+ * accept()ed socket to __ccs_socket_post_accept_permission().
1429+ * But since socket's family and type are same for both sockets,
1430+ * passing the accept()ed socket in place for the listen()ing socket
1431+ * will work.
1432+ */
1433+ ret = ccs_socket_post_accept_permission(sock, sock);
1434+ /*
1435+ * If permission was granted, we forget that this is an accept()ed
1436+ * socket. Otherwise, we remember that this socket needs to return
1437+ * error for subsequent socketcalls.
1438+ */
1439+ ccs_update_socket_tag(inode, ret);
1440+ return ret;
1441+}
1442+
1443+/**
1444+ * ccs_socket_accept - Check permission for accept().
1445+ *
1446+ * @sock: Pointer to "struct socket".
1447+ * @newsock: Pointer to "struct socket".
1448+ *
1449+ * Returns 0 on success, negative value otherwise.
1450+ *
1451+ * This hook is used for setting up environment for doing post accept()
1452+ * permission check. If dereferencing sock->ops->something() were ordered by
1453+ * rcu_dereference(), we could replace sock->ops with "a copy of original
1454+ * sock->ops with modified sock->ops->accept()" using rcu_assign_pointer()
1455+ * in order to do post accept() permission check before returning to userspace.
1456+ * If we make the copy in security_socket_post_create(), it would be possible
1457+ * to safely replace sock->ops here, but we don't do so because we don't want
1458+ * to allocate memory for sockets which do not call sock->ops->accept().
1459+ * Therefore, we do post accept() permission check upon next socket syscalls
1460+ * rather than between sock->ops->accept() and returning to userspace.
1461+ * This means that if a socket was close()d before calling some socket
1462+ * syscalls, post accept() permission check will not be done.
1463+ */
1464+static int ccs_socket_accept(struct socket *sock, struct socket *newsock)
1465+{
1466+ struct ccs_socket_tag *ptr;
1467+ int rc = ccs_validate_socket(sock);
1468+ if (rc < 0)
1469+ return rc;
1470+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
1471+ if (!ptr)
1472+ return -ENOMEM;
1473+ while (!original_security_ops.socket_accept);
1474+ rc = original_security_ops.socket_accept(sock, newsock);
1475+ if (rc) {
1476+ kfree(ptr);
1477+ return rc;
1478+ }
1479+ /*
1480+ * Subsequent LSM hooks will receive "newsock". Therefore, I mark
1481+ * "newsock" as "an accept()ed socket but post accept() permission
1482+ * check is not done yet" by allocating memory using inode of the
1483+ * "newsock" as a search key.
1484+ */
1485+ ptr->inode = SOCK_INODE(newsock);
1486+ ptr->status = 1; /* Check post accept() permission later. */
1487+ spin_lock(&ccs_accepted_socket_list_lock);
1488+ list_add_tail_rcu(&ptr->list, &ccs_accepted_socket_list);
1489+ spin_unlock(&ccs_accepted_socket_list_lock);
1490+ return 0;
1491+}
1492+
1493+/**
1494+ * ccs_socket_listen - Check permission for listen().
1495+ *
1496+ * @sock: Pointer to "struct socket".
1497+ * @backlog: Backlog parameter.
1498+ *
1499+ * Returns 0 on success, negative value otherwise.
1500+ */
1501+static int ccs_socket_listen(struct socket *sock, int backlog)
1502+{
1503+ int rc = ccs_validate_socket(sock);
1504+ if (rc < 0)
1505+ return rc;
1506+ rc = ccs_socket_listen_permission(sock);
1507+ if (rc)
1508+ return rc;
1509+ while (!original_security_ops.socket_listen);
1510+ return original_security_ops.socket_listen(sock, backlog);
1511+}
1512+
1513+/**
1514+ * ccs_socket_connect - Check permission for connect().
1515+ *
1516+ * @sock: Pointer to "struct socket".
1517+ * @addr: Pointer to "struct sockaddr".
1518+ * @addr_len: Size of @addr.
1519+ *
1520+ * Returns 0 on success, negative value otherwise.
1521+ */
1522+static int ccs_socket_connect(struct socket *sock, struct sockaddr *addr,
1523+ int addr_len)
1524+{
1525+ int rc = ccs_validate_socket(sock);
1526+ if (rc < 0)
1527+ return rc;
1528+ rc = ccs_socket_connect_permission(sock, addr, addr_len);
1529+ if (rc)
1530+ return rc;
1531+ while (!original_security_ops.socket_connect);
1532+ return original_security_ops.socket_connect(sock, addr, addr_len);
1533+}
1534+
1535+/**
1536+ * ccs_socket_bind - Check permission for bind().
1537+ *
1538+ * @sock: Pointer to "struct socket".
1539+ * @addr: Pointer to "struct sockaddr".
1540+ * @addr_len: Size of @addr.
1541+ *
1542+ * Returns 0 on success, negative value otherwise.
1543+ */
1544+static int ccs_socket_bind(struct socket *sock, struct sockaddr *addr,
1545+ int addr_len)
1546+{
1547+ int rc = ccs_validate_socket(sock);
1548+ if (rc < 0)
1549+ return rc;
1550+ rc = ccs_socket_bind_permission(sock, addr, addr_len);
1551+ if (rc)
1552+ return rc;
1553+ while (!original_security_ops.socket_bind);
1554+ return original_security_ops.socket_bind(sock, addr, addr_len);
1555+}
1556+
1557+/**
1558+ * ccs_socket_sendmsg - Check permission for sendmsg().
1559+ *
1560+ * @sock: Pointer to "struct socket".
1561+ * @msg: Pointer to "struct msghdr".
1562+ * @size: Size of message.
1563+ *
1564+ * Returns 0 on success, negative value otherwise.
1565+ */
1566+static int ccs_socket_sendmsg(struct socket *sock, struct msghdr *msg,
1567+ int size)
1568+{
1569+ int rc = ccs_validate_socket(sock);
1570+ if (rc < 0)
1571+ return rc;
1572+ rc = ccs_socket_sendmsg_permission(sock, msg, size);
1573+ if (rc)
1574+ return rc;
1575+ while (!original_security_ops.socket_sendmsg);
1576+ return original_security_ops.socket_sendmsg(sock, msg, size);
1577+}
1578+
1579+/**
1580+ * ccs_socket_recvmsg - Check permission for recvmsg().
1581+ *
1582+ * @sock: Pointer to "struct socket".
1583+ * @msg: Pointer to "struct msghdr".
1584+ * @size: Size of message.
1585+ * @flags: Flags.
1586+ *
1587+ * Returns 0 on success, negative value otherwise.
1588+ */
1589+static int ccs_socket_recvmsg(struct socket *sock, struct msghdr *msg,
1590+ int size, int flags)
1591+{
1592+ int rc = ccs_validate_socket(sock);
1593+ if (rc < 0)
1594+ return rc;
1595+ while (!original_security_ops.socket_recvmsg);
1596+ return original_security_ops.socket_recvmsg(sock, msg, size, flags);
1597+}
1598+
1599+/**
1600+ * ccs_socket_getsockname - Check permission for getsockname().
1601+ *
1602+ * @sock: Pointer to "struct socket".
1603+ *
1604+ * Returns 0 on success, negative value otherwise.
1605+ */
1606+static int ccs_socket_getsockname(struct socket *sock)
1607+{
1608+ int rc = ccs_validate_socket(sock);
1609+ if (rc < 0)
1610+ return rc;
1611+ while (!original_security_ops.socket_getsockname);
1612+ return original_security_ops.socket_getsockname(sock);
1613+}
1614+
1615+/**
1616+ * ccs_socket_getpeername - Check permission for getpeername().
1617+ *
1618+ * @sock: Pointer to "struct socket".
1619+ *
1620+ * Returns 0 on success, negative value otherwise.
1621+ */
1622+static int ccs_socket_getpeername(struct socket *sock)
1623+{
1624+ int rc = ccs_validate_socket(sock);
1625+ if (rc < 0)
1626+ return rc;
1627+ while (!original_security_ops.socket_getpeername);
1628+ return original_security_ops.socket_getpeername(sock);
1629+}
1630+
1631+/**
1632+ * ccs_socket_getsockopt - Check permission for getsockopt().
1633+ *
1634+ * @sock: Pointer to "struct socket".
1635+ * @level: Level.
1636+ * @optname: Option's name,
1637+ *
1638+ * Returns 0 on success, negative value otherwise.
1639+ */
1640+static int ccs_socket_getsockopt(struct socket *sock, int level, int optname)
1641+{
1642+ int rc = ccs_validate_socket(sock);
1643+ if (rc < 0)
1644+ return rc;
1645+ while (!original_security_ops.socket_getsockopt);
1646+ return original_security_ops.socket_getsockopt(sock, level, optname);
1647+}
1648+
1649+/**
1650+ * ccs_socket_setsockopt - Check permission for setsockopt().
1651+ *
1652+ * @sock: Pointer to "struct socket".
1653+ * @level: Level.
1654+ * @optname: Option's name,
1655+ *
1656+ * Returns 0 on success, negative value otherwise.
1657+ */
1658+static int ccs_socket_setsockopt(struct socket *sock, int level, int optname)
1659+{
1660+ int rc = ccs_validate_socket(sock);
1661+ if (rc < 0)
1662+ return rc;
1663+ while (!original_security_ops.socket_setsockopt);
1664+ return original_security_ops.socket_setsockopt(sock, level, optname);
1665+}
1666+
1667+/**
1668+ * ccs_socket_shutdown - Check permission for shutdown().
1669+ *
1670+ * @sock: Pointer to "struct socket".
1671+ * @how: Shutdown mode.
1672+ *
1673+ * Returns 0 on success, negative value otherwise.
1674+ */
1675+static int ccs_socket_shutdown(struct socket *sock, int how)
1676+{
1677+ int rc = ccs_validate_socket(sock);
1678+ if (rc < 0)
1679+ return rc;
1680+ while (!original_security_ops.socket_shutdown);
1681+ return original_security_ops.socket_shutdown(sock, how);
1682+}
1683+
1684+#define SOCKFS_MAGIC 0x534F434B
1685+
1686+/**
1687+ * ccs_inode_free_security - Release memory associated with an inode.
1688+ *
1689+ * @inode: Pointer to "struct inode".
1690+ *
1691+ * Returns nothing.
1692+ *
1693+ * We use this hook for releasing memory associated with an accept()ed socket.
1694+ */
1695+static void ccs_inode_free_security(struct inode *inode)
1696+{
1697+ while (!original_security_ops.inode_free_security);
1698+ original_security_ops.inode_free_security(inode);
1699+ if (inode->i_sb && inode->i_sb->s_magic == SOCKFS_MAGIC)
1700+ ccs_update_socket_tag(inode, 0);
1701+}
1702+
1703+#endif
1704+
1705+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1706+
1707+/**
1708+ * ccs_sb_pivotroot - Check permission for pivot_root().
1709+ *
1710+ * @old_nd: Pointer to "struct nameidata".
1711+ * @new_nd: Pointer to "struct nameidata".
1712+ *
1713+ * Returns 0 on success, negative value otherwise.
1714+ */
1715+static int ccs_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd)
1716+{
1717+ int rc = ccs_pivot_root_permission(old_nd, new_nd);
1718+ if (rc)
1719+ return rc;
1720+ while (!original_security_ops.sb_pivotroot);
1721+ return original_security_ops.sb_pivotroot(old_nd, new_nd);
1722+}
1723+
1724+/**
1725+ * ccs_sb_mount - Check permission for mount().
1726+ *
1727+ * @dev_name: Name of device file.
1728+ * @nd: Pointer to "struct nameidata".
1729+ * @type: Name of filesystem type. Maybe NULL.
1730+ * @flags: Mount options.
1731+ * @data_page: Optional data. Maybe NULL.
1732+ *
1733+ * Returns 0 on success, negative value otherwise.
1734+ */
1735+static int ccs_sb_mount(char *dev_name, struct nameidata *nd, char *type,
1736+ unsigned long flags, void *data_page)
1737+{
1738+ int rc = ccs_mount_permission(dev_name, nd, type, flags, data_page);
1739+ if (rc)
1740+ return rc;
1741+ while (!original_security_ops.sb_mount);
1742+ return original_security_ops.sb_mount(dev_name, nd, type, flags,
1743+ data_page);
1744+}
1745+
1746+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
1747+
1748+/**
1749+ * ccs_sb_pivotroot - Check permission for pivot_root().
1750+ *
1751+ * @old_nd: Pointer to "struct nameidata".
1752+ * @new_nd: Pointer to "struct nameidata".
1753+ *
1754+ * Returns 0 on success, negative value otherwise.
1755+ */
1756+static int ccs_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd)
1757+{
1758+ int rc = ccs_pivot_root_permission(&old_nd->path, &new_nd->path);
1759+ if (rc)
1760+ return rc;
1761+ while (!original_security_ops.sb_pivotroot);
1762+ return original_security_ops.sb_pivotroot(old_nd, new_nd);
1763+}
1764+
1765+/**
1766+ * ccs_sb_mount - Check permission for mount().
1767+ *
1768+ * @dev_name: Name of device file.
1769+ * @nd: Pointer to "struct nameidata".
1770+ * @type: Name of filesystem type. Maybe NULL.
1771+ * @flags: Mount options.
1772+ * @data_page: Optional data. Maybe NULL.
1773+ *
1774+ * Returns 0 on success, negative value otherwise.
1775+ */
1776+static int ccs_sb_mount(char *dev_name, struct nameidata *nd, char *type,
1777+ unsigned long flags, void *data_page)
1778+{
1779+ int rc = ccs_mount_permission(dev_name, &nd->path, type, flags,
1780+ data_page);
1781+ if (rc)
1782+ return rc;
1783+ while (!original_security_ops.sb_mount);
1784+ return original_security_ops.sb_mount(dev_name, nd, type, flags,
1785+ data_page);
1786+}
1787+
1788+#else
1789+
1790+/**
1791+ * ccs_sb_pivotroot - Check permission for pivot_root().
1792+ *
1793+ * @old_path: Pointer to "struct path".
1794+ * @new_path: Pointer to "struct path".
1795+ *
1796+ * Returns 0 on success, negative value otherwise.
1797+ */
1798+static int ccs_sb_pivotroot(struct path *old_path, struct path *new_path)
1799+{
1800+ int rc = ccs_pivot_root_permission(old_path, new_path);
1801+ if (rc)
1802+ return rc;
1803+ while (!original_security_ops.sb_pivotroot);
1804+ return original_security_ops.sb_pivotroot(old_path, new_path);
1805+}
1806+
1807+/**
1808+ * ccs_sb_mount - Check permission for mount().
1809+ *
1810+ * @dev_name: Name of device file.
1811+ * @path: Pointer to "struct path".
1812+ * @type: Name of filesystem type. Maybe NULL.
1813+ * @flags: Mount options.
1814+ * @data_page: Optional data. Maybe NULL.
1815+ *
1816+ * Returns 0 on success, negative value otherwise.
1817+ */
1818+static int ccs_sb_mount(char *dev_name, struct path *path, char *type,
1819+ unsigned long flags, void *data_page)
1820+{
1821+ int rc = ccs_mount_permission(dev_name, path, type, flags, data_page);
1822+ if (rc)
1823+ return rc;
1824+ while (!original_security_ops.sb_mount);
1825+ return original_security_ops.sb_mount(dev_name, path, type, flags,
1826+ data_page);
1827+}
1828+
1829+#endif
1830+
1831+/**
1832+ * ccs_sb_umount - Check permission for umount().
1833+ *
1834+ * @mnt: Pointer to "struct vfsmount".
1835+ * @flags: Unmount flags.
1836+ *
1837+ * Returns 0 on success, negative value otherwise.
1838+ */
1839+static int ccs_sb_umount(struct vfsmount *mnt, int flags)
1840+{
1841+ int rc = ccs_umount_permission(mnt, flags);
1842+ if (rc)
1843+ return rc;
1844+ while (!original_security_ops.sb_umount);
1845+ return original_security_ops.sb_umount(mnt, flags);
1846+}
1847+
1848+/**
1849+ * ccs_file_fcntl - Check permission for fcntl().
1850+ *
1851+ * @file: Pointer to "struct file".
1852+ * @cmd: Command number.
1853+ * @arg: Value for @cmd.
1854+ *
1855+ * Returns 0 on success, negative value otherwise.
1856+ */
1857+static int ccs_file_fcntl(struct file *file, unsigned int cmd,
1858+ unsigned long arg)
1859+{
1860+ int rc = ccs_fcntl_permission(file, cmd, arg);
1861+ if (rc)
1862+ return rc;
1863+ while (!original_security_ops.file_fcntl);
1864+ return original_security_ops.file_fcntl(file, cmd, arg);
1865+}
1866+
1867+/**
1868+ * ccs_file_ioctl - Check permission for ioctl().
1869+ *
1870+ * @filp: Pointer to "struct file".
1871+ * @cmd: Command number.
1872+ * @arg: Value for @cmd.
1873+ *
1874+ * Returns 0 on success, negative value otherwise.
1875+ */
1876+static int ccs_file_ioctl(struct file *filp, unsigned int cmd,
1877+ unsigned long arg)
1878+{
1879+ int rc = ccs_ioctl_permission(filp, cmd, arg);
1880+ if (rc)
1881+ return rc;
1882+ while (!original_security_ops.file_ioctl);
1883+ return original_security_ops.file_ioctl(filp, cmd, arg);
1884+}
1885+
1886+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
1887+
1888+/**
1889+ * ccs_prepend - Copy of prepend() in fs/dcache.c.
1890+ *
1891+ * @buffer: Pointer to "struct char *".
1892+ * @buflen: Pointer to int which holds size of @buffer.
1893+ * @str: String to copy.
1894+ *
1895+ * Returns 0 on success, negative value otherwise.
1896+ *
1897+ * @buffer and @buflen are updated upon success.
1898+ */
1899+static int ccs_prepend(char **buffer, int *buflen, const char *str)
1900+{
1901+ int namelen = strlen(str);
1902+ if (*buflen < namelen)
1903+ return -ENOMEM;
1904+ *buflen -= namelen;
1905+ *buffer -= namelen;
1906+ memcpy(*buffer, str, namelen);
1907+ return 0;
1908+}
1909+
1910+/**
1911+ * ccs_sysctl_permission - Check permission for sysctl().
1912+ *
1913+ * @table: Pointer to "struct ctl_table".
1914+ * @op: Operation. (MAY_READ and/or MAY_WRITE)
1915+ *
1916+ * Returns 0 on success, negative value otherwise.
1917+ */
1918+static int ccs_sysctl(struct ctl_table *table, int op)
1919+{
1920+ int error;
1921+ struct ccs_path_info buf;
1922+ struct ccs_request_info r;
1923+ int buflen;
1924+ char *buffer;
1925+ int idx;
1926+ while (!original_security_ops.sysctl);
1927+ error = original_security_ops.sysctl(table, op);
1928+ if (error)
1929+ return error;
1930+ op &= MAY_READ | MAY_WRITE;
1931+ if (!op)
1932+ return 0;
1933+ buffer = NULL;
1934+ buf.name = NULL;
1935+ idx = ccs_read_lock();
1936+ if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
1937+ == CCS_CONFIG_DISABLED)
1938+ goto out;
1939+ error = -ENOMEM;
1940+ buflen = 4096;
1941+ buffer = kmalloc(buflen, CCS_GFP_FLAGS);
1942+ if (buffer) {
1943+ char *end = buffer + buflen;
1944+ *--end = '\0';
1945+ buflen--;
1946+ while (table) {
1947+ char num[32];
1948+ const char *sp = table->procname;
1949+ if (!sp) {
1950+ memset(num, 0, sizeof(num));
1951+ snprintf(num, sizeof(num) - 1, "=%d=",
1952+ table->ctl_name);
1953+ sp = num;
1954+ }
1955+ if (ccs_prepend(&end, &buflen, sp) ||
1956+ ccs_prepend(&end, &buflen, "/"))
1957+ goto out;
1958+ table = table->parent;
1959+ }
1960+ if (ccs_prepend(&end, &buflen, "proc:/sys"))
1961+ goto out;
1962+ buf.name = ccs_encode(end);
1963+ }
1964+ if (buf.name) {
1965+ ccs_fill_path_info(&buf);
1966+ if (op & MAY_READ)
1967+ error = ccs_path_permission(&r, CCS_TYPE_READ, &buf);
1968+ else
1969+ error = 0;
1970+ if (!error && (op & MAY_WRITE))
1971+ error = ccs_path_permission(&r, CCS_TYPE_WRITE, &buf);
1972+ }
1973+out:
1974+ ccs_read_unlock(idx);
1975+ kfree(buf.name);
1976+ kfree(buffer);
1977+ return error;
1978+}
1979+
1980+#endif
1981+
1982+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
1983+
1984+#include <linux/mount.h>
1985+#include <linux/fs_struct.h>
1986+
1987+/**
1988+ * ccs_kernel_read - Wrapper for kernel_read().
1989+ *
1990+ * @file: Pointer to "struct file".
1991+ * @offset: Starting position.
1992+ * @addr: Buffer.
1993+ * @count: Size of @addr.
1994+ *
1995+ * Returns return value from kernel_read().
1996+ */
1997+static int __init ccs_kernel_read(struct file *file, unsigned long offset,
1998+ char *addr, unsigned long count)
1999+{
2000+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
2001+ /*
2002+ * I can't use kernel_read() because seq_read() returns -EPIPE
2003+ * if &pos != &file->f_pos .
2004+ */
2005+ mm_segment_t old_fs;
2006+ unsigned long pos = file->f_pos;
2007+ int result;
2008+ file->f_pos = offset;
2009+ old_fs = get_fs();
2010+ set_fs(get_ds());
2011+ result = vfs_read(file, (void __user *)addr, count, &file->f_pos);
2012+ set_fs(old_fs);
2013+ file->f_pos = pos;
2014+ return result;
2015+#else
2016+ return kernel_read(file, offset, addr, count);
2017+#endif
2018+}
2019+
2020+/**
2021+ * ccs_find_symbol - Find function's address from /proc/kallsyms .
2022+ *
2023+ * @keyline: Function to find.
2024+ *
2025+ * Returns address of specified function on success, NULL otherwise.
2026+ */
2027+static void *__init ccs_find_symbol(const char *keyline)
2028+{
2029+ struct file *file = NULL;
2030+ char *buf;
2031+ unsigned long entry = 0;
2032+ {
2033+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
2034+ struct file_system_type *fstype = get_fs_type("proc");
2035+ struct vfsmount *mnt = vfs_kern_mount(fstype, 0, "proc", NULL);
2036+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
2037+ struct file_system_type *fstype = NULL;
2038+ struct vfsmount *mnt = do_kern_mount("proc", 0, "proc", NULL);
2039+#else
2040+ struct file_system_type *fstype = get_fs_type("proc");
2041+ struct vfsmount *mnt = kern_mount(fstype);
2042+#endif
2043+ struct dentry *root;
2044+ struct dentry *dentry;
2045+ /*
2046+ * We embed put_filesystem() here because it is not exported.
2047+ */
2048+ if (fstype)
2049+ module_put(fstype->owner);
2050+ if (IS_ERR(mnt))
2051+ goto out;
2052+ root = dget(mnt->mnt_root);
2053+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
2054+ mutex_lock(&root->d_inode->i_mutex);
2055+ dentry = lookup_one_len("kallsyms", root, 8);
2056+ mutex_unlock(&root->d_inode->i_mutex);
2057+#else
2058+ down(&root->d_inode->i_sem);
2059+ dentry = lookup_one_len("kallsyms", root, 8);
2060+ up(&root->d_inode->i_sem);
2061+#endif
2062+ dput(root);
2063+ if (IS_ERR(dentry))
2064+ mntput(mnt);
2065+ else
2066+ file = dentry_open(dentry, mnt, O_RDONLY
2067+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2068+ , current_cred()
2069+#endif
2070+ );
2071+ }
2072+ if (IS_ERR(file) || !file)
2073+ goto out;
2074+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2075+ if (buf) {
2076+ int len;
2077+ int offset = 0;
2078+ while ((len = ccs_kernel_read(file, offset, buf,
2079+ PAGE_SIZE - 1)) > 0) {
2080+ char *cp;
2081+ buf[len] = '\0';
2082+ cp = strrchr(buf, '\n');
2083+ if (!cp)
2084+ break;
2085+ *(cp + 1) = '\0';
2086+ offset += strlen(buf);
2087+ cp = strstr(buf, keyline);
2088+ if (!cp)
2089+ continue;
2090+ *cp = '\0';
2091+ while (cp > buf && *(cp - 1) != '\n')
2092+ cp--;
2093+ entry = simple_strtoul(cp, NULL, 16);
2094+ break;
2095+ }
2096+ kfree(buf);
2097+ }
2098+ filp_close(file, NULL);
2099+out:
2100+ return (void *) entry;
2101+}
2102+
2103+#endif
2104+
2105+/**
2106+ * ccs_find_variable - Find variable's address using dummy.
2107+ *
2108+ * @function: Pointer to dummy function's entry point.
2109+ * @addr: Address of the variable which is used within @function.
2110+ * @symbol: Name of symbol to resolve.
2111+ *
2112+ * This trick depends on below assumptions.
2113+ *
2114+ * (1) @addr is found within 128 bytes from @function, even if additional
2115+ * code (e.g. debug symbols) is added.
2116+ * (2) It is safe to read 128 bytes from @function.
2117+ * (3) @addr != Byte code except @addr.
2118+ */
2119+static void * __init ccs_find_variable(void *function, unsigned long addr,
2120+ const char *symbol)
2121+{
2122+ int i;
2123+ u8 *base;
2124+ u8 *cp = function;
2125+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2126+ if (*symbol == ' ')
2127+ base = ccs_find_symbol(symbol);
2128+ else
2129+#endif
2130+ base = __symbol_get(symbol);
2131+ if (!base)
2132+ return NULL;
2133+ /* First, assume absolute adressing mode is used. */
2134+ for (i = 0; i < 128; i++) {
2135+ if (*(unsigned long *) cp == addr)
2136+ return base + i;
2137+ cp++;
2138+ }
2139+ /* Next, assume PC-relative addressing mode is used. */
2140+ cp = function;
2141+ for (i = 0; i < 128; i++) {
2142+ if ((unsigned long) (cp + sizeof(int) + *(int *) cp) == addr) {
2143+ static void *cp4ret;
2144+ cp = base + i;
2145+ cp += sizeof(int) + *(int *) cp;
2146+ cp4ret = cp;
2147+ return &cp4ret;
2148+ }
2149+ cp++;
2150+ }
2151+ cp = function;
2152+ for (i = 0; i < 128; i++) {
2153+ if ((unsigned long) (long) (*(int *) cp) == addr) {
2154+ static void *cp4ret;
2155+ cp = base + i;
2156+ cp = (void *) (long) (*(int *) cp);
2157+ cp4ret = cp;
2158+ return &cp4ret;
2159+ }
2160+ cp++;
2161+ }
2162+ return NULL;
2163+}
2164+
2165+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2166+
2167+/* Never mark this variable as __initdata . */
2168+static struct security_operations *ccs_security_ops;
2169+
2170+/**
2171+ * lsm_addr_calculator - Dummy function which does identical to security_file_alloc() in security/security.c.
2172+ *
2173+ * @file: Pointer to "struct file".
2174+ *
2175+ * Returns return value fromfrom security_file_alloc().
2176+ *
2177+ * Never mark this function as __init in order to make sure that compiler
2178+ * generates identical code for security_file_alloc() and this function.
2179+ */
2180+static int lsm_addr_calculator(struct file *file)
2181+{
2182+ return ccs_security_ops->file_alloc_security(file);
2183+}
2184+
2185+#endif
2186+
2187+/**
2188+ * ccs_find_find_security_ops - Find address of "struct security_operations *security_ops".
2189+ *
2190+ * Returns pointer to "struct security_operations" on success, NULL otherwise.
2191+ */
2192+static struct security_operations * __init ccs_find_security_ops(void)
2193+{
2194+ struct security_operations **ptr;
2195+ struct security_operations *ops;
2196+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2197+ void *cp;
2198+ /* Guess "struct security_operations *security_ops;". */
2199+ cp = ccs_find_variable(lsm_addr_calculator, (unsigned long)
2200+ &ccs_security_ops, " security_file_alloc\n");
2201+ if (!cp) {
2202+ printk(KERN_ERR "Can't resolve security_file_alloc().\n");
2203+ goto out;
2204+ }
2205+ /* This should be "struct security_operations *security_ops;". */
2206+ ptr = *(struct security_operations ***) cp;
2207+#else
2208+ /* This is "struct security_operations *security_ops;". */
2209+ ptr = (struct security_operations **) __symbol_get("security_ops");
2210+#endif
2211+ if (!ptr) {
2212+ printk(KERN_ERR "Can't resolve security_ops structure.\n");
2213+ goto out;
2214+ }
2215+ printk(KERN_INFO "&security_ops=%p\n", ptr);
2216+ ops = *ptr;
2217+ if (!ops) {
2218+ printk(KERN_ERR "No security_operations registered.\n");
2219+ goto out;
2220+ }
2221+ return ops;
2222+out:
2223+ return NULL;
2224+}
2225+
2226+/**
2227+ * ccs_find_find_task_by_pid - Find address of find_task_by_pid().
2228+ *
2229+ * Returns true on success, false otherwise.
2230+ */
2231+static bool __init ccs_find_find_task_by_pid(void)
2232+{
2233+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2234+ void *ptr;
2235+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
2236+ ptr = ccs_find_symbol(" find_task_by_vpid\n");
2237+#else
2238+ ptr = __symbol_get("find_task_by_vpid");
2239+#endif
2240+ if (!ptr) {
2241+ printk(KERN_ERR "Can't resolve find_task_by_vpid().\n");
2242+ goto out;
2243+ }
2244+ ccsecurity_exports.find_task_by_vpid = ptr;
2245+ printk(KERN_INFO "find_task_by_vpid=%p\n", ptr);
2246+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
2247+ ptr = ccs_find_symbol(" find_task_by_pid_ns\n");
2248+#else
2249+ ptr = __symbol_get("find_task_by_pid_ns");
2250+#endif
2251+ if (!ptr) {
2252+ printk(KERN_ERR "Can't resolve find_task_by_pid_ns().\n");
2253+ goto out;
2254+ }
2255+ ccsecurity_exports.find_task_by_pid_ns = ptr;
2256+ printk(KERN_INFO "find_task_by_pid_ns=%p\n", ptr);
2257+ return true;
2258+out:
2259+ return false;
2260+#else
2261+ return true;
2262+#endif
2263+}
2264+
2265+/**
2266+ * ccs_find___put_task_struct - Find address of __put_task_struct().
2267+ *
2268+ * Returns true on success, false otherwise.
2269+ */
2270+static bool __init ccs_find___put_task_struct(void)
2271+{
2272+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2273+ void *ptr;
2274+ ptr = ccs_find_symbol(" __put_task_struct\n");
2275+ if (!ptr) {
2276+ printk(KERN_ERR "Can't resolve __put_task_struct().\n");
2277+ goto out;
2278+ }
2279+ ccs___put_task_struct = ptr;
2280+ printk(KERN_INFO "__put_task_struct=%p\n", ptr);
2281+ return true;
2282+out:
2283+ return false;
2284+#else
2285+ return true;
2286+#endif
2287+}
2288+
2289+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2290+
2291+/* Never mark this variable as __initdata . */
2292+static spinlock_t ccs_vfsmount_lock;
2293+
2294+/**
2295+ * lsm_umnt_tr - Dummy function which prototype is identical to umount_tree() in fs/namespace.c.
2296+ *
2297+ * @mnt: Pointer to "struct vfsmount".
2298+ *
2299+ * Returns nothing.
2300+ */
2301+static void lsm_umnt_tr(struct vfsmount *mnt)
2302+{
2303+ /* Nothing to do because this function is not called. */
2304+}
2305+
2306+/**
2307+ * lsm__put_nmspce - Dummy function which does identical to __put_namespace() in fs/namespace.c.
2308+ *
2309+ * @namespace: Pointer to "struct namespace".
2310+ *
2311+ * Returns nothing.
2312+ *
2313+ * Never mark this function as __init in order to make sure that compiler
2314+ * generates identical code for __put_namespace() and this function.
2315+ */
2316+static void lsm__put_nmspce(struct namespace *namespace)
2317+{
2318+ down_write(&namespace->sem);
2319+ spin_lock(&ccs_vfsmount_lock);
2320+ lsm_umnt_tr(namespace->root);
2321+ spin_unlock(&ccs_vfsmount_lock);
2322+ up_write(&namespace->sem);
2323+ kfree(namespace);
2324+}
2325+
2326+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
2327+
2328+/* Never mark this variable as __initdata . */
2329+static spinlock_t ccs_vfsmount_lock;
2330+
2331+/**
2332+ * lsm_flwup - Dummy function which does identical to follow_up() in fs/namei.c.
2333+ *
2334+ * @mnt: Pointer to "struct vfsmount *".
2335+ * @dentry: Pointer to "struct dentry *".
2336+ *
2337+ * Returns 1 if followed up, 0 otehrwise.
2338+ *
2339+ * Never mark this function as __init in order to make sure that compiler
2340+ * generates identical code for follow_up() and this function.
2341+ */
2342+static int lsm_flwup(struct vfsmount **mnt, struct dentry **dentry)
2343+{
2344+ struct vfsmount *parent;
2345+ struct dentry *mountpoint;
2346+ spin_lock(&ccs_vfsmount_lock);
2347+ parent = (*mnt)->mnt_parent;
2348+ if (parent == *mnt) {
2349+ spin_unlock(&ccs_vfsmount_lock);
2350+ return 0;
2351+ }
2352+ mntget(parent);
2353+ mountpoint = dget((*mnt)->mnt_mountpoint);
2354+ spin_unlock(&ccs_vfsmount_lock);
2355+ dput(*dentry);
2356+ *dentry = mountpoint;
2357+ mntput(*mnt);
2358+ *mnt = parent;
2359+ return 1;
2360+}
2361+
2362+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
2363+
2364+/* Never mark this variable as __initdata . */
2365+static spinlock_t ccs_vfsmount_lock;
2366+
2367+/**
2368+ * lsm_pin - Dummy function which does identical to mnt_pin() in fs/namespace.c.
2369+ *
2370+ * @mnt: Pointer to "struct vfsmount".
2371+ *
2372+ * Returns nothing.
2373+ *
2374+ * Never mark this function as __init in order to make sure that compiler
2375+ * generates identical code for mnt_pin() and this function.
2376+ */
2377+static void lsm_pin(struct vfsmount *mnt)
2378+{
2379+ spin_lock(&ccs_vfsmount_lock);
2380+ mnt->mnt_pinned++;
2381+ spin_lock(&ccs_vfsmount_lock);
2382+}
2383+
2384+#endif
2385+
2386+/**
2387+ * ccs_find_vfsmount_lock - Find address of "spinlock_t vfsmount_lock".
2388+ *
2389+ * Returns true on success, false otherwise.
2390+ */
2391+static bool __init ccs_find_vfsmount_lock(void)
2392+{
2393+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
2394+ void *cp;
2395+ spinlock_t *ptr;
2396+ /* Guess "spinlock_t vfsmount_lock;". */
2397+ cp = ccs_find_variable(lsm__put_nmspce,
2398+ (unsigned long) &ccs_vfsmount_lock,
2399+ " __put_namespace\n");
2400+ if (!cp) {
2401+ printk(KERN_ERR "Can't resolve __put_namespace().\n");
2402+ goto out;
2403+ }
2404+ /* This should be "spinlock_t *vfsmount_lock;". */
2405+ ptr = *(spinlock_t **) cp;
2406+ if (!ptr) {
2407+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
2408+ goto out;
2409+ }
2410+ ccsecurity_exports.vfsmount_lock = ptr;
2411+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
2412+ return true;
2413+out:
2414+ /*
2415+ * Dummy call for preventing lsm_umnt_tr() from being inlined into
2416+ * lsm__put_nmspce().
2417+ */
2418+ cp = ccs_find_variable(lsm_umnt_tr,
2419+ (unsigned long) &ccs_vfsmount_lock,
2420+ " __put_namespace\n");
2421+ return false;
2422+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
2423+ void *cp;
2424+ spinlock_t *ptr;
2425+ /* Guess "spinlock_t vfsmount_lock;". */
2426+ cp = ccs_find_variable(lsm_flwup, (unsigned long) &ccs_vfsmount_lock,
2427+ "follow_up");
2428+ if (!cp) {
2429+ printk(KERN_ERR "Can't resolve follow_up().\n");
2430+ goto out;
2431+ }
2432+ /* This should be "spinlock_t *vfsmount_lock;". */
2433+ ptr = *(spinlock_t **) cp;
2434+ if (!ptr) {
2435+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
2436+ goto out;
2437+ }
2438+ ccsecurity_exports.vfsmount_lock = ptr;
2439+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
2440+ return true;
2441+out:
2442+ return false;
2443+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
2444+ void *cp;
2445+ spinlock_t *ptr;
2446+ /* Guess "spinlock_t vfsmount_lock;". */
2447+ cp = ccs_find_variable(lsm_pin, (unsigned long) &ccs_vfsmount_lock,
2448+ "mnt_pin");
2449+ if (!cp) {
2450+ printk(KERN_ERR "Can't resolve mnt_pin().\n");
2451+ goto out;
2452+ }
2453+ /* This should be "spinlock_t *vfsmount_lock;". */
2454+ ptr = *(spinlock_t **) cp;
2455+ if (!ptr) {
2456+ printk(KERN_ERR "Can't resolve vfsmount_lock .\n");
2457+ goto out;
2458+ }
2459+ ccsecurity_exports.vfsmount_lock = ptr;
2460+ printk(KERN_INFO "vfsmount_lock=%p\n", ptr);
2461+ return true;
2462+out:
2463+ return false;
2464+#else
2465+ void *ptr = ccs_find_symbol(" __d_path\n");
2466+ if (!ptr) {
2467+ printk(KERN_ERR "Can't resolve __d_path().\n");
2468+ return false;
2469+ }
2470+ ccsecurity_exports.__d_path = ptr;
2471+ printk(KERN_INFO "__d_path=%p\n", ptr);
2472+ return true;
2473+#endif
2474+}
2475+
2476+/*
2477+ * Why not to copy all operations by "original_security_ops = *ops" ?
2478+ * Because copying byte array is not atomic. Reader checks
2479+ * original_security_ops.op != NULL before doing original_security_ops.op().
2480+ * Thus, modifying original_security_ops.op has to be atomic.
2481+ */
2482+#define swap_security_ops(op) \
2483+ original_security_ops.op = ops->op; smp_wmb(); ops->op = ccs_##op;
2484+
2485+/**
2486+ * ccs_update_security_ops - Overwrite original "struct security_operations".
2487+ *
2488+ * @ops: Pointer to "struct security_operations".
2489+ *
2490+ * Returns nothing.
2491+ */
2492+static void __init ccs_update_security_ops(struct security_operations *ops)
2493+{
2494+ /* Security context allocator. */
2495+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2496+ swap_security_ops(task_create);
2497+ swap_security_ops(cred_prepare);
2498+ swap_security_ops(cred_free);
2499+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
2500+ swap_security_ops(cred_alloc_blank);
2501+ swap_security_ops(cred_transfer);
2502+#endif
2503+#else
2504+ swap_security_ops(task_alloc_security);
2505+ swap_security_ops(task_free_security);
2506+ swap_security_ops(bprm_free_security);
2507+#endif
2508+ /* Security context updater for successful execve(). */
2509+ swap_security_ops(bprm_check_security);
2510+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6)
2511+ swap_security_ops(bprm_compute_creds);
2512+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2513+ swap_security_ops(bprm_apply_creds);
2514+#else
2515+ swap_security_ops(bprm_committing_creds);
2516+#endif
2517+ /* Various permission checker. */
2518+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2519+ swap_security_ops(dentry_open);
2520+#else
2521+ swap_security_ops(inode_permission);
2522+#endif
2523+ swap_security_ops(file_fcntl);
2524+ swap_security_ops(file_ioctl);
2525+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
2526+ swap_security_ops(sysctl);
2527+#endif
2528+ swap_security_ops(sb_pivotroot);
2529+ swap_security_ops(sb_mount);
2530+ swap_security_ops(sb_umount);
2531+#if defined(CONFIG_SECURITY_PATH)
2532+ swap_security_ops(path_mknod);
2533+ swap_security_ops(path_mkdir);
2534+ swap_security_ops(path_rmdir);
2535+ swap_security_ops(path_unlink);
2536+ swap_security_ops(path_symlink);
2537+ swap_security_ops(path_rename);
2538+ swap_security_ops(path_link);
2539+ swap_security_ops(path_truncate);
2540+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2541+ swap_security_ops(path_chmod);
2542+ swap_security_ops(path_chown);
2543+ swap_security_ops(path_chroot);
2544+#endif
2545+#else
2546+ swap_security_ops(inode_mknod);
2547+ swap_security_ops(inode_mkdir);
2548+ swap_security_ops(inode_rmdir);
2549+ swap_security_ops(inode_unlink);
2550+ swap_security_ops(inode_symlink);
2551+ swap_security_ops(inode_rename);
2552+ swap_security_ops(inode_link);
2553+ swap_security_ops(inode_create);
2554+#endif
2555+ swap_security_ops(inode_setattr);
2556+ swap_security_ops(inode_getattr);
2557+#ifdef CONFIG_SECURITY_NETWORK
2558+ swap_security_ops(socket_bind);
2559+ swap_security_ops(socket_connect);
2560+ swap_security_ops(socket_listen);
2561+ swap_security_ops(socket_sendmsg);
2562+ swap_security_ops(socket_recvmsg);
2563+ swap_security_ops(socket_getsockname);
2564+ swap_security_ops(socket_getpeername);
2565+ swap_security_ops(socket_getsockopt);
2566+ swap_security_ops(socket_setsockopt);
2567+ swap_security_ops(socket_shutdown);
2568+ swap_security_ops(socket_accept);
2569+ swap_security_ops(inode_free_security);
2570+#endif
2571+}
2572+
2573+#undef swap_security_ops
2574+
2575+/**
2576+ * ccs_init - Initialize this module.
2577+ *
2578+ * Returns 0 on success, negative value otherwise.
2579+ */
2580+static int __init ccs_init(void)
2581+{
2582+ struct security_operations *ops = ccs_find_security_ops();
2583+ if (!ops || !ccs_find_find_task_by_pid() ||
2584+ !ccs_find_vfsmount_lock() || !ccs_find___put_task_struct())
2585+ return -EINVAL;
2586+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2587+ {
2588+ int idx;
2589+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++)
2590+ INIT_LIST_HEAD(&ccs_cred_security_list[idx]);
2591+ }
2592+#endif
2593+ ccs_main_init();
2594+ ccs_update_security_ops(ops);
2595+ printk(KERN_INFO "AKARI: 1.0.12 2011/04/11\n");
2596+ printk(KERN_INFO
2597+ "Access Keeping And Regulating Instrument registered.\n");
2598+ return 0;
2599+}
2600+
2601+module_init(ccs_init);
2602+MODULE_LICENSE("GPL");
2603+
2604+/**
2605+ * ccs_used_by_cred - Check whether the given domain is in use or not.
2606+ *
2607+ * @domain: Pointer to "struct ccs_domain_info".
2608+ *
2609+ * Returns true if @domain is in use, false otherwise.
2610+ *
2611+ * Caller holds rcu_read_lock().
2612+ */
2613+bool ccs_used_by_cred(const struct ccs_domain_info *domain)
2614+{
2615+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2616+ int idx;
2617+ struct ccs_security *ptr;
2618+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
2619+ struct list_head *list = &ccs_cred_security_list[idx];
2620+ list_for_each_entry_rcu(ptr, list, list) {
2621+ struct ccs_execve *ee = ptr->ee;
2622+ if (ptr->ccs_domain_info == domain ||
2623+ (ee && ee->previous_domain == domain)) {
2624+ return true;
2625+ }
2626+ }
2627+ }
2628+#endif
2629+ return false;
2630+}
2631+
2632+/**
2633+ * ccs_find_task_security - Find "struct ccs_security" for given task.
2634+ *
2635+ * @task: Pointer to "struct task_struct".
2636+ *
2637+ * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
2638+ * out of memory, &ccs_default_security otherwise.
2639+ *
2640+ * If @task is current thread and "struct ccs_security" for current thread was
2641+ * not found, I try to allocate it. But if allocation failed, current thread
2642+ * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
2643+ * won't work.
2644+ */
2645+struct ccs_security *ccs_find_task_security(const struct task_struct *task)
2646+{
2647+ struct ccs_security *ptr;
2648+ struct list_head *list = &ccs_task_security_list
2649+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
2650+ /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
2651+ while (!list->next);
2652+ rcu_read_lock();
2653+ list_for_each_entry_rcu(ptr, list, list) {
2654+ if (ptr->task != task)
2655+ continue;
2656+ rcu_read_unlock();
2657+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2658+ /*
2659+ * Current thread needs to transit from old domain to new
2660+ * domain before do_execve() succeeds in order to check
2661+ * permission for interpreters and environment variables using
2662+ * new domain's ACL rules. The domain transition has to be
2663+ * visible from other CPU in order to allow interactive
2664+ * enforcing mode. Also, the domain transition has to be
2665+ * reverted if do_execve() failed. However, an LSM hook for
2666+ * reverting domain transition is missing.
2667+ *
2668+ * When do_execve() failed, "struct cred" in
2669+ * "struct linux_binprm" is scheduled for destruction.
2670+ * But current thread returns to userspace without waiting for
2671+ * destruction. The security_cred_free() LSM hook is called
2672+ * after an RCU grace period has elapsed. Since some CPU may be
2673+ * doing long long RCU read side critical section, there is
2674+ * no guarantee that security_cred_free() is called before
2675+ * current thread again calls do_execve().
2676+ *
2677+ * To be able to revert domain transition before processing
2678+ * next do_execve() request, current thread gets a refcount on
2679+ * "struct cred" in "struct linux_binprm" and memorizes it.
2680+ * Current thread drops the refcount and forgets it when
2681+ * do_execve() succeeded.
2682+ *
2683+ * Therefore, if current thread hasn't forgotten it and
2684+ * current thread is the last one using that "struct cred",
2685+ * it indicates that do_execve() has failed and reverting
2686+ * domain transition is needed.
2687+ */
2688+ if (task == current && ptr->cred &&
2689+ atomic_read(&ptr->cred->usage) == 1) {
2690+ /*
2691+ printk(KERN_DEBUG
2692+ "pid=%u: Reverting domain transition because "
2693+ "do_execve() has failed.\n", task->pid);
2694+ */
2695+ ccs_clear_execve(-1, ptr);
2696+ }
2697+#endif
2698+ return ptr;
2699+ }
2700+ rcu_read_unlock();
2701+ if (task != current) {
2702+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2703+ /*
2704+ * If a thread does nothing after fork(), caller will reach
2705+ * here because "struct ccs_security" for that thread is not
2706+ * yet allocated. But that thread is keeping a snapshot of
2707+ * "struct ccs_security" taken as of ccs_task_create()
2708+ * associated with that thread's "struct cred".
2709+ *
2710+ * Since that snapshot will be used as initial data when that
2711+ * thread allocates "struct ccs_security" for that thread, we
2712+ * can return that snapshot rather than &ccs_default_security.
2713+ *
2714+ * Since this function is called by only ccs_select_one() and
2715+ * ccs_read_pid() (via ccs_task_domain() and ccs_task_flags()),
2716+ * it is guaranteed that caller has called rcu_read_lock()
2717+ * (via ccs_tasklist_lock()) before finding this thread and
2718+ * this thread is valid. Therefore, we can do __task_cred(task)
2719+ * like get_robust_list() does.
2720+ */
2721+ return ccs_find_cred_security(__task_cred(task));
2722+#else
2723+ return &ccs_default_security;
2724+#endif
2725+ }
2726+ /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
2727+ ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
2728+ if (!ptr) {
2729+ printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
2730+ task->pid);
2731+ send_sig(SIGKILL, current, 0);
2732+ return &ccs_oom_security;
2733+ }
2734+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2735+ *ptr = *ccs_find_cred_security(task->cred);
2736+#else
2737+ *ptr = ccs_default_security;
2738+#endif
2739+ get_task_struct((struct task_struct *) task);
2740+ ptr->task = (struct task_struct *) task;
2741+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2742+ /* ptr->cred may point to garbage. I need to explicitly clear. */
2743+ ptr->cred = NULL;
2744+#endif
2745+ ccs_add_task_security(ptr, list);
2746+ return ptr;
2747+}
2748+
2749+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
2750+
2751+/**
2752+ * ccs_copy_cred_security - Allocate memory for new credentials.
2753+ *
2754+ * @new: Pointer to "struct cred".
2755+ * @old: Pointer to "struct cred".
2756+ * @gfp: Memory allocation flags.
2757+ *
2758+ * Returns 0 on success, negative value otherwise.
2759+ */
2760+static int ccs_copy_cred_security(const struct cred *new,
2761+ const struct cred *old, gfp_t gfp)
2762+{
2763+ struct ccs_security *old_security = ccs_find_cred_security(old);
2764+ struct ccs_security *new_security =
2765+ kzalloc(sizeof(*new_security), gfp);
2766+ if (!new_security)
2767+ return -ENOMEM;
2768+ *new_security = *old_security;
2769+ new_security->cred = new;
2770+ ccs_add_cred_security(new_security);
2771+ return 0;
2772+}
2773+
2774+/**
2775+ * ccs_find_cred_security - Find "struct ccs_security" for given credential.
2776+ *
2777+ * @cred: Pointer to "struct cred".
2778+ *
2779+ * Returns pointer to "struct ccs_security" on success, &ccs_default_security
2780+ * otherwise.
2781+ */
2782+static struct ccs_security *ccs_find_cred_security(const struct cred *cred)
2783+{
2784+ struct ccs_security *ptr;
2785+ struct list_head *list = &ccs_cred_security_list
2786+ [hash_ptr((void *) cred, CCS_TASK_SECURITY_HASH_BITS)];
2787+ rcu_read_lock();
2788+ list_for_each_entry_rcu(ptr, list, list) {
2789+ if (ptr->cred != cred)
2790+ continue;
2791+ rcu_read_unlock();
2792+ return ptr;
2793+ }
2794+ rcu_read_unlock();
2795+ return &ccs_default_security;
2796+}
2797+
2798+/**
2799+ * ccs_task_security_gc - Do garbage collection for "struct task_struct".
2800+ *
2801+ * Returns nothing.
2802+ *
2803+ * Since security_task_free_security() is missing, I can't release memory
2804+ * associated with "struct task_struct" when a task dies. Therefore, I hold
2805+ * a reference on "struct task_struct" and runs garbage collection when I
2806+ * became the last user who refers that "struct task_struct".
2807+ */
2808+static void ccs_task_security_gc(void)
2809+{
2810+ static DEFINE_MUTEX(lock);
2811+ static unsigned int counter;
2812+ unsigned int idx;
2813+ if (!mutex_trylock(&lock))
2814+ return;
2815+ /* Checking everytime is too wasteful. */
2816+ if (counter++ < 1024)
2817+ goto skip;
2818+ counter = 0;
2819+ rcu_read_lock();
2820+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
2821+ struct ccs_security *ptr;
2822+ struct list_head *list = &ccs_task_security_list[idx];
2823+ list_for_each_entry_rcu(ptr, list, list) {
2824+ struct task_struct *task =
2825+ (struct task_struct *) ptr->task;
2826+ /* Am I the last one using this task? */
2827+ if (atomic_read(&task->usage) != 1)
2828+ continue;
2829+ /*
2830+ * We need to call put_task_struct(task); here.
2831+ * However, since put_task_struct() is an inlined
2832+ * function which calls __put_task_struct() and
2833+ * __put_task_struct() is not exported,
2834+ * we embed put_task_struct() into here.
2835+ */
2836+ atomic_dec(&task->usage);
2837+ ccs___put_task_struct(task);
2838+ ccs_del_security(ptr);
2839+ }
2840+ }
2841+ rcu_read_unlock();
2842+skip:
2843+ mutex_unlock(&lock);
2844+}
2845+
2846+#endif
--- tags/patches/1.0.12/load_policy.c (nonexistent)
+++ tags/patches/1.0.12/load_policy.c (revision 197)
@@ -0,0 +1,303 @@
1+/*
2+ * security/ccsecurity/load_policy.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include <linux/version.h>
10+#include <linux/module.h>
11+#include <linux/init.h>
12+#include <linux/binfmts.h>
13+#include <linux/sched.h>
14+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
15+#include <linux/kmod.h>
16+/*
17+ * Regarding 2.4 kernels, we need to define __KERNEL_SYSCALLS__ in order to use
18+ * waitpid() because call_usermodehelper() does not support UMH_WAIT_PROC.
19+ */
20+#define __KERNEL_SYSCALLS__
21+#include <linux/unistd.h>
22+#else
23+#include <linux/fs.h>
24+#include <linux/namei.h>
25+#endif
26+#ifndef LOOKUP_POSITIVE
27+#define LOOKUP_POSITIVE 0
28+#endif
29+
30+/*
31+ * TOMOYO specific part start.
32+ */
33+
34+#include "internal.h"
35+
36+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
37+
38+/* Path to the policy loader. (default = CONFIG_CCSECURITY_DEFAULT_LOADER) */
39+static const char *ccs_loader;
40+
41+#if 0
42+/**
43+ * ccs_loader_setup - Specify the policy loader to use.
44+ *
45+ * @str: Path to the policy loader.
46+ *
47+ * Returns 0.
48+ */
49+static int __init ccs_loader_setup(char *str)
50+{
51+ ccs_loader = str;
52+ return 0;
53+}
54+
55+__setup("CCS_loader=", ccs_loader_setup);
56+#endif
57+
58+#endif
59+
60+#if 0
61+/**
62+ * ccs_setup - Set enable/disable upon boot.
63+ *
64+ * @str: "off" to disable, "on" to enable.
65+ *
66+ * Returns 0.
67+ */
68+static int __init ccs_setup(char *str)
69+{
70+ if (!strcmp(str, "off"))
71+ ccsecurity_ops.disabled = 1;
72+ else if (!strcmp(str, "on"))
73+ ccsecurity_ops.disabled = 0;
74+ return 0;
75+}
76+
77+__setup("ccsecurity=", ccs_setup);
78+#endif
79+
80+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
81+
82+/**
83+ * ccs_policy_loader_exists - Check whether /sbin/ccs-init exists.
84+ *
85+ * Returns true if /sbin/ccs-init exists, false otherwise.
86+ */
87+static _Bool ccs_policy_loader_exists(void)
88+{
89+ /*
90+ * Don't activate MAC if the path given by 'CCS_loader=' option doesn't
91+ * exist. If the initrd includes /sbin/init but real-root-dev has not
92+ * mounted on / yet, activating MAC will block the system since
93+ * policies are not loaded yet.
94+ * Thus, let do_execve() call this function everytime.
95+ */
96+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
97+ struct path path;
98+ if (!ccs_loader)
99+ ccs_loader = CONFIG_CCSECURITY_DEFAULT_LOADER;
100+ if (kern_path(ccs_loader, LOOKUP_FOLLOW | LOOKUP_POSITIVE,
101+ &path) == 0) {
102+ path_put(&path);
103+ return 1;
104+ }
105+#else
106+ struct nameidata nd;
107+ if (!ccs_loader)
108+ ccs_loader = CONFIG_CCSECURITY_DEFAULT_LOADER;
109+ if (path_lookup(ccs_loader, LOOKUP_FOLLOW | LOOKUP_POSITIVE,
110+ &nd) == 0) {
111+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
112+ path_put(&nd.path);
113+#else
114+ path_release(&nd);
115+#endif
116+ return 1;
117+ }
118+#endif
119+ printk(KERN_INFO "Not activating Mandatory Access Control "
120+ "as %s does not exist.\n", ccs_loader);
121+ return 0;
122+}
123+
124+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
125+
126+/**
127+ * ccs_run_loader - Start /sbin/ccs-init.
128+ *
129+ * @unused: Not used.
130+ *
131+ * Returns PID of /sbin/ccs-init on success, negative value otherwise.
132+ */
133+static int ccs_run_loader(void *unused)
134+{
135+ char *argv[2];
136+ char *envp[3];
137+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
138+ ccs_loader);
139+ argv[0] = (char *) ccs_loader;
140+ argv[1] = NULL;
141+ envp[0] = "HOME=/";
142+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
143+ envp[2] = NULL;
144+ return exec_usermodehelper(argv[0], argv, envp);
145+}
146+
147+#endif
148+
149+/**
150+ * ccs_load_policy - Run external policy loader to load policy.
151+ *
152+ * @filename: The program about to start.
153+ *
154+ * Returns nothing.
155+ *
156+ * This function checks whether @filename is /sbin/init, and if so
157+ * invoke /sbin/ccs-init and wait for the termination of /sbin/ccs-init
158+ * and then continues invocation of /sbin/init.
159+ * /sbin/ccs-init reads policy files in /etc/ccs/ directory and
160+ * writes to /proc/ccs/ interfaces.
161+ */
162+void ccs_load_policy(const char *filename)
163+{
164+ if (ccsecurity_ops.disabled)
165+ return;
166+ if (strcmp(filename, "/sbin/init") &&
167+ strcmp(filename, CONFIG_CCSECURITY_ALTERNATIVE_TRIGGER))
168+ return;
169+ if (!ccs_policy_loader_exists())
170+ return;
171+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
172+ {
173+ char *argv[2];
174+ char *envp[3];
175+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
176+ ccs_loader);
177+ argv[0] = (char *) ccs_loader;
178+ argv[1] = NULL;
179+ envp[0] = "HOME=/";
180+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
181+ envp[2] = NULL;
182+ call_usermodehelper(argv[0], argv, envp, 1);
183+ }
184+#elif defined(TASK_DEAD)
185+ {
186+ /* Copied from kernel/kmod.c */
187+ struct task_struct *task = current;
188+ pid_t pid = kernel_thread(ccs_run_loader, NULL, 0);
189+ sigset_t tmpsig;
190+ spin_lock_irq(&task->sighand->siglock);
191+ tmpsig = task->blocked;
192+ siginitsetinv(&task->blocked,
193+ sigmask(SIGKILL) | sigmask(SIGSTOP));
194+ recalc_sigpending();
195+ spin_unlock_irq(&task->sighand->siglock);
196+ if (pid >= 0)
197+ waitpid(pid, NULL, __WCLONE);
198+ spin_lock_irq(&task->sighand->siglock);
199+ task->blocked = tmpsig;
200+ recalc_sigpending();
201+ spin_unlock_irq(&task->sighand->siglock);
202+ }
203+#else
204+ {
205+ /* Copied from kernel/kmod.c */
206+ struct task_struct *task = current;
207+ pid_t pid = kernel_thread(ccs_run_loader, NULL, 0);
208+ sigset_t tmpsig;
209+ spin_lock_irq(&task->sigmask_lock);
210+ tmpsig = task->blocked;
211+ siginitsetinv(&task->blocked,
212+ sigmask(SIGKILL) | sigmask(SIGSTOP));
213+ recalc_sigpending(task);
214+ spin_unlock_irq(&task->sigmask_lock);
215+ if (pid >= 0)
216+ waitpid(pid, NULL, __WCLONE);
217+ spin_lock_irq(&task->sigmask_lock);
218+ task->blocked = tmpsig;
219+ recalc_sigpending(task);
220+ spin_unlock_irq(&task->sigmask_lock);
221+ }
222+#endif
223+ if (ccsecurity_ops.check_profile)
224+ ccsecurity_ops.check_profile();
225+ else
226+ panic("Failed to load policy.");
227+}
228+
229+#endif
230+
231+#if 0
232+/**
233+ * __ccs_search_binary_handler - Load policy before calling search_binary_handler().
234+ *
235+ * @bprm: Pointer to "struct linux_binprm".
236+ * @regs: Pointer to "struct pt_regs".
237+ *
238+ * Returns 0 on success, negative value otherwise.
239+ */
240+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
241+ struct pt_regs *regs)
242+{
243+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
244+ ccs_load_policy(bprm->filename);
245+#endif
246+ /*
247+ * ccs_load_policy() executes /sbin/ccs-init if bprm->filename is
248+ * /sbin/init. /sbin/ccs-init executes /etc/ccs/ccs-load-module to
249+ * load loadable kernel module. The loadable kernel module modifies
250+ * "struct ccsecurity_ops". Thus, we need to transfer control to
251+ * __ccs_search_binary_handler() in security/ccsecurity/domain.c
252+ * if "struct ccsecurity_ops" was modified.
253+ */
254+ if (ccsecurity_ops.search_binary_handler
255+ != __ccs_search_binary_handler)
256+ return ccsecurity_ops.search_binary_handler(bprm, regs);
257+ return search_binary_handler(bprm, regs);
258+}
259+
260+/*
261+ * Some exports for loadable kernel module part.
262+ *
263+ * Although scripts/checkpatch.pl complains about use of "extern" in C file,
264+ * we don't put these into security/ccsecurity/internal.h because we want to
265+ * split built-in part and loadable kernel module part.
266+ */
267+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
268+extern spinlock_t vfsmount_lock;
269+#endif
270+
271+/* For exporting variables and functions. */
272+const struct ccsecurity_exports ccsecurity_exports = {
273+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
274+ .load_policy = ccs_load_policy,
275+#endif
276+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
277+ .__d_path = __d_path,
278+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
279+ .vfsmount_lock = &vfsmount_lock,
280+#endif
281+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
282+ .find_task_by_vpid = find_task_by_vpid,
283+ .find_task_by_pid_ns = find_task_by_pid_ns,
284+#endif
285+};
286+#ifdef CONFIG_CCSECURITY_LKM
287+/* Only ccsecurity module need to access this struct. */
288+EXPORT_SYMBOL_GPL(ccsecurity_exports);
289+#endif
290+
291+/* Members are updated by loadable kernel module. */
292+struct ccsecurity_operations ccsecurity_ops = {
293+ .search_binary_handler = __ccs_search_binary_handler,
294+#ifdef CONFIG_CCSECURITY_DISABLE_BY_DEFAULT
295+ .disabled = 1,
296+#endif
297+};
298+/*
299+ * Non-GPL modules might need to access this struct via inlined functions
300+ * embedded into include/linux/security.h and include/net/ip.h
301+ */
302+EXPORT_SYMBOL(ccsecurity_ops);
303+#endif
--- tags/patches/1.0.12/realpath.c (nonexistent)
+++ tags/patches/1.0.12/realpath.c (revision 197)
@@ -0,0 +1,615 @@
1+/*
2+ * security/ccsecurity/realpath.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
11+#define ccs_lookup_flags LOOKUP_FOLLOW
12+#else
13+#define ccs_lookup_flags (LOOKUP_FOLLOW | LOOKUP_POSITIVE)
14+#endif
15+
16+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
17+#define s_fs_info u.generic_sbp
18+#endif
19+
20+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
21+
22+/**
23+ * SOCKET_I - Get "struct socket".
24+ *
25+ * @inode: Pointer to "struct inode".
26+ *
27+ * Returns pointer to "struct socket".
28+ *
29+ * This is for compatibility with older kernels.
30+ */
31+static inline struct socket *SOCKET_I(struct inode *inode)
32+{
33+ return inode->i_sock ? &inode->u.socket_i : NULL;
34+}
35+
36+#endif
37+
38+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
39+
40+/**
41+ * ccs_realpath_lock - Take locks for __d_path().
42+ *
43+ * Returns nothing.
44+ */
45+static inline void ccs_realpath_lock(void)
46+{
47+ /* dcache_lock is locked by __d_path(). */
48+ /* vfsmount_lock is locked by __d_path(). */
49+}
50+
51+/**
52+ * ccs_realpath_unlock - Release locks for __d_path().
53+ *
54+ * Returns nothing.
55+ */
56+static inline void ccs_realpath_unlock(void)
57+{
58+ /* vfsmount_lock is unlocked by __d_path(). */
59+ /* dcache_lock is unlocked by __d_path(). */
60+}
61+
62+#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 36)
63+
64+/**
65+ * ccs_realpath_lock - Take locks for __d_path().
66+ *
67+ * Returns nothing.
68+ */
69+static inline void ccs_realpath_lock(void)
70+{
71+ spin_lock(&dcache_lock);
72+ /* vfsmount_lock is locked by __d_path(). */
73+}
74+
75+/**
76+ * ccs_realpath_unlock - Release locks for __d_path().
77+ *
78+ * Returns nothing.
79+ */
80+static inline void ccs_realpath_unlock(void)
81+{
82+ /* vfsmount_lock is unlocked by __d_path(). */
83+ spin_unlock(&dcache_lock);
84+}
85+
86+#elif defined(D_PATH_DISCONNECT) && !defined(CONFIG_SUSE_KERNEL)
87+
88+/**
89+ * ccs_realpath_lock - Take locks for __d_path().
90+ *
91+ * Returns nothing.
92+ *
93+ * Original unambiguous-__d_path.diff in patches.apparmor.tar.bz2 inversed the
94+ * order of holding dcache_lock and vfsmount_lock. That patch was applied on
95+ * (at least) SUSE 11.1 and Ubuntu 8.10 and Ubuntu 9.04 kernels.
96+ *
97+ * However, that patch was updated to use original order and the updated patch
98+ * is applied to (as far as I know) only SUSE kernels.
99+ *
100+ * Therefore, I need to use original order for SUSE 11.1 kernels and inversed
101+ * order for other kernels. I detect it by checking D_PATH_DISCONNECT and
102+ * CONFIG_SUSE_KERNEL. I don't know whether other distributions are using the
103+ * updated patch or not. If you got deadlock, check fs/dcache.c for locking
104+ * order, and add " && 0" to this "#elif " block if fs/dcache.c uses original
105+ * order.
106+ */
107+static inline void ccs_realpath_lock(void)
108+{
109+ spin_lock(ccsecurity_exports.vfsmount_lock);
110+ spin_lock(&dcache_lock);
111+}
112+
113+/**
114+ * ccs_realpath_unlock - Release locks for __d_path().
115+ *
116+ * Returns nothing.
117+ */
118+static inline void ccs_realpath_unlock(void)
119+{
120+ spin_unlock(&dcache_lock);
121+ spin_unlock(ccsecurity_exports.vfsmount_lock);
122+}
123+
124+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
125+
126+/**
127+ * ccs_realpath_lock - Take locks for __d_path().
128+ *
129+ * Returns nothing.
130+ */
131+static inline void ccs_realpath_lock(void)
132+{
133+ spin_lock(&dcache_lock);
134+ spin_lock(ccsecurity_exports.vfsmount_lock);
135+}
136+
137+/**
138+ * ccs_realpath_unlock - Release locks for __d_path().
139+ *
140+ * Returns nothing.
141+ */
142+static inline void ccs_realpath_unlock(void)
143+{
144+ spin_unlock(ccsecurity_exports.vfsmount_lock);
145+ spin_unlock(&dcache_lock);
146+}
147+
148+#else
149+
150+/**
151+ * ccs_realpath_lock - Take locks for __d_path().
152+ *
153+ * Returns nothing.
154+ */
155+static inline void ccs_realpath_lock(void)
156+{
157+ spin_lock(&dcache_lock);
158+}
159+
160+/**
161+ * ccs_realpath_unlock - Release locks for __d_path().
162+ *
163+ * Returns nothing.
164+ */
165+static inline void ccs_realpath_unlock(void)
166+{
167+ spin_unlock(&dcache_lock);
168+}
169+
170+#endif
171+
172+/**
173+ * ccs_kern_path - Wrapper for kern_path().
174+ *
175+ * @pathname: Pathname to resolve. Maybe NULL.
176+ * @flags: Lookup flags.
177+ * @path: Pointer to "struct path".
178+ *
179+ * Returns 0 on success, negative value otherwise.
180+ */
181+static int ccs_kern_path(const char *pathname, int flags, struct path *path)
182+{
183+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
184+ if (!pathname || kern_path(pathname, flags, path))
185+ return -ENOENT;
186+#else
187+ struct nameidata nd;
188+ if (!pathname || path_lookup(pathname, flags, &nd))
189+ return -ENOENT;
190+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
191+ *path = nd.path;
192+#else
193+ path->dentry = nd.dentry;
194+ path->mnt = nd.mnt;
195+#endif
196+#endif
197+ return 0;
198+}
199+
200+/**
201+ * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
202+ *
203+ * @path: Pointer to "struct path".
204+ * @buffer: Pointer to buffer to return value in.
205+ * @buflen: Sizeof @buffer.
206+ *
207+ * Returns the buffer on success, an error code otherwise.
208+ *
209+ * Caller holds the dcache_lock and vfsmount_lock.
210+ * Based on __d_path() in fs/dcache.c
211+ *
212+ * If dentry is a directory, trailing '/' is appended.
213+ */
214+static char *ccs_get_absolute_path(struct path *path, char * const buffer,
215+ const int buflen)
216+{
217+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
218+ char *pos = ERR_PTR(-ENOMEM);
219+ if (buflen >= 256) {
220+ struct path root = { };
221+ pos = ccsecurity_exports.__d_path(path, &root, buffer,
222+ buflen - 1);
223+ if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
224+ struct inode *inode = path->dentry->d_inode;
225+ if (inode && S_ISDIR(inode->i_mode)) {
226+ buffer[buflen - 2] = '/';
227+ buffer[buflen - 1] = '\0';
228+ }
229+ }
230+ }
231+ return pos;
232+#else
233+ char *pos = buffer + buflen - 1;
234+ struct dentry *dentry = path->dentry;
235+ struct vfsmount *vfsmnt = path->mnt;
236+ const char *name;
237+ int len;
238+
239+ if (buflen < 256)
240+ goto out;
241+
242+ *pos = '\0';
243+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
244+ *--pos = '/';
245+ for (;;) {
246+ struct dentry *parent;
247+ if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
248+ if (vfsmnt->mnt_parent == vfsmnt)
249+ break;
250+ dentry = vfsmnt->mnt_mountpoint;
251+ vfsmnt = vfsmnt->mnt_parent;
252+ continue;
253+ }
254+ parent = dentry->d_parent;
255+ name = dentry->d_name.name;
256+ len = dentry->d_name.len;
257+ pos -= len;
258+ if (pos <= buffer)
259+ goto out;
260+ memmove(pos, name, len);
261+ *--pos = '/';
262+ dentry = parent;
263+ }
264+ if (*pos == '/')
265+ pos++;
266+ len = dentry->d_name.len;
267+ pos -= len;
268+ if (pos < buffer)
269+ goto out;
270+ memmove(pos, dentry->d_name.name, len);
271+ return pos;
272+out:
273+ return ERR_PTR(-ENOMEM);
274+#endif
275+}
276+
277+/**
278+ * ccs_get_dentry_path - Get the path of a dentry.
279+ *
280+ * @dentry: Pointer to "struct dentry".
281+ * @buffer: Pointer to buffer to return value in.
282+ * @buflen: Sizeof @buffer.
283+ *
284+ * Returns the buffer on success, an error code otherwise.
285+ *
286+ * Based on dentry_path() in fs/dcache.c
287+ *
288+ * If dentry is a directory, trailing '/' is appended.
289+ */
290+static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
291+ const int buflen)
292+{
293+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
294+ char *pos = ERR_PTR(-ENOMEM);
295+ if (buflen >= 256) {
296+ /* rename_lock is locked/unlocked by dentry_path_raw(). */
297+ pos = dentry_path_raw(dentry, buffer, buflen - 1);
298+ if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
299+ struct inode *inode = dentry->d_inode;
300+ if (inode && S_ISDIR(inode->i_mode)) {
301+ buffer[buflen - 2] = '/';
302+ buffer[buflen - 1] = '\0';
303+ }
304+ }
305+ }
306+ return pos;
307+#else
308+ char *pos = buffer + buflen - 1;
309+ if (buflen < 256)
310+ return ERR_PTR(-ENOMEM);
311+ *pos = '\0';
312+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
313+ *--pos = '/';
314+ spin_lock(&dcache_lock);
315+ while (!IS_ROOT(dentry)) {
316+ struct dentry *parent = dentry->d_parent;
317+ const char *name = dentry->d_name.name;
318+ const int len = dentry->d_name.len;
319+ pos -= len;
320+ if (pos <= buffer) {
321+ pos = ERR_PTR(-ENOMEM);
322+ break;
323+ }
324+ memmove(pos, name, len);
325+ *--pos = '/';
326+ dentry = parent;
327+ }
328+ spin_unlock(&dcache_lock);
329+ return pos;
330+#endif
331+}
332+
333+/**
334+ * ccs_get_local_path - Get the path of a dentry.
335+ *
336+ * @dentry: Pointer to "struct dentry".
337+ * @buffer: Pointer to buffer to return value in.
338+ * @buflen: Sizeof @buffer.
339+ *
340+ * Returns the buffer on success, an error code otherwise.
341+ */
342+static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
343+ const int buflen)
344+{
345+ struct super_block *sb = dentry->d_sb;
346+ char *pos = ccs_get_dentry_path(dentry, buffer, buflen);
347+ if (IS_ERR(pos))
348+ return pos;
349+ /* Convert from $PID to self if $PID is current thread. */
350+ if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
351+ char *ep;
352+ const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
353+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
354+ if (*ep == '/' && pid && pid ==
355+ task_tgid_nr_ns(current, sb->s_fs_info)) {
356+ pos = ep - 5;
357+ if (pos < buffer)
358+ goto out;
359+ memmove(pos, "/self", 5);
360+ }
361+#else
362+ if (*ep == '/' && pid == ccs_sys_getpid()) {
363+ pos = ep - 5;
364+ if (pos < buffer)
365+ goto out;
366+ memmove(pos, "/self", 5);
367+ }
368+#endif
369+ goto prepend_filesystem_name;
370+ }
371+ /* Use filesystem name for unnamed devices. */
372+ if (!MAJOR(sb->s_dev))
373+ goto prepend_filesystem_name;
374+ {
375+ struct inode *inode = sb->s_root->d_inode;
376+ /*
377+ * Use filesystem name if filesystems does not support rename()
378+ * operation.
379+ */
380+ if (inode->i_op && !inode->i_op->rename)
381+ goto prepend_filesystem_name;
382+ }
383+ /* Prepend device name. */
384+ {
385+ char name[64];
386+ int name_len;
387+ const dev_t dev = sb->s_dev;
388+ name[sizeof(name) - 1] = '\0';
389+ snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
390+ MINOR(dev));
391+ name_len = strlen(name);
392+ pos -= name_len;
393+ if (pos < buffer)
394+ goto out;
395+ memmove(pos, name, name_len);
396+ return pos;
397+ }
398+ /* Prepend filesystem name. */
399+prepend_filesystem_name:
400+ {
401+ const char *name = sb->s_type->name;
402+ const int name_len = strlen(name);
403+ pos -= name_len + 1;
404+ if (pos < buffer)
405+ goto out;
406+ memmove(pos, name, name_len);
407+ pos[name_len] = ':';
408+ }
409+ return pos;
410+out:
411+ return ERR_PTR(-ENOMEM);
412+}
413+
414+/**
415+ * ccs_get_socket_name - Get the name of a socket.
416+ *
417+ * @path: Pointer to "struct path".
418+ * @buffer: Pointer to buffer to return value in.
419+ * @buflen: Sizeof @buffer.
420+ *
421+ * Returns the buffer.
422+ */
423+static char *ccs_get_socket_name(struct path *path, char * const buffer,
424+ const int buflen)
425+{
426+ struct inode *inode = path->dentry->d_inode;
427+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
428+ struct sock *sk = sock ? sock->sk : NULL;
429+ if (sk) {
430+ snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
431+ "protocol=%u]", sk->sk_family, sk->sk_type,
432+ sk->sk_protocol);
433+ } else {
434+ snprintf(buffer, buflen, "socket:[unknown]");
435+ }
436+ return buffer;
437+}
438+
439+#define SOCKFS_MAGIC 0x534F434B
440+
441+/**
442+ * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
443+ *
444+ * @path: Pointer to "struct path".
445+ *
446+ * Returns the realpath of the given @path on success, NULL otherwise.
447+ *
448+ * This function uses kzalloc(), so caller must kfree() if this function
449+ * didn't return NULL.
450+ */
451+char *ccs_realpath_from_path(struct path *path)
452+{
453+ char *buf = NULL;
454+ char *name = NULL;
455+ unsigned int buf_len = PAGE_SIZE / 2;
456+ struct dentry *dentry = path->dentry;
457+ struct super_block *sb;
458+ if (!dentry)
459+ return NULL;
460+ sb = dentry->d_sb;
461+ while (1) {
462+ char *pos;
463+ struct inode *inode;
464+ buf_len <<= 1;
465+ kfree(buf);
466+ buf = kmalloc(buf_len, CCS_GFP_FLAGS);
467+ if (!buf)
468+ break;
469+ /* To make sure that pos is '\0' terminated. */
470+ buf[buf_len - 1] = '\0';
471+ /* Get better name for socket. */
472+ if (sb->s_magic == SOCKFS_MAGIC) {
473+ pos = ccs_get_socket_name(path, buf, buf_len - 1);
474+ goto encode;
475+ }
476+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
477+ /* For "pipe:[\$]". */
478+ if (dentry->d_op && dentry->d_op->d_dname) {
479+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
480+ goto encode;
481+ }
482+#endif
483+ inode = sb->s_root->d_inode;
484+ /*
485+ * Get local name for filesystems without rename() operation
486+ * or dentry without vfsmount.
487+ */
488+ if (!path->mnt || (inode->i_op && !inode->i_op->rename)) {
489+ pos = ccs_get_local_path(path->dentry, buf,
490+ buf_len - 1);
491+ goto encode;
492+ }
493+ /* Get absolute name for the rest. */
494+ ccs_realpath_lock();
495+ pos = ccs_get_absolute_path(path, buf, buf_len - 1);
496+ ccs_realpath_unlock();
497+encode:
498+ if (IS_ERR(pos))
499+ continue;
500+ name = ccs_encode(pos);
501+ break;
502+ }
503+ kfree(buf);
504+ if (!name)
505+ ccs_warn_oom(__func__);
506+ return name;
507+}
508+
509+/**
510+ * ccs_symlink_path - Get symlink's pathname.
511+ *
512+ * @pathname: The pathname to solve.
513+ * @name: Pointer to "struct ccs_path_info".
514+ *
515+ * Returns 0 on success, negative value otherwise.
516+ *
517+ * This function uses kzalloc(), so caller must kfree() if this function
518+ * didn't return NULL.
519+ */
520+int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
521+{
522+ char *buf;
523+ struct path path;
524+ if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))
525+ return -ENOENT;
526+ buf = ccs_realpath_from_path(&path);
527+ path_put(&path);
528+ if (buf) {
529+ name->name = buf;
530+ ccs_fill_path_info(name);
531+ return 0;
532+ }
533+ return -ENOMEM;
534+}
535+
536+/**
537+ * ccs_encode2 - Encode binary string to ascii string.
538+ *
539+ * @str: String in binary format.
540+ * @str_len: Size of @str in byte.
541+ *
542+ * Returns pointer to @str in ascii format on success, NULL otherwise.
543+ *
544+ * This function uses kzalloc(), so caller must kfree() if this function
545+ * didn't return NULL.
546+ */
547+char *ccs_encode2(const char *str, int str_len)
548+{
549+ int i;
550+ int len = 0;
551+ const char *p = str;
552+ char *cp;
553+ char *cp0;
554+ if (!p)
555+ return NULL;
556+ for (i = 0; i < str_len; i++) {
557+ const unsigned char c = p[i];
558+ if (c == '\\')
559+ len += 2;
560+ else if (c > ' ' && c < 127)
561+ len++;
562+ else
563+ len += 4;
564+ }
565+ len++;
566+ /* Reserve space for appending "/". */
567+ cp = kzalloc(len + 10, CCS_GFP_FLAGS);
568+ if (!cp)
569+ return NULL;
570+ cp0 = cp;
571+ p = str;
572+ for (i = 0; i < str_len; i++) {
573+ const unsigned char c = p[i];
574+ if (c == '\\') {
575+ *cp++ = '\\';
576+ *cp++ = '\\';
577+ } else if (c > ' ' && c < 127) {
578+ *cp++ = c;
579+ } else {
580+ *cp++ = '\\';
581+ *cp++ = (c >> 6) + '0';
582+ *cp++ = ((c >> 3) & 7) + '0';
583+ *cp++ = (c & 7) + '0';
584+ }
585+ }
586+ return cp0;
587+}
588+
589+/**
590+ * ccs_encode - Encode binary string to ascii string.
591+ *
592+ * @str: String in binary format.
593+ *
594+ * Returns pointer to @str in ascii format on success, NULL otherwise.
595+ *
596+ * This function uses kzalloc(), so caller must kfree() if this function
597+ * didn't return NULL.
598+ */
599+char *ccs_encode(const char *str)
600+{
601+ return str ? ccs_encode2(str, strlen(str)) : NULL;
602+}
603+
604+/**
605+ * ccs_get_path - Get dentry/vfsmmount of a pathname.
606+ *
607+ * @pathname: The pathname to solve.
608+ * @path: Pointer to "struct path".
609+ *
610+ * Returns 0 on success, negative value otherwise.
611+ */
612+int ccs_get_path(const char *pathname, struct path *path)
613+{
614+ return ccs_kern_path(pathname, ccs_lookup_flags, path);
615+}
--- tags/patches/1.0.12/mount.c (nonexistent)
+++ tags/patches/1.0.12/mount.c (revision 197)
@@ -0,0 +1,300 @@
1+/*
2+ * security/ccsecurity/mount.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/* String table for special mount operations. */
12+static const char * const ccs_mounts[CCS_MAX_SPECIAL_MOUNT] = {
13+ [CCS_MOUNT_BIND] = "--bind",
14+ [CCS_MOUNT_MOVE] = "--move",
15+ [CCS_MOUNT_REMOUNT] = "--remount",
16+ [CCS_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
17+ [CCS_MOUNT_MAKE_PRIVATE] = "--make-private",
18+ [CCS_MOUNT_MAKE_SLAVE] = "--make-slave",
19+ [CCS_MOUNT_MAKE_SHARED] = "--make-shared",
20+};
21+
22+/**
23+ * ccs_audit_mount_log - Audit mount log.
24+ *
25+ * @r: Pointer to "struct ccs_request_info".
26+ *
27+ * Returns 0 on success, negative value otherwise.
28+ */
29+static int ccs_audit_mount_log(struct ccs_request_info *r)
30+{
31+ return ccs_supervisor(r, "file mount %s %s %s 0x%lX\n",
32+ r->param.mount.dev->name,
33+ r->param.mount.dir->name,
34+ r->param.mount.type->name, r->param.mount.flags);
35+}
36+
37+/**
38+ * ccs_check_mount_acl - Check permission for path path path number operation.
39+ *
40+ * @r: Pointer to "struct ccs_request_info".
41+ * @ptr: Pointer to "struct ccs_acl_info".
42+ *
43+ * Returns true if granted, false otherwise.
44+ */
45+static bool ccs_check_mount_acl(struct ccs_request_info *r,
46+ const struct ccs_acl_info *ptr)
47+{
48+ const struct ccs_mount_acl *acl =
49+ container_of(ptr, typeof(*acl), head);
50+ return ccs_compare_number_union(r->param.mount.flags, &acl->flags) &&
51+ ccs_compare_name_union(r->param.mount.type, &acl->fs_type) &&
52+ ccs_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
53+ (!r->param.mount.need_dev ||
54+ ccs_compare_name_union(r->param.mount.dev, &acl->dev_name));
55+}
56+
57+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
58+
59+/**
60+ * module_put - Put a reference on module.
61+ *
62+ * @module: Pointer to "struct module". Maybe NULL.
63+ *
64+ * Returns nothing.
65+ *
66+ * This is for compatibility with older kernels.
67+ */
68+static inline void module_put(struct module *module)
69+{
70+ if (module)
71+ __MOD_DEC_USE_COUNT(module);
72+}
73+
74+#endif
75+
76+/**
77+ * ccs_put_filesystem - Wrapper for put_filesystem().
78+ *
79+ * @fstype: Pointer to "struct file_system_type".
80+ *
81+ * Returns nothing.
82+ *
83+ * Since put_filesystem() is not exported, I embed put_filesystem() here.
84+ */
85+static inline void ccs_put_filesystem(struct file_system_type *fstype)
86+{
87+ module_put(fstype->owner);
88+}
89+
90+/**
91+ * ccs_mount_acl - Check permission for mount() operation.
92+ *
93+ * @r: Pointer to "struct ccs_request_info".
94+ * @dev_name: Name of device file.
95+ * @dir: Pointer to "struct path".
96+ * @type: Name of filesystem type.
97+ * @flags: Mount options.
98+ *
99+ * Returns 0 on success, negative value otherwise.
100+ *
101+ * Caller holds ccs_read_lock().
102+ */
103+static int ccs_mount_acl(struct ccs_request_info *r, char *dev_name,
104+ struct path *dir, const char *type,
105+ unsigned long flags)
106+{
107+ struct ccs_obj_info obj = { };
108+ struct path path;
109+ struct file_system_type *fstype = NULL;
110+ const char *requested_type = NULL;
111+ const char *requested_dir_name = NULL;
112+ const char *requested_dev_name = NULL;
113+ struct ccs_path_info rtype;
114+ struct ccs_path_info rdev;
115+ struct ccs_path_info rdir;
116+ int need_dev = 0;
117+ int error = -ENOMEM;
118+ r->obj = &obj;
119+
120+ /* Get fstype. */
121+ requested_type = ccs_encode(type);
122+ if (!requested_type)
123+ goto out;
124+ rtype.name = requested_type;
125+ ccs_fill_path_info(&rtype);
126+
127+ /* Get mount point. */
128+ obj.path2 = *dir;
129+ requested_dir_name = ccs_realpath_from_path(dir);
130+ if (!requested_dir_name) {
131+ error = -ENOMEM;
132+ goto out;
133+ }
134+ rdir.name = requested_dir_name;
135+ ccs_fill_path_info(&rdir);
136+
137+ /* Compare fs name. */
138+ if (type == ccs_mounts[CCS_MOUNT_REMOUNT]) {
139+ /* dev_name is ignored. */
140+ } else if (type == ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE] ||
141+ type == ccs_mounts[CCS_MOUNT_MAKE_PRIVATE] ||
142+ type == ccs_mounts[CCS_MOUNT_MAKE_SLAVE] ||
143+ type == ccs_mounts[CCS_MOUNT_MAKE_SHARED]) {
144+ /* dev_name is ignored. */
145+ } else if (type == ccs_mounts[CCS_MOUNT_BIND] ||
146+ type == ccs_mounts[CCS_MOUNT_MOVE]) {
147+ need_dev = -1; /* dev_name is a directory */
148+ } else {
149+ fstype = get_fs_type(type);
150+ if (!fstype) {
151+ error = -ENODEV;
152+ goto out;
153+ }
154+ if (fstype->fs_flags & FS_REQUIRES_DEV)
155+ /* dev_name is a block device file. */
156+ need_dev = 1;
157+ }
158+ if (need_dev) {
159+ /* Get mount point or device file. */
160+ if (ccs_get_path(dev_name, &path)) {
161+ error = -ENOENT;
162+ goto out;
163+ }
164+ obj.path1 = path;
165+ requested_dev_name = ccs_realpath_from_path(&path);
166+ if (!requested_dev_name) {
167+ error = -ENOENT;
168+ goto out;
169+ }
170+ } else {
171+ /* Map dev_name to "<NULL>" if no dev_name given. */
172+ if (!dev_name)
173+ dev_name = "<NULL>";
174+ requested_dev_name = ccs_encode(dev_name);
175+ if (!requested_dev_name) {
176+ error = -ENOMEM;
177+ goto out;
178+ }
179+ }
180+ rdev.name = requested_dev_name;
181+ ccs_fill_path_info(&rdev);
182+ r->param_type = CCS_TYPE_MOUNT_ACL;
183+ r->param.mount.need_dev = need_dev;
184+ r->param.mount.dev = &rdev;
185+ r->param.mount.dir = &rdir;
186+ r->param.mount.type = &rtype;
187+ r->param.mount.flags = flags;
188+ do {
189+ ccs_check_acl(r, ccs_check_mount_acl);
190+ error = ccs_audit_mount_log(r);
191+ } while (error == CCS_RETRY_REQUEST);
192+out:
193+ kfree(requested_dev_name);
194+ kfree(requested_dir_name);
195+ if (fstype)
196+ ccs_put_filesystem(fstype);
197+ kfree(requested_type);
198+ /* Drop refcount obtained by ccs_get_path(). */
199+ if (obj.path1.dentry)
200+ path_put(&obj.path1);
201+ return error;
202+}
203+
204+/**
205+ * __ccs_mount_permission - Check permission for mount() operation.
206+ *
207+ * @dev_name: Name of device file.
208+ * @path: Pointer to "struct path".
209+ * @type: Name of filesystem type. Maybe NULL.
210+ * @flags: Mount options.
211+ * @data_page: Optional data. Maybe NULL.
212+ *
213+ * Returns 0 on success, negative value otherwise.
214+ */
215+static int __ccs_mount_permission(char *dev_name, struct path *path,
216+ const char *type, unsigned long flags,
217+ void *data_page)
218+{
219+ struct ccs_request_info r;
220+ int error = 0;
221+ int idx;
222+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
223+ flags &= ~MS_MGC_MSK;
224+ if (flags & MS_REMOUNT) {
225+ type = ccs_mounts[CCS_MOUNT_REMOUNT];
226+ flags &= ~MS_REMOUNT;
227+ }
228+ if (flags & MS_MOVE) {
229+ type = ccs_mounts[CCS_MOUNT_MOVE];
230+ flags &= ~MS_MOVE;
231+ }
232+ if (flags & MS_BIND) {
233+ type = ccs_mounts[CCS_MOUNT_BIND];
234+ flags &= ~MS_BIND;
235+ }
236+ if (flags & MS_UNBINDABLE) {
237+ type = ccs_mounts[CCS_MOUNT_MAKE_UNBINDABLE];
238+ flags &= ~MS_UNBINDABLE;
239+ }
240+ if (flags & MS_PRIVATE) {
241+ type = ccs_mounts[CCS_MOUNT_MAKE_PRIVATE];
242+ flags &= ~MS_PRIVATE;
243+ }
244+ if (flags & MS_SLAVE) {
245+ type = ccs_mounts[CCS_MOUNT_MAKE_SLAVE];
246+ flags &= ~MS_SLAVE;
247+ }
248+ if (flags & MS_SHARED) {
249+ type = ccs_mounts[CCS_MOUNT_MAKE_SHARED];
250+ flags &= ~MS_SHARED;
251+ }
252+ if (!type)
253+ type = "<NULL>";
254+ idx = ccs_read_lock();
255+ if (ccs_init_request_info(&r, CCS_MAC_FILE_MOUNT)
256+ != CCS_CONFIG_DISABLED)
257+ error = ccs_mount_acl(&r, dev_name, path, type, flags);
258+ ccs_read_unlock(idx);
259+ return error;
260+}
261+
262+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
263+
264+/**
265+ * ccs_old_mount_permission - Check permission for mount() operation.
266+ *
267+ * @dev_name: Name of device file.
268+ * @nd: Pointer to "struct nameidata".
269+ * @type: Name of filesystem type. Maybe NULL.
270+ * @flags: Mount options.
271+ * @data_page: Optional data. Maybe NULL.
272+ *
273+ * Returns 0 on success, negative value otherwise.
274+ */
275+static int ccs_old_mount_permission(char *dev_name, struct nameidata *nd,
276+ const char *type, unsigned long flags,
277+ void *data_page)
278+{
279+ struct path path = { nd->mnt, nd->dentry };
280+ return __ccs_mount_permission(dev_name, &path, type, flags, data_page);
281+}
282+
283+#endif
284+
285+/**
286+ * ccs_mount_init - Register hooks for mount() operation.
287+ *
288+ * Returns nothing.
289+ *
290+ * Since checking permission for mount() operation is complicated compared to
291+ * other file related operations, I split code for mount() operation.
292+ */
293+void __init ccs_mount_init(void)
294+{
295+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
296+ ccsecurity_ops.mount_permission = __ccs_mount_permission;
297+#else
298+ ccsecurity_ops.mount_permission = ccs_old_mount_permission;
299+#endif
300+}
--- tags/patches/1.0.12/autobind.c (nonexistent)
+++ tags/patches/1.0.12/autobind.c (revision 197)
@@ -0,0 +1,116 @@
1+/*
2+ * security/ccsecurity/autobind.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/* Bitmap for reserved local port numbers.*/
12+static u8 ccs_reserved_port_map[8192];
13+
14+/**
15+ * ccs_lport_reserved - Check whether local port is reserved or not.
16+ *
17+ * @port: Port number.
18+ *
19+ * Returns true if local port is reserved, false otherwise.
20+ */
21+static bool __ccs_lport_reserved(const u16 port)
22+{
23+ return ccs_reserved_port_map[port >> 3] & (1 << (port & 7))
24+ ? true : false;
25+}
26+
27+/**
28+ * ccs_same_reserved - Check for duplicated "struct ccs_reserved" entry.
29+ *
30+ * @a: Pointer to "struct ccs_acl_head".
31+ * @b: Pointer to "struct ccs_acl_head".
32+ *
33+ * Returns true if @a == @b, false otherwise.
34+ */
35+static bool ccs_same_reserved(const struct ccs_acl_head *a,
36+ const struct ccs_acl_head *b)
37+{
38+ const struct ccs_reserved *p1 = container_of(a, typeof(*p1), head);
39+ const struct ccs_reserved *p2 = container_of(b, typeof(*p2), head);
40+ return p1->min_port == p2->min_port && p1->max_port == p2->max_port;
41+}
42+
43+/**
44+ * ccs_update_reserved_entry - Update "struct ccs_reserved" list.
45+ *
46+ * @min_port: Start of port number range.
47+ * @max_port: End of port number range.
48+ * @is_delete: True if it is a delete request.
49+ *
50+ * Returns 0 on success, negative value otherwise.
51+ *
52+ * Caller holds ccs_read_lock().
53+ */
54+static int ccs_update_reserved_entry(const u16 min_port, const u16 max_port,
55+ const bool is_delete)
56+{
57+ struct ccs_reserved *ptr;
58+ struct ccs_reserved e = {
59+ .min_port = min_port,
60+ .max_port = max_port
61+ };
62+ const int error =
63+ ccs_update_policy(&e.head, sizeof(e), is_delete,
64+ &ccs_policy_list[CCS_ID_RESERVEDPORT],
65+ ccs_same_reserved);
66+ u8 *tmp;
67+ if (error)
68+ return error;
69+ tmp = kzalloc(sizeof(ccs_reserved_port_map), CCS_GFP_FLAGS);
70+ if (!tmp)
71+ return -ENOMEM;
72+ list_for_each_entry_srcu(ptr, &ccs_policy_list[CCS_ID_RESERVEDPORT],
73+ head.list, &ccs_ss) {
74+ unsigned int port;
75+ if (ptr->head.is_deleted)
76+ continue;
77+ for (port = ptr->min_port; port <= ptr->max_port; port++)
78+ tmp[port >> 3] |= 1 << (port & 7);
79+ }
80+ memmove(ccs_reserved_port_map, tmp, sizeof(ccs_reserved_port_map));
81+ kfree(tmp);
82+ /*
83+ * Since this feature is no-op by default, we don't need to register
84+ * this callback hook unless the first entry is added.
85+ */
86+ ccsecurity_ops.lport_reserved = __ccs_lport_reserved;
87+ return 0;
88+}
89+
90+/**
91+ * ccs_write_reserved_port - Write "struct ccs_reserved" list.
92+ *
93+ * @data: String to parse.
94+ * @is_delete: True if it is a delete request.
95+ *
96+ * Returns 0 on success, negative value otherwise.
97+ */
98+int ccs_write_reserved_port(char *data, const bool is_delete)
99+{
100+ unsigned int from;
101+ unsigned int to;
102+ if (strchr(data, ' '))
103+ goto out;
104+ switch (sscanf(data, "%u-%u", &from, &to)) {
105+ case 1:
106+ to = from;
107+ /* fall through */
108+ case 2:
109+ if (from <= to && to < 65536)
110+ return ccs_update_reserved_entry(from, to,
111+ is_delete);
112+ break;
113+ }
114+out:
115+ return -EINVAL;
116+}
--- tags/patches/1.0.12/audit.c (nonexistent)
+++ tags/patches/1.0.12/audit.c (revision 197)
@@ -0,0 +1,532 @@
1+/*
2+ * security/ccsecurity/audit.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
12+
13+/**
14+ * fatal_signal_pending - Check whether SIGKILL is pending or not.
15+ *
16+ * @p: Pointer to "struct task_struct".
17+ *
18+ * Returns true if SIGKILL is pending on @p, false otherwise.
19+ *
20+ * This is for compatibility with older kernels.
21+ */
22+#define fatal_signal_pending(p) (signal_pending(p) && \
23+ sigismember(&p->pending.signal, SIGKILL))
24+
25+#endif
26+
27+/**
28+ * ccs_print_bprm - Print "struct linux_binprm" for auditing.
29+ *
30+ * @bprm: Pointer to "struct linux_binprm".
31+ * @dump: Pointer to "struct ccs_page_dump".
32+ *
33+ * Returns the contents of @bprm on success, NULL otherwise.
34+ *
35+ * This function uses kzalloc(), so caller must kfree() if this function
36+ * didn't return NULL.
37+ */
38+static char *ccs_print_bprm(struct linux_binprm *bprm,
39+ struct ccs_page_dump *dump)
40+{
41+ static const int ccs_buffer_len = 4096 * 2;
42+ char *buffer = kzalloc(ccs_buffer_len, CCS_GFP_FLAGS);
43+ char *cp;
44+ char *last_start;
45+ int len;
46+ unsigned long pos = bprm->p;
47+ int offset = pos % PAGE_SIZE;
48+ int argv_count = bprm->argc;
49+ int envp_count = bprm->envc;
50+ bool truncated = false;
51+ if (!buffer)
52+ return NULL;
53+ len = snprintf(buffer, ccs_buffer_len - 1, "argv[]={ ");
54+ cp = buffer + len;
55+ if (!argv_count) {
56+ memmove(cp, "} envp[]={ ", 11);
57+ cp += 11;
58+ }
59+ last_start = cp;
60+ while (argv_count || envp_count) {
61+ if (!ccs_dump_page(bprm, pos, dump))
62+ goto out;
63+ pos += PAGE_SIZE - offset;
64+ /* Read. */
65+ while (offset < PAGE_SIZE) {
66+ const char *kaddr = dump->data;
67+ const unsigned char c = kaddr[offset++];
68+ if (cp == last_start)
69+ *cp++ = '"';
70+ if (cp >= buffer + ccs_buffer_len - 32) {
71+ /* Reserve some room for "..." string. */
72+ truncated = true;
73+ } else if (c == '\\') {
74+ *cp++ = '\\';
75+ *cp++ = '\\';
76+ } else if (c > ' ' && c < 127) {
77+ *cp++ = c;
78+ } else if (!c) {
79+ *cp++ = '"';
80+ *cp++ = ' ';
81+ last_start = cp;
82+ } else {
83+ *cp++ = '\\';
84+ *cp++ = (c >> 6) + '0';
85+ *cp++ = ((c >> 3) & 7) + '0';
86+ *cp++ = (c & 7) + '0';
87+ }
88+ if (c)
89+ continue;
90+ if (argv_count) {
91+ if (--argv_count == 0) {
92+ if (truncated) {
93+ cp = last_start;
94+ memmove(cp, "... ", 4);
95+ cp += 4;
96+ }
97+ memmove(cp, "} envp[]={ ", 11);
98+ cp += 11;
99+ last_start = cp;
100+ truncated = false;
101+ }
102+ } else if (envp_count) {
103+ if (--envp_count == 0) {
104+ if (truncated) {
105+ cp = last_start;
106+ memmove(cp, "... ", 4);
107+ cp += 4;
108+ }
109+ }
110+ }
111+ if (!argv_count && !envp_count)
112+ break;
113+ }
114+ offset = 0;
115+ }
116+ *cp++ = '}';
117+ *cp = '\0';
118+ return buffer;
119+out:
120+ snprintf(buffer, ccs_buffer_len - 1, "argv[]={ ... } envp[]= { ... }");
121+ return buffer;
122+}
123+
124+/**
125+ * ccs_filetype - Get string representation of file type.
126+ *
127+ * @mode: Mode value for stat().
128+ *
129+ * Returns file type string.
130+ */
131+static inline const char *ccs_filetype(const mode_t mode)
132+{
133+ switch (mode & S_IFMT) {
134+ case S_IFREG:
135+ case 0:
136+ return ccs_condition_keyword[CCS_TYPE_IS_FILE];
137+ case S_IFDIR:
138+ return ccs_condition_keyword[CCS_TYPE_IS_DIRECTORY];
139+ case S_IFLNK:
140+ return ccs_condition_keyword[CCS_TYPE_IS_SYMLINK];
141+ case S_IFIFO:
142+ return ccs_condition_keyword[CCS_TYPE_IS_FIFO];
143+ case S_IFSOCK:
144+ return ccs_condition_keyword[CCS_TYPE_IS_SOCKET];
145+ case S_IFBLK:
146+ return ccs_condition_keyword[CCS_TYPE_IS_BLOCK_DEV];
147+ case S_IFCHR:
148+ return ccs_condition_keyword[CCS_TYPE_IS_CHAR_DEV];
149+ }
150+ return "unknown"; /* This should not happen. */
151+}
152+
153+/**
154+ * ccs_print_header - Get header line of audit log.
155+ *
156+ * @r: Pointer to "struct ccs_request_info".
157+ *
158+ * Returns string representation.
159+ *
160+ * This function uses kmalloc(), so caller must kfree() if this function
161+ * didn't return NULL.
162+ */
163+static char *ccs_print_header(struct ccs_request_info *r)
164+{
165+ struct ccs_time stamp;
166+ struct ccs_obj_info *obj = r->obj;
167+ const u32 ccs_flags = ccs_current_flags();
168+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
169+ const pid_t gpid = ccs_sys_getpid();
170+#else
171+ const pid_t gpid = task_pid_nr(current);
172+#endif
173+ static const int ccs_buffer_len = 4096;
174+ char *buffer = kmalloc(ccs_buffer_len, CCS_GFP_FLAGS);
175+ int pos;
176+ u8 i;
177+ if (!buffer)
178+ return NULL;
179+ {
180+ struct timeval tv;
181+ do_gettimeofday(&tv);
182+ ccs_convert_time(tv.tv_sec, &stamp);
183+ }
184+ pos = snprintf(buffer, ccs_buffer_len - 1,
185+ "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
186+ "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
187+ "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
188+ "fsuid=%u fsgid=%u type%s=execute_handler }",
189+ stamp.year, stamp.month, stamp.day, stamp.hour,
190+ stamp.min, stamp.sec, r->profile, ccs_mode[r->mode],
191+ ccs_yesno(r->granted), gpid, ccs_sys_getpid(),
192+ ccs_sys_getppid(), current_uid(), current_gid(),
193+ current_euid(), current_egid(), current_suid(),
194+ current_sgid(), current_fsuid(), current_fsgid(),
195+ ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER ? "" : "!");
196+ if (!obj)
197+ goto no_obj_info;
198+ if (!obj->validate_done) {
199+ ccs_get_attributes(obj);
200+ obj->validate_done = true;
201+ }
202+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
203+ struct ccs_mini_stat *stat;
204+ unsigned int dev;
205+ mode_t mode;
206+ if (!obj->stat_valid[i])
207+ continue;
208+ stat = &obj->stat[i];
209+ dev = stat->dev;
210+ mode = stat->mode;
211+ if (i & 1) {
212+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
213+ " path%u.parent={ uid=%u gid=%u "
214+ "ino=%lu perm=0%o }", (i >> 1) + 1,
215+ stat->uid, stat->gid, (unsigned long)
216+ stat->ino, stat->mode & S_IALLUGO);
217+ continue;
218+ }
219+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
220+ " path%u={ uid=%u gid=%u ino=%lu major=%u"
221+ " minor=%u perm=0%o type=%s", (i >> 1) + 1,
222+ stat->uid, stat->gid, (unsigned long)
223+ stat->ino, MAJOR(dev), MINOR(dev),
224+ mode & S_IALLUGO, ccs_filetype(mode));
225+ if (S_ISCHR(mode) || S_ISBLK(mode)) {
226+ dev = stat->rdev;
227+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos,
228+ " dev_major=%u dev_minor=%u",
229+ MAJOR(dev), MINOR(dev));
230+ }
231+ pos += snprintf(buffer + pos, ccs_buffer_len - 1 - pos, " }");
232+ }
233+no_obj_info:
234+ if (pos < ccs_buffer_len - 1)
235+ return buffer;
236+ kfree(buffer);
237+ return NULL;
238+}
239+
240+/**
241+ * ccs_init_log - Allocate buffer for audit logs.
242+ *
243+ * @r: Pointer to "struct ccs_request_info".
244+ * @len: Buffer size needed for @fmt and @args.
245+ * @fmt: The printf()'s format string.
246+ * @args: va_list structure for @fmt.
247+ *
248+ * Returns pointer to allocated memory.
249+ *
250+ * This function uses kzalloc(), so caller must kfree() if this function
251+ * didn't return NULL.
252+ */
253+char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt,
254+ va_list args)
255+{
256+ char *buf = NULL;
257+ char *bprm_info = NULL;
258+ char *realpath = NULL;
259+ const char *symlink = NULL;
260+ const char *header = NULL;
261+ int pos;
262+ const char *domainname = ccs_current_domain()->domainname->name;
263+ header = ccs_print_header(r);
264+ if (!header)
265+ return NULL;
266+ /* +10 is for '\n' etc. and '\0'. */
267+ len += strlen(domainname) + strlen(header) + 10;
268+ if (r->ee) {
269+ struct file *file = r->ee->bprm->file;
270+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
271+ struct path path = { file->f_vfsmnt, file->f_dentry };
272+ realpath = ccs_realpath_from_path(&path);
273+#else
274+ realpath = ccs_realpath_from_path(&file->f_path);
275+#endif
276+ bprm_info = ccs_print_bprm(r->ee->bprm, &r->ee->dump);
277+ if (!realpath || !bprm_info)
278+ goto out;
279+ /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
280+ len += strlen(realpath) + 80 + strlen(bprm_info);
281+ } else if (r->obj && r->obj->symlink_target) {
282+ symlink = r->obj->symlink_target->name;
283+ /* +18 is for " symlink.target=\"%s\"" */
284+ len += 18 + strlen(symlink);
285+ }
286+ len = ccs_round2(len);
287+ buf = kzalloc(len, CCS_GFP_FLAGS);
288+ if (!buf)
289+ goto out;
290+ len--;
291+ pos = snprintf(buf, len, "%s", header);
292+ if (realpath) {
293+ struct linux_binprm *bprm = r->ee->bprm;
294+ pos += snprintf(buf + pos, len - pos,
295+ " exec={ realpath=\"%s\" argc=%d envc=%d %s }",
296+ realpath, bprm->argc, bprm->envc, bprm_info);
297+ } else if (symlink)
298+ pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
299+ symlink);
300+ pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
301+ vsnprintf(buf + pos, len - pos, fmt, args);
302+out:
303+ kfree(realpath);
304+ kfree(bprm_info);
305+ kfree(header);
306+ return buf;
307+}
308+
309+/**
310+ * ccs_transition_failed - Print waning message and send signal when domain transition failed.
311+ *
312+ * @domainname: Name of domain to transit.
313+ *
314+ * Returns nothing.
315+ *
316+ * Note that if current->pid == 1, sending SIGKILL won't work.
317+ */
318+void ccs_transition_failed(const char *domainname)
319+{
320+ printk(KERN_WARNING
321+ "ERROR: Unable to transit to '%s' domain.\n", domainname);
322+ force_sig(SIGKILL, current);
323+}
324+
325+/**
326+ * ccs_update_task_domain - Update task's domain.
327+ *
328+ * @r: Pointer to "struct ccs_request_info".
329+ *
330+ * Returns nothing.
331+ *
332+ * The task will retry as hard as possible. But if domain transition failed,
333+ * the task will be killed by SIGKILL.
334+ */
335+static void ccs_update_task_domain(struct ccs_request_info *r)
336+{
337+ const struct ccs_domain_info *domain;
338+ char *buf;
339+ const struct ccs_acl_info *acl = r->matched_acl;
340+ r->matched_acl = NULL;
341+ if (!acl || !acl->cond || !acl->cond->transit)
342+ return;
343+ while (1) {
344+ buf = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
345+ if (buf)
346+ break;
347+ ssleep(1);
348+ if (fatal_signal_pending(current))
349+ return;
350+ }
351+ domain = ccs_current_domain();
352+ snprintf(buf, CCS_EXEC_TMPSIZE - 1, "%s %s", domain->domainname->name,
353+ acl->cond->transit->name);
354+ if (!ccs_assign_domain(buf, r->profile, domain->group, true))
355+ ccs_transition_failed(buf);
356+ kfree(buf);
357+}
358+
359+/* Wait queue for /proc/ccs/audit. */
360+static DECLARE_WAIT_QUEUE_HEAD(ccs_log_wait);
361+
362+/* Structure for audit log. */
363+struct ccs_log {
364+ struct list_head list;
365+ char *log;
366+ int size;
367+};
368+
369+/* The list for "struct ccs_log". */
370+static LIST_HEAD(ccs_log);
371+
372+/* Lock for "struct list_head ccs_log". */
373+static DEFINE_SPINLOCK(ccs_log_lock);
374+
375+/* Length of "stuct list_head ccs_log". */
376+static unsigned int ccs_log_count;
377+
378+/**
379+ * ccs_get_audit - Get audit mode.
380+ *
381+ * @profile: Profile number.
382+ * @index: Index number of functionality.
383+ * @matched_acl: Pointer to "struct ccs_acl_info". Maybe NULL.
384+ * @is_granted: True if granted log, false otherwise.
385+ *
386+ * Returns true if this request should be audited, false otherwise.
387+ */
388+static bool ccs_get_audit(const u8 profile, const u8 index,
389+ const struct ccs_acl_info *matched_acl,
390+ const bool is_granted)
391+{
392+ u8 mode;
393+ const u8 category = ccs_index2category[index] + CCS_MAX_MAC_INDEX;
394+ struct ccs_profile *p;
395+ if (!ccs_policy_loaded)
396+ return false;
397+ p = ccs_profile(profile);
398+ if (ccs_log_count >= p->pref[CCS_PREF_MAX_AUDIT_LOG])
399+ return false;
400+ if (is_granted && matched_acl && matched_acl->cond &&
401+ matched_acl->cond->grant_log != CCS_GRANTLOG_AUTO)
402+ return matched_acl->cond->grant_log == CCS_GRANTLOG_YES;
403+ mode = p->config[index];
404+ if (mode == CCS_CONFIG_USE_DEFAULT)
405+ mode = p->config[category];
406+ if (mode == CCS_CONFIG_USE_DEFAULT)
407+ mode = p->default_config;
408+ if (is_granted)
409+ return mode & CCS_CONFIG_WANT_GRANT_LOG;
410+ return mode & CCS_CONFIG_WANT_REJECT_LOG;
411+}
412+
413+/**
414+ * ccs_write_log2 - Write an audit log.
415+ *
416+ * @r: Pointer to "struct ccs_request_info".
417+ * @len: Buffer size needed for @fmt and @args.
418+ * @fmt: The printf()'s format string.
419+ * @args: va_list structure for @fmt.
420+ *
421+ * Returns nothing.
422+ */
423+void ccs_write_log2(struct ccs_request_info *r, int len, const char *fmt,
424+ va_list args)
425+{
426+ char *buf;
427+ struct ccs_log *entry;
428+ bool quota_exceeded = false;
429+ if (!ccs_get_audit(r->profile, r->type, r->matched_acl, r->granted))
430+ goto out;
431+ buf = ccs_init_log(r, len, fmt, args);
432+ if (!buf)
433+ goto out;
434+ entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
435+ if (!entry) {
436+ kfree(buf);
437+ goto out;
438+ }
439+ entry->log = buf;
440+ len = ccs_round2(strlen(buf) + 1);
441+ /*
442+ * The entry->size is used for memory quota checks.
443+ * Don't go beyond strlen(entry->log).
444+ */
445+ entry->size = len + ccs_round2(sizeof(*entry));
446+ spin_lock(&ccs_log_lock);
447+ if (ccs_memory_quota[CCS_MEMORY_AUDIT] &&
448+ ccs_memory_used[CCS_MEMORY_AUDIT] + entry->size >=
449+ ccs_memory_quota[CCS_MEMORY_AUDIT]) {
450+ quota_exceeded = true;
451+ } else {
452+ ccs_memory_used[CCS_MEMORY_AUDIT] += entry->size;
453+ list_add_tail(&entry->list, &ccs_log);
454+ ccs_log_count++;
455+ }
456+ spin_unlock(&ccs_log_lock);
457+ if (quota_exceeded) {
458+ kfree(buf);
459+ kfree(entry);
460+ goto out;
461+ }
462+ wake_up(&ccs_log_wait);
463+out:
464+ ccs_update_task_domain(r);
465+}
466+
467+/**
468+ * ccs_write_log - Write an audit log.
469+ *
470+ * @r: Pointer to "struct ccs_request_info".
471+ * @fmt: The printf()'s format string, followed by parameters.
472+ *
473+ * Returns nothing.
474+ */
475+void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...)
476+{
477+ va_list args;
478+ int len;
479+ va_start(args, fmt);
480+ len = vsnprintf((char *) &len, 1, fmt, args) + 1;
481+ va_end(args);
482+ va_start(args, fmt);
483+ ccs_write_log2(r, len, fmt, args);
484+ va_end(args);
485+}
486+
487+/**
488+ * ccs_read_log - Read an audit log.
489+ *
490+ * @head: Pointer to "struct ccs_io_buffer".
491+ *
492+ * Returns nothing.
493+ */
494+void ccs_read_log(struct ccs_io_buffer *head)
495+{
496+ struct ccs_log *ptr = NULL;
497+ if (head->r.w_pos)
498+ return;
499+ kfree(head->read_buf);
500+ head->read_buf = NULL;
501+ spin_lock(&ccs_log_lock);
502+ if (!list_empty(&ccs_log)) {
503+ ptr = list_entry(ccs_log.next, typeof(*ptr), list);
504+ list_del(&ptr->list);
505+ ccs_log_count--;
506+ ccs_memory_used[CCS_MEMORY_AUDIT] -= ptr->size;
507+ }
508+ spin_unlock(&ccs_log_lock);
509+ if (ptr) {
510+ head->read_buf = ptr->log;
511+ head->r.w[head->r.w_pos++] = head->read_buf;
512+ kfree(ptr);
513+ }
514+}
515+
516+/**
517+ * ccs_poll_log - Wait for an audit log.
518+ *
519+ * @file: Pointer to "struct file".
520+ * @wait: Pointer to "poll_table".
521+ *
522+ * Returns POLLIN | POLLRDNORM when ready to read an audit log.
523+ */
524+int ccs_poll_log(struct file *file, poll_table *wait)
525+{
526+ if (ccs_log_count)
527+ return POLLIN | POLLRDNORM;
528+ poll_wait(file, &ccs_log_wait, wait);
529+ if (ccs_log_count)
530+ return POLLIN | POLLRDNORM;
531+ return 0;
532+}
--- tags/patches/1.0.12/domain.c (nonexistent)
+++ tags/patches/1.0.12/domain.c (revision 197)
@@ -0,0 +1,1261 @@
1+/*
2+ * security/ccsecurity/domain.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/*
12+ * The global domains referred by "use_group" keyword.
13+ *
14+ * Although "use_group" needs only "struct list_head acl_info_list[2]",
15+ * we define structure for "use_group" as "struct ccs_domain_info" in order to
16+ * use common code.
17+ */
18+struct ccs_domain_info ccs_acl_group[CCS_MAX_ACL_GROUPS];
19+
20+/* The initial domain. */
21+struct ccs_domain_info ccs_kernel_domain;
22+
23+/* The list for "struct ccs_domain_info". */
24+LIST_HEAD(ccs_domain_list);
25+
26+/* List of domain policy. */
27+struct list_head ccs_policy_list[CCS_MAX_POLICY];
28+/* List of "struct ccs_group". */
29+struct list_head ccs_group_list[CCS_MAX_GROUP];
30+/* List of "struct ccs_condition" and "struct ccs_ipv6addr". */
31+struct list_head ccs_shared_list[CCS_MAX_LIST];
32+
33+/**
34+ * ccs_update_policy - Update an entry for exception policy.
35+ *
36+ * @new_entry: Pointer to "struct ccs_acl_info".
37+ * @size: Size of @new_entry in bytes.
38+ * @is_delete: True if it is a delete request.
39+ * @list: Pointer to "struct list_head".
40+ * @check_duplicate: Callback function to find duplicated entry.
41+ *
42+ * Returns 0 on success, negative value otherwise.
43+ *
44+ * Caller holds ccs_read_lock().
45+ */
46+int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
47+ bool is_delete, struct list_head *list,
48+ bool (*check_duplicate) (const struct ccs_acl_head *,
49+ const struct ccs_acl_head *))
50+{
51+ int error = is_delete ? -ENOENT : -ENOMEM;
52+ struct ccs_acl_head *entry;
53+ if (mutex_lock_interruptible(&ccs_policy_lock))
54+ return -ENOMEM;
55+ list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
56+ if (!check_duplicate(entry, new_entry))
57+ continue;
58+ entry->is_deleted = is_delete;
59+ error = 0;
60+ break;
61+ }
62+ if (error && !is_delete) {
63+ entry = ccs_commit_ok(new_entry, size);
64+ if (entry) {
65+ list_add_tail_rcu(&entry->list, list);
66+ error = 0;
67+ }
68+ }
69+ mutex_unlock(&ccs_policy_lock);
70+ return error;
71+}
72+
73+/**
74+ * ccs_same_acl_head - Check for duplicated "struct ccs_acl_info" entry.
75+ *
76+ * @a: Pointer to "struct ccs_acl_info".
77+ * @b: Pointer to "struct ccs_acl_info".
78+ *
79+ * Returns true if @a == @b, false otherwise.
80+ */
81+static inline bool ccs_same_acl_head(const struct ccs_acl_info *a,
82+ const struct ccs_acl_info *b)
83+{
84+ return a->type == b->type && a->cond == b->cond;
85+}
86+
87+/**
88+ * ccs_update_domain - Update an entry for domain policy.
89+ *
90+ * @new_entry: Pointer to "struct ccs_acl_info".
91+ * @size: Size of @new_entry in bytes.
92+ * @param: Pointer to "struct ccs_acl_param".
93+ * @check_duplicate: Callback function to find duplicated entry.
94+ * @merge_duplicate: Callback function to merge duplicated entry. Maybe NULL.
95+ *
96+ * Returns 0 on success, negative value otherwise.
97+ *
98+ * Caller holds ccs_read_lock().
99+ */
100+int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
101+ struct ccs_acl_param *param,
102+ bool (*check_duplicate) (const struct ccs_acl_info *,
103+ const struct ccs_acl_info *),
104+ bool (*merge_duplicate) (struct ccs_acl_info *,
105+ struct ccs_acl_info *,
106+ const bool))
107+{
108+ int error = param->is_delete ? -ENOENT : -ENOMEM;
109+ struct ccs_acl_info *entry;
110+ const u8 type = new_entry->type;
111+ const u8 i = type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
112+ type == CCS_TYPE_DENIED_EXECUTE_HANDLER ||
113+ type == CCS_TYPE_AUTO_TASK_ACL;
114+ const bool is_delete = param->is_delete;
115+ struct ccs_domain_info * const domain = param->domain;
116+ if (param->data[0]) {
117+ new_entry->cond = ccs_get_condition(param->data);
118+ if (!new_entry->cond)
119+ return -EINVAL;
120+ }
121+ if (mutex_lock_interruptible(&ccs_policy_lock))
122+ goto out;
123+ list_for_each_entry_srcu(entry, &domain->acl_info_list[i], list,
124+ &ccs_ss) {
125+ if (!ccs_same_acl_head(entry, new_entry) ||
126+ !check_duplicate(entry, new_entry))
127+ continue;
128+ if (merge_duplicate)
129+ entry->is_deleted = merge_duplicate(entry, new_entry,
130+ is_delete);
131+ else
132+ entry->is_deleted = is_delete;
133+ error = 0;
134+ break;
135+ }
136+ if (error && !is_delete) {
137+ entry = ccs_commit_ok(new_entry, size);
138+ if (entry) {
139+ list_add_tail_rcu(&entry->list,
140+ &domain->acl_info_list[i]);
141+ error = 0;
142+ }
143+ }
144+ mutex_unlock(&ccs_policy_lock);
145+out:
146+ ccs_put_condition(new_entry->cond);
147+ return error;
148+}
149+
150+/**
151+ * ccs_check_acl - Do permission check.
152+ *
153+ * @r: Pointer to "struct ccs_request_info".
154+ * @check_entry: Callback function to check type specific parameters.
155+ * Maybe NULL.
156+ *
157+ * Returns 0 on success, negative value otherwise.
158+ *
159+ * Caller holds ccs_read_lock().
160+ */
161+void ccs_check_acl(struct ccs_request_info *r,
162+ bool (*check_entry) (struct ccs_request_info *,
163+ const struct ccs_acl_info *))
164+{
165+ const struct ccs_domain_info *domain = ccs_current_domain();
166+ struct ccs_acl_info *ptr;
167+ bool retried = false;
168+ const u8 i = !check_entry;
169+retry:
170+ list_for_each_entry_srcu(ptr, &domain->acl_info_list[i], list,
171+ &ccs_ss) {
172+ if (ptr->is_deleted)
173+ continue;
174+ if (ptr->type != r->param_type)
175+ continue;
176+ if (check_entry && !check_entry(r, ptr))
177+ continue;
178+ if (!ccs_condition(r, ptr->cond))
179+ continue;
180+ r->matched_acl = ptr;
181+ r->granted = true;
182+ return;
183+ }
184+ if (!retried) {
185+ retried = true;
186+ domain = &ccs_acl_group[domain->group];
187+ goto retry;
188+ }
189+ r->granted = false;
190+}
191+
192+/**
193+ * ccs_same_transition_control - Check for duplicated "struct ccs_transition_control" entry.
194+ *
195+ * @a: Pointer to "struct ccs_acl_head".
196+ * @b: Pointer to "struct ccs_acl_head".
197+ *
198+ * Returns true if @a == @b, false otherwise.
199+ */
200+static bool ccs_same_transition_control(const struct ccs_acl_head *a,
201+ const struct ccs_acl_head *b)
202+{
203+ const struct ccs_transition_control *p1 = container_of(a, typeof(*p1),
204+ head);
205+ const struct ccs_transition_control *p2 = container_of(b, typeof(*p2),
206+ head);
207+ return p1->type == p2->type && p1->is_last_name == p2->is_last_name
208+ && p1->domainname == p2->domainname
209+ && p1->program == p2->program;
210+}
211+
212+/**
213+ * ccs_update_transition_control_entry - Update "struct ccs_transition_control" list.
214+ *
215+ * @domainname: The name of domain. Maybe NULL.
216+ * @program: The name of program. Maybe NULL.
217+ * @type: Type of transition.
218+ * @is_delete: True if it is a delete request.
219+ *
220+ * Returns 0 on success, negative value otherwise.
221+ */
222+static int ccs_update_transition_control_entry(const char *domainname,
223+ const char *program,
224+ const u8 type,
225+ const bool is_delete)
226+{
227+ struct ccs_transition_control e = { .type = type };
228+ int error = is_delete ? -ENOENT : -ENOMEM;
229+ if (program && strcmp(program, "any")) {
230+ if (!ccs_correct_path(program))
231+ return -EINVAL;
232+ e.program = ccs_get_name(program);
233+ if (!e.program)
234+ goto out;
235+ }
236+ if (domainname && strcmp(domainname, "any")) {
237+ if (!ccs_correct_domain(domainname)) {
238+ if (!ccs_correct_path(domainname))
239+ goto out;
240+ e.is_last_name = true;
241+ }
242+ e.domainname = ccs_get_name(domainname);
243+ if (!e.domainname)
244+ goto out;
245+ }
246+ error = ccs_update_policy(&e.head, sizeof(e), is_delete,
247+ &ccs_policy_list[CCS_ID_TRANSITION_CONTROL],
248+ ccs_same_transition_control);
249+out:
250+ ccs_put_name(e.domainname);
251+ ccs_put_name(e.program);
252+ return error;
253+}
254+
255+/**
256+ * ccs_write_transition_control - Write "struct ccs_transition_control" list.
257+ *
258+ * @data: String to parse.
259+ * @is_delete: True if it is a delete request.
260+ * @type: Type of this entry.
261+ *
262+ * Returns 0 on success, negative value otherwise.
263+ */
264+int ccs_write_transition_control(char *data, const bool is_delete,
265+ const u8 type)
266+{
267+ char *domainname = strstr(data, " from ");
268+ if (domainname) {
269+ *domainname = '\0';
270+ domainname += 6;
271+ } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
272+ type == CCS_TRANSITION_CONTROL_KEEP) {
273+ domainname = data;
274+ data = NULL;
275+ }
276+ return ccs_update_transition_control_entry(domainname, data, type,
277+ is_delete);
278+}
279+
280+/**
281+ * ccs_last_word - Get last component of a domainname.
282+ *
283+ * @name: Domainname to check.
284+ *
285+ * Returns the last word of @name.
286+ */
287+static const char *ccs_last_word(const char *name)
288+{
289+ const char *cp = strrchr(name, ' ');
290+ if (cp)
291+ return cp + 1;
292+ return name;
293+}
294+
295+/**
296+ * ccs_transition_type - Get domain transition type.
297+ *
298+ * @domainname: The name of domain.
299+ * @program: The name of program.
300+ *
301+ * Returns CCS_TRANSITION_CONTROL_INITIALIZE if executing @program
302+ * reinitializes domain transition, CCS_TRANSITION_CONTROL_KEEP if executing
303+ * @program suppresses domain transition, others otherwise.
304+ *
305+ * Caller holds ccs_read_lock().
306+ */
307+static u8 ccs_transition_type(const struct ccs_path_info *domainname,
308+ const struct ccs_path_info *program)
309+{
310+ const struct ccs_transition_control *ptr;
311+ const char *last_name = ccs_last_word(domainname->name);
312+ u8 type;
313+ for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) {
314+next:
315+ list_for_each_entry_srcu(ptr, &ccs_policy_list
316+ [CCS_ID_TRANSITION_CONTROL],
317+ head.list, &ccs_ss) {
318+ if (ptr->head.is_deleted || ptr->type != type)
319+ continue;
320+ if (ptr->domainname) {
321+ if (!ptr->is_last_name) {
322+ if (ptr->domainname != domainname)
323+ continue;
324+ } else {
325+ /*
326+ * Use direct strcmp() since this is
327+ * unlikely used.
328+ */
329+ if (strcmp(ptr->domainname->name,
330+ last_name))
331+ continue;
332+ }
333+ }
334+ if (ptr->program && ccs_pathcmp(ptr->program, program))
335+ continue;
336+ if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) {
337+ /*
338+ * Do not check for initialize_domain if
339+ * no_initialize_domain matched.
340+ */
341+ type = CCS_TRANSITION_CONTROL_NO_KEEP;
342+ goto next;
343+ }
344+ goto done;
345+ }
346+ }
347+done:
348+ return type;
349+}
350+
351+/**
352+ * ccs_same_aggregator - Check for duplicated "struct ccs_aggregator" entry.
353+ *
354+ * @a: Pointer to "struct ccs_acl_head".
355+ * @b: Pointer to "struct ccs_acl_head".
356+ *
357+ * Returns true if @a == @b, false otherwise.
358+ */
359+static bool ccs_same_aggregator(const struct ccs_acl_head *a,
360+ const struct ccs_acl_head *b)
361+{
362+ const struct ccs_aggregator *p1 = container_of(a, typeof(*p1), head);
363+ const struct ccs_aggregator *p2 = container_of(b, typeof(*p2), head);
364+ return p1->original_name == p2->original_name &&
365+ p1->aggregated_name == p2->aggregated_name;
366+}
367+
368+/**
369+ * ccs_update_aggregator_entry - Update "struct ccs_aggregator" list.
370+ *
371+ * @original_name: The original program's name.
372+ * @aggregated_name: The aggregated program's name.
373+ * @is_delete: True if it is a delete request.
374+ *
375+ * Returns 0 on success, negative value otherwise.
376+ */
377+static int ccs_update_aggregator_entry(const char *original_name,
378+ const char *aggregated_name,
379+ const bool is_delete)
380+{
381+ struct ccs_aggregator e = { };
382+ int error = is_delete ? -ENOENT : -ENOMEM;
383+ if (!ccs_correct_word(original_name) ||
384+ !ccs_correct_path(aggregated_name))
385+ return -EINVAL;
386+ e.original_name = ccs_get_name(original_name);
387+ e.aggregated_name = ccs_get_name(aggregated_name);
388+ if (!e.original_name || !e.aggregated_name ||
389+ e.aggregated_name->is_patterned) /* No patterns allowed. */
390+ goto out;
391+ error = ccs_update_policy(&e.head, sizeof(e), is_delete,
392+ &ccs_policy_list[CCS_ID_AGGREGATOR],
393+ ccs_same_aggregator);
394+out:
395+ ccs_put_name(e.original_name);
396+ ccs_put_name(e.aggregated_name);
397+ return error;
398+}
399+
400+/**
401+ * ccs_write_aggregator - Write "struct ccs_aggregator" list.
402+ *
403+ * @data: String to parse.
404+ * @is_delete: True if it is a delete request.
405+ *
406+ * Returns 0 on success, negative value otherwise.
407+ */
408+int ccs_write_aggregator(char *data, const bool is_delete)
409+{
410+ char *w[2];
411+ if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
412+ return -EINVAL;
413+ return ccs_update_aggregator_entry(w[0], w[1], is_delete);
414+}
415+
416+/* Domain create/delete handler. */
417+
418+/**
419+ * ccs_delete_domain - Delete a domain.
420+ *
421+ * @domainname: The name of domain.
422+ *
423+ * Returns 0.
424+ */
425+int ccs_delete_domain(char *domainname)
426+{
427+ struct ccs_domain_info *domain;
428+ struct ccs_path_info name;
429+ name.name = domainname;
430+ ccs_fill_path_info(&name);
431+ if (mutex_lock_interruptible(&ccs_policy_lock))
432+ return 0;
433+ /* Is there an active domain? */
434+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
435+ /* Never delete ccs_kernel_domain. */
436+ if (domain == &ccs_kernel_domain)
437+ continue;
438+ if (domain->is_deleted ||
439+ ccs_pathcmp(domain->domainname, &name))
440+ continue;
441+ domain->is_deleted = true;
442+ break;
443+ }
444+ mutex_unlock(&ccs_policy_lock);
445+ return 0;
446+}
447+
448+/**
449+ * ccs_assign_domain - Create a domain.
450+ *
451+ * @domainname: The name of domain.
452+ * @profile: Profile number to assign if the domain was newly created.
453+ * @group: Group number to assign if the domain was newly created.
454+ * @transit: True if transit to domain found or created.
455+ *
456+ * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
457+ *
458+ * Caller holds ccs_read_lock().
459+ */
460+struct ccs_domain_info *ccs_assign_domain(const char *domainname,
461+ const u8 profile, const u8 group,
462+ const bool transit)
463+{
464+ struct ccs_domain_info e = { };
465+ struct ccs_domain_info *entry = ccs_find_domain(domainname);
466+ bool created = false;
467+ if (entry)
468+ goto out;
469+ if (strlen(domainname) >= CCS_EXEC_TMPSIZE - 10 ||
470+ !ccs_correct_domain(domainname))
471+ return NULL;
472+ e.profile = profile;
473+ e.group = group;
474+ e.domainname = ccs_get_name(domainname);
475+ if (!e.domainname)
476+ return NULL;
477+ if (mutex_lock_interruptible(&ccs_policy_lock))
478+ goto out;
479+ entry = ccs_find_domain(domainname);
480+ if (!entry) {
481+ entry = ccs_commit_ok(&e, sizeof(e));
482+ if (entry) {
483+ INIT_LIST_HEAD(&entry->acl_info_list[0]);
484+ INIT_LIST_HEAD(&entry->acl_info_list[1]);
485+ list_add_tail_rcu(&entry->list, &ccs_domain_list);
486+ created = true;
487+ }
488+ }
489+ mutex_unlock(&ccs_policy_lock);
490+out:
491+ ccs_put_name(e.domainname);
492+ if (entry && transit) {
493+ ccs_current_security()->ccs_domain_info = entry;
494+ if (created) {
495+ struct ccs_request_info r;
496+ ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
497+ r.granted = false;
498+ ccs_write_log(&r, "use_profile %u\n", profile);
499+ ccs_write_log(&r, "use_group %u\n", group);
500+ ccs_update_stat(CCS_STAT_POLICY_UPDATES);
501+ }
502+ }
503+ return entry;
504+}
505+
506+/**
507+ * ccs_find_next_domain - Find a domain.
508+ *
509+ * @ee: Pointer to "struct ccs_execve".
510+ *
511+ * Returns 0 on success, negative value otherwise.
512+ *
513+ * Caller holds ccs_read_lock().
514+ */
515+static int ccs_find_next_domain(struct ccs_execve *ee)
516+{
517+ struct ccs_request_info *r = &ee->r;
518+ const struct ccs_path_info *handler = ee->handler;
519+ struct ccs_domain_info *domain = NULL;
520+ struct ccs_domain_info * const old_domain = ccs_current_domain();
521+ struct linux_binprm *bprm = ee->bprm;
522+ struct ccs_security *task = ccs_current_security();
523+ struct ccs_path_info rn = { }; /* real name */
524+ int retval;
525+ bool need_kfree = false;
526+retry:
527+ r->matched_acl = NULL;
528+ if (need_kfree) {
529+ kfree(rn.name);
530+ need_kfree = false;
531+ }
532+
533+ /* Get symlink's pathname of program. */
534+ retval = ccs_symlink_path(bprm->filename, &rn);
535+ if (retval < 0)
536+ goto out;
537+ need_kfree = true;
538+
539+ if (handler) {
540+ if (ccs_pathcmp(&rn, handler)) {
541+ /* Failed to verify execute handler. */
542+ static u8 counter = 20;
543+ if (counter) {
544+ counter--;
545+ printk(KERN_WARNING "Failed to verify: %s\n",
546+ handler->name);
547+ }
548+ goto out;
549+ }
550+ } else {
551+ struct ccs_aggregator *ptr;
552+ /* Check 'aggregator' directive. */
553+ list_for_each_entry_srcu(ptr,
554+ &ccs_policy_list[CCS_ID_AGGREGATOR],
555+ head.list, &ccs_ss) {
556+ if (ptr->head.is_deleted ||
557+ !ccs_path_matches_pattern(&rn, ptr->original_name))
558+ continue;
559+ kfree(rn.name);
560+ need_kfree = false;
561+ /* This is OK because it is read only. */
562+ rn = *ptr->aggregated_name;
563+ break;
564+ }
565+
566+ /* Check execute permission. */
567+ retval = ccs_path_permission(r, CCS_TYPE_EXECUTE, &rn);
568+ if (retval == CCS_RETRY_REQUEST)
569+ goto retry;
570+ if (retval < 0)
571+ goto out;
572+ /*
573+ * To be able to specify domainnames with wildcards, use the
574+ * pathname specified in the policy (which may contain
575+ * wildcard) rather than the pathname passed to execve()
576+ * (which never contains wildcard).
577+ */
578+ if (r->param.path.matched_path) {
579+ if (need_kfree)
580+ kfree(rn.name);
581+ need_kfree = false;
582+ /* This is OK because it is read only. */
583+ rn = *r->param.path.matched_path;
584+ }
585+ }
586+
587+ /* Calculate domain to transit to. */
588+ switch (ccs_transition_type(old_domain->domainname, &rn)) {
589+ case CCS_TRANSITION_CONTROL_INITIALIZE:
590+ /* Transit to the child of ccs_kernel_domain domain. */
591+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, CCS_ROOT_NAME " " "%s",
592+ rn.name);
593+ break;
594+ case CCS_TRANSITION_CONTROL_KEEP:
595+ /* Keep current domain. */
596+ domain = old_domain;
597+ break;
598+ default:
599+ if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
600+ /*
601+ * Needn't to transit from kernel domain before
602+ * starting /sbin/init. But transit from kernel domain
603+ * if executing initializers because they might start
604+ * before /sbin/init.
605+ */
606+ domain = old_domain;
607+ } else {
608+ /* Normal domain transition. */
609+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
610+ old_domain->domainname->name, rn.name);
611+ }
612+ break;
613+ }
614+ /*
615+ * Tell GC that I started execve().
616+ * Also, tell open_exec() to check read permission.
617+ */
618+ task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
619+ /*
620+ * Make task->ccs_flags visible to GC before changing
621+ * task->ccs_domain_info.
622+ */
623+ smp_wmb();
624+ /*
625+ * Proceed to the next domain in order to allow reaching via PID.
626+ * It will be reverted if execve() failed. Reverting is not good.
627+ * But it is better than being unable to reach via PID in interactive
628+ * enforcing mode.
629+ */
630+ if (!domain)
631+ domain = ccs_assign_domain(ee->tmp, r->profile,
632+ old_domain->group, true);
633+ if (domain)
634+ retval = 0;
635+ else if (r->mode == CCS_CONFIG_ENFORCING)
636+ retval = -ENOMEM;
637+ else {
638+ retval = 0;
639+ if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) {
640+ old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true;
641+ r->granted = false;
642+ ccs_write_log(r, "%s",
643+ ccs_dif[CCS_DIF_TRANSITION_FAILED]);
644+ printk(KERN_WARNING
645+ "ERROR: Domain '%s' not defined.\n", ee->tmp);
646+ }
647+ }
648+out:
649+ if (need_kfree)
650+ kfree(rn.name);
651+ return retval;
652+}
653+
654+/**
655+ * ccs_environ - Check permission for environment variable names.
656+ *
657+ * @ee: Pointer to "struct ccs_execve".
658+ *
659+ * Returns 0 on success, negative value otherwise.
660+ */
661+static int ccs_environ(struct ccs_execve *ee)
662+{
663+ struct ccs_request_info *r = &ee->r;
664+ struct linux_binprm *bprm = ee->bprm;
665+ /* env_page->data is allocated by ccs_dump_page(). */
666+ struct ccs_page_dump env_page = { };
667+ char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
668+ int arg_len = 0;
669+ unsigned long pos = bprm->p;
670+ int offset = pos % PAGE_SIZE;
671+ int argv_count = bprm->argc;
672+ int envp_count = bprm->envc;
673+ /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
674+ int error = -ENOMEM;
675+ ee->r.type = CCS_MAC_ENVIRON;
676+ ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
677+ CCS_MAC_ENVIRON);
678+ if (!r->mode || !envp_count)
679+ return 0;
680+ arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
681+ if (!arg_ptr)
682+ goto out;
683+ while (error == -ENOMEM) {
684+ if (!ccs_dump_page(bprm, pos, &env_page))
685+ goto out;
686+ pos += PAGE_SIZE - offset;
687+ /* Read. */
688+ while (argv_count && offset < PAGE_SIZE) {
689+ if (!env_page.data[offset++])
690+ argv_count--;
691+ }
692+ if (argv_count) {
693+ offset = 0;
694+ continue;
695+ }
696+ while (offset < PAGE_SIZE) {
697+ const unsigned char c = env_page.data[offset++];
698+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
699+ if (c == '=') {
700+ arg_ptr[arg_len++] = '\0';
701+ } else if (c == '\\') {
702+ arg_ptr[arg_len++] = '\\';
703+ arg_ptr[arg_len++] = '\\';
704+ } else if (c > ' ' && c < 127) {
705+ arg_ptr[arg_len++] = c;
706+ } else {
707+ arg_ptr[arg_len++] = '\\';
708+ arg_ptr[arg_len++] = (c >> 6) + '0';
709+ arg_ptr[arg_len++]
710+ = ((c >> 3) & 7) + '0';
711+ arg_ptr[arg_len++] = (c & 7) + '0';
712+ }
713+ } else {
714+ arg_ptr[arg_len] = '\0';
715+ }
716+ if (c)
717+ continue;
718+ if (ccs_env_perm(r, arg_ptr)) {
719+ error = -EPERM;
720+ break;
721+ }
722+ if (!--envp_count) {
723+ error = 0;
724+ break;
725+ }
726+ arg_len = 0;
727+ }
728+ offset = 0;
729+ }
730+out:
731+ if (r->mode != 3)
732+ error = 0;
733+ kfree(env_page.data);
734+ kfree(arg_ptr);
735+ return error;
736+}
737+
738+/**
739+ * ccs_unescape - Unescape escaped string.
740+ *
741+ * @dest: String to unescape.
742+ *
743+ * Returns nothing.
744+ */
745+static void ccs_unescape(unsigned char *dest)
746+{
747+ unsigned char *src = dest;
748+ unsigned char c;
749+ unsigned char d;
750+ unsigned char e;
751+ while (1) {
752+ c = *src++;
753+ if (!c)
754+ break;
755+ if (c != '\\') {
756+ *dest++ = c;
757+ continue;
758+ }
759+ c = *src++;
760+ if (c == '\\') {
761+ *dest++ = c;
762+ continue;
763+ }
764+ if (c < '0' || c > '3')
765+ break;
766+ d = *src++;
767+ if (d < '0' || d > '7')
768+ break;
769+ e = *src++;
770+ if (e < '0' || e > '7')
771+ break;
772+ *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
773+ }
774+ *dest = '\0';
775+}
776+
777+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
778+
779+/**
780+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
781+ *
782+ * @arg: String to copy.
783+ * @bprm: Pointer to "struct linux_binprm".
784+ *
785+ * Returns return value of copy_strings_kernel().
786+ */
787+static int ccs_copy_argv(const char *arg, struct linux_binprm *bprm)
788+{
789+ const int ret = copy_strings_kernel(1, &arg, bprm);
790+ if (ret >= 0)
791+ bprm->argc++;
792+ return ret;
793+}
794+
795+#else
796+
797+/**
798+ * ccs_copy_argv - Wrapper for copy_strings_kernel().
799+ *
800+ * @arg: String to copy.
801+ * @bprm: Pointer to "struct linux_binprm".
802+ *
803+ * Returns return value of copy_strings_kernel().
804+ */
805+static int ccs_copy_argv(char *arg, struct linux_binprm *bprm)
806+{
807+ const int ret = copy_strings_kernel(1, &arg, bprm);
808+ if (ret >= 0)
809+ bprm->argc++;
810+ return ret;
811+}
812+
813+#endif
814+
815+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)
816+
817+/**
818+ * get_fs_root - Get reference on root directory.
819+ *
820+ * @fs: Pointer to "struct fs_struct".
821+ * @root: Pointer to "struct path".
822+ *
823+ * Returns nothing.
824+ *
825+ * This is for compatibility with older kernels.
826+ */
827+static inline void get_fs_root(struct fs_struct *fs, struct path *root)
828+{
829+ read_lock(&fs->lock);
830+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
831+ *root = fs->root;
832+ path_get(root);
833+#else
834+ root->dentry = dget(fs->root);
835+ root->mnt = mntget(fs->rootmnt);
836+#endif
837+ read_unlock(&fs->lock);
838+}
839+
840+#endif
841+
842+/**
843+ * ccs_try_alt_exec - Try to start execute handler.
844+ *
845+ * @ee: Pointer to "struct ccs_execve".
846+ *
847+ * Returns 0 on success, negative value otherwise.
848+ */
849+static int ccs_try_alt_exec(struct ccs_execve *ee)
850+{
851+ /*
852+ * Contents of modified bprm.
853+ * The envp[] in original bprm is moved to argv[] so that
854+ * the alternatively executed program won't be affected by
855+ * some dangerous environment variables like LD_PRELOAD.
856+ *
857+ * modified bprm->argc
858+ * = original bprm->argc + original bprm->envc + 7
859+ * modified bprm->envc
860+ * = 0
861+ *
862+ * modified bprm->argv[0]
863+ * = the program's name specified by *_execute_handler
864+ * modified bprm->argv[1]
865+ * = ccs_current_domain()->domainname->name
866+ * modified bprm->argv[2]
867+ * = the current process's name
868+ * modified bprm->argv[3]
869+ * = the current process's information (e.g. uid/gid).
870+ * modified bprm->argv[4]
871+ * = original bprm->filename
872+ * modified bprm->argv[5]
873+ * = original bprm->argc in string expression
874+ * modified bprm->argv[6]
875+ * = original bprm->envc in string expression
876+ * modified bprm->argv[7]
877+ * = original bprm->argv[0]
878+ * ...
879+ * modified bprm->argv[bprm->argc + 6]
880+ * = original bprm->argv[bprm->argc - 1]
881+ * modified bprm->argv[bprm->argc + 7]
882+ * = original bprm->envp[0]
883+ * ...
884+ * modified bprm->argv[bprm->envc + bprm->argc + 6]
885+ * = original bprm->envp[bprm->envc - 1]
886+ */
887+ struct linux_binprm *bprm = ee->bprm;
888+ struct file *filp;
889+ int retval;
890+ const int original_argc = bprm->argc;
891+ const int original_envc = bprm->envc;
892+
893+ /* Close the requested program's dentry. */
894+ ee->obj.path1.dentry = NULL;
895+ ee->obj.path1.mnt = NULL;
896+ ee->obj.validate_done = false;
897+ allow_write_access(bprm->file);
898+ fput(bprm->file);
899+ bprm->file = NULL;
900+
901+ /* Invalidate page dump cache. */
902+ ee->dump.page = NULL;
903+
904+ /* Move envp[] to argv[] */
905+ bprm->argc += bprm->envc;
906+ bprm->envc = 0;
907+
908+ /* Set argv[6] */
909+ {
910+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
911+ retval = ccs_copy_argv(ee->tmp, bprm);
912+ if (retval < 0)
913+ goto out;
914+ }
915+
916+ /* Set argv[5] */
917+ {
918+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
919+ retval = ccs_copy_argv(ee->tmp, bprm);
920+ if (retval < 0)
921+ goto out;
922+ }
923+
924+ /* Set argv[4] */
925+ {
926+ retval = ccs_copy_argv(bprm->filename, bprm);
927+ if (retval < 0)
928+ goto out;
929+ }
930+
931+ /* Set argv[3] */
932+ {
933+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
934+ "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
935+ "sgid=%d fsuid=%d fsgid=%d", ccs_sys_getpid(),
936+ current_uid(), current_gid(), current_euid(),
937+ current_egid(), current_suid(), current_sgid(),
938+ current_fsuid(), current_fsgid());
939+ retval = ccs_copy_argv(ee->tmp, bprm);
940+ if (retval < 0)
941+ goto out;
942+ }
943+
944+ /* Set argv[2] */
945+ {
946+ char *exe = (char *) ccs_get_exe();
947+ if (exe) {
948+ retval = ccs_copy_argv(exe, bprm);
949+ kfree(exe);
950+ } else {
951+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
952+ retval = ccs_copy_argv("<unknown>", bprm);
953+#else
954+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
955+ retval = ccs_copy_argv(ee->tmp, bprm);
956+#endif
957+ }
958+ if (retval < 0)
959+ goto out;
960+ }
961+
962+ /* Set argv[1] */
963+ {
964+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
965+ retval = ccs_copy_argv(ccs_current_domain()->domainname->name,
966+ bprm);
967+#else
968+ snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
969+ ccs_current_domain()->domainname->name);
970+ retval = ccs_copy_argv(ee->tmp, bprm);
971+#endif
972+ if (retval < 0)
973+ goto out;
974+ }
975+
976+ /* Set argv[0] */
977+ {
978+ struct path root;
979+ char *cp;
980+ int root_len;
981+ int handler_len;
982+ get_fs_root(current->fs, &root);
983+ cp = ccs_realpath_from_path(&root);
984+ path_put(&root);
985+ if (!cp) {
986+ retval = -ENOMEM;
987+ goto out;
988+ }
989+ root_len = strlen(cp);
990+ retval = strncmp(ee->handler->name, cp, root_len);
991+ root_len--;
992+ kfree(cp);
993+ if (retval) {
994+ retval = -ENOENT;
995+ goto out;
996+ }
997+ handler_len = ee->handler->total_len + 1;
998+ cp = kmalloc(handler_len, CCS_GFP_FLAGS);
999+ if (!cp) {
1000+ retval = -ENOMEM;
1001+ goto out;
1002+ }
1003+ /* ee->handler_path is released by ccs_finish_execve(). */
1004+ ee->handler_path = cp;
1005+ /* Adjust root directory for open_exec(). */
1006+ memmove(cp, ee->handler->name + root_len,
1007+ handler_len - root_len);
1008+ ccs_unescape(cp);
1009+ retval = -ENOENT;
1010+ if (*cp != '/')
1011+ goto out;
1012+ retval = ccs_copy_argv(cp, bprm);
1013+ if (retval < 0)
1014+ goto out;
1015+ }
1016+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1017+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1018+ bprm->argv_len = bprm->exec - bprm->p;
1019+#endif
1020+#endif
1021+
1022+ /*
1023+ * OK, now restart the process with execute handler program's dentry.
1024+ */
1025+ filp = open_exec(ee->handler_path);
1026+ if (IS_ERR(filp)) {
1027+ retval = PTR_ERR(filp);
1028+ goto out;
1029+ }
1030+ ee->obj.path1.dentry = filp->f_dentry;
1031+ ee->obj.path1.mnt = filp->f_vfsmnt;
1032+ bprm->file = filp;
1033+ bprm->filename = ee->handler_path;
1034+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1035+ bprm->interp = bprm->filename;
1036+#endif
1037+ retval = prepare_binprm(bprm);
1038+ if (retval < 0)
1039+ goto out;
1040+ ee->r.dont_sleep_on_enforce_error = true;
1041+ retval = ccs_find_next_domain(ee);
1042+ ee->r.dont_sleep_on_enforce_error = false;
1043+out:
1044+ return retval;
1045+}
1046+
1047+/**
1048+ * ccs_find_execute_handler - Find an execute handler.
1049+ *
1050+ * @ee: Pointer to "struct ccs_execve".
1051+ * @type: Type of execute handler.
1052+ *
1053+ * Returns true if found, false otherwise.
1054+ *
1055+ * Caller holds ccs_read_lock().
1056+ */
1057+static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type)
1058+{
1059+ struct ccs_request_info *r = &ee->r;
1060+ /*
1061+ * To avoid infinite execute handler loop, don't use execute handler
1062+ * if the current process is marked as execute handler.
1063+ */
1064+ if (ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)
1065+ return false;
1066+ r->param_type = type;
1067+ ccs_check_acl(r, NULL);
1068+ if (!r->granted)
1069+ return false;
1070+ ee->handler = container_of(r->matched_acl, struct ccs_handler_acl,
1071+ head)->handler;
1072+ return true;
1073+}
1074+
1075+#ifdef CONFIG_MMU
1076+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1077+#define CCS_BPRM_MMU
1078+#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5
1079+#define CCS_BPRM_MMU
1080+#elif defined(AX_MAJOR) && AX_MAJOR == 3
1081+#define CCS_BPRM_MMU
1082+#endif
1083+#endif
1084+
1085+/**
1086+ * ccs_dump_page - Dump a page to buffer.
1087+ *
1088+ * @bprm: Pointer to "struct linux_binprm".
1089+ * @pos: Location to dump.
1090+ * @dump: Poiner to "struct ccs_page_dump".
1091+ *
1092+ * Returns true on success, false otherwise.
1093+ */
1094+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1095+ struct ccs_page_dump *dump)
1096+{
1097+ struct page *page;
1098+ /* dump->data is released by ccs_finish_execve(). */
1099+ if (!dump->data) {
1100+ dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1101+ if (!dump->data)
1102+ return false;
1103+ }
1104+ /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1105+#ifdef CCS_BPRM_MMU
1106+ if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1107+ return false;
1108+#else
1109+ page = bprm->page[pos / PAGE_SIZE];
1110+#endif
1111+ if (page != dump->page) {
1112+ const unsigned int offset = pos % PAGE_SIZE;
1113+ /*
1114+ * Maybe kmap()/kunmap() should be used here.
1115+ * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1116+ * So do I.
1117+ */
1118+ char *kaddr = kmap_atomic(page, KM_USER0);
1119+ dump->page = page;
1120+ memcpy(dump->data + offset, kaddr + offset,
1121+ PAGE_SIZE - offset);
1122+ kunmap_atomic(kaddr, KM_USER0);
1123+ }
1124+ /* Same with put_arg_page(page) in fs/exec.c */
1125+#ifdef CCS_BPRM_MMU
1126+ put_page(page);
1127+#endif
1128+ return true;
1129+}
1130+
1131+/**
1132+ * ccs_start_execve - Prepare for execve() operation.
1133+ *
1134+ * @bprm: Pointer to "struct linux_binprm".
1135+ * @eep: Pointer to "struct ccs_execve *".
1136+ *
1137+ * Returns 0 on success, negative value otherwise.
1138+ */
1139+int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve **eep)
1140+{
1141+ int retval;
1142+ struct ccs_security *task = ccs_current_security();
1143+ struct ccs_execve *ee;
1144+ *eep = NULL;
1145+ ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1146+ if (!ee)
1147+ return -ENOMEM;
1148+ ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1149+ if (!ee->tmp) {
1150+ kfree(ee);
1151+ return -ENOMEM;
1152+ }
1153+ ee->reader_idx = ccs_read_lock();
1154+ /* ee->dump->data is allocated by ccs_dump_page(). */
1155+ ee->previous_domain = task->ccs_domain_info;
1156+ /* Clear manager flag. */
1157+ task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1158+ *eep = ee;
1159+ ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1160+ ee->r.ee = ee;
1161+ ee->bprm = bprm;
1162+ ee->r.obj = &ee->obj;
1163+ ee->obj.path1.dentry = bprm->file->f_dentry;
1164+ ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1165+ /*
1166+ * No need to call ccs_environ() for execute handler because envp[] is
1167+ * moved to argv[].
1168+ */
1169+ if (ccs_find_execute_handler(ee, CCS_TYPE_AUTO_EXECUTE_HANDLER))
1170+ return ccs_try_alt_exec(ee);
1171+ retval = ccs_find_next_domain(ee);
1172+ if (retval == -EPERM) {
1173+ if (ccs_find_execute_handler(ee,
1174+ CCS_TYPE_DENIED_EXECUTE_HANDLER))
1175+ return ccs_try_alt_exec(ee);
1176+ }
1177+ if (!retval)
1178+ retval = ccs_environ(ee);
1179+ return retval;
1180+}
1181+
1182+/**
1183+ * ccs_finish_execve - Clean up execve() operation.
1184+ *
1185+ * @retval: Return code of an execve() operation.
1186+ * @ee: Pointer to "struct ccs_execve".
1187+ *
1188+ * Returns nothing.
1189+ *
1190+ * Caller holds ccs_read_lock().
1191+ */
1192+void ccs_finish_execve(int retval, struct ccs_execve *ee)
1193+{
1194+ struct ccs_security *task = ccs_current_security();
1195+ if (!ee)
1196+ return;
1197+ if (retval < 0) {
1198+ task->ccs_domain_info = ee->previous_domain;
1199+ /*
1200+ * Make task->ccs_domain_info visible to GC before changing
1201+ * task->ccs_flags.
1202+ */
1203+ smp_wmb();
1204+ } else {
1205+ /* Mark the current process as execute handler. */
1206+ if (ee->handler)
1207+ task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1208+ /* Mark the current process as normal process. */
1209+ else
1210+ task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1211+ }
1212+ /* Tell GC that I finished execve(). */
1213+ task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1214+ ccs_read_unlock(ee->reader_idx);
1215+ kfree(ee->handler_path);
1216+ kfree(ee->tmp);
1217+ kfree(ee->dump.data);
1218+ kfree(ee);
1219+}
1220+
1221+/**
1222+ * __ccs_search_binary_handler - Main routine for do_execve().
1223+ *
1224+ * @bprm: Pointer to "struct linux_binprm".
1225+ * @regs: Pointer to "struct pt_regs".
1226+ *
1227+ * Returns 0 on success, negative value otherwise.
1228+ *
1229+ * Performs permission checks for do_execve() and domain transition.
1230+ * Domain transition by "struct ccs_domain_transition_control" and
1231+ * "auto_domain_transition=" parameter of "struct ccs_condition" are reverted
1232+ * if do_execve() failed.
1233+ * Garbage collector does not remove "struct ccs_domain_info" from
1234+ * ccs_domain_list nor kfree("struct ccs_domain_info") if the current thread is
1235+ * marked as CCS_TASK_IS_IN_EXECVE.
1236+ */
1237+static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1238+ struct pt_regs *regs)
1239+{
1240+ struct ccs_execve *ee;
1241+ int retval;
1242+#ifndef CONFIG_CCSECURITY_OMIT_USERSPACE_LOADER
1243+ if (!ccs_policy_loaded)
1244+ ccsecurity_exports.load_policy(bprm->filename);
1245+#endif
1246+ retval = ccs_start_execve(bprm, &ee);
1247+ if (!retval)
1248+ retval = search_binary_handler(bprm, regs);
1249+ ccs_finish_execve(retval, ee);
1250+ return retval;
1251+}
1252+
1253+/**
1254+ * ccs_domain_init - Register program execution hook.
1255+ *
1256+ * Returns nothing.
1257+ */
1258+void __init ccs_domain_init(void)
1259+{
1260+ ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1261+}
--- tags/patches/1.0.12/memory.c (nonexistent)
+++ tags/patches/1.0.12/memory.c (revision 197)
@@ -0,0 +1,453 @@
1+/*
2+ * security/ccsecurity/memory.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/**
12+ * ccs_warn_oom - Print out of memory warning message.
13+ *
14+ * @function: Function's name.
15+ *
16+ * Returns nothing.
17+ */
18+void ccs_warn_oom(const char *function)
19+{
20+ /* Reduce error messages. */
21+ static pid_t ccs_last_pid;
22+ const pid_t pid = current->pid;
23+ if (ccs_last_pid != pid) {
24+ printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
25+ function);
26+ ccs_last_pid = pid;
27+ }
28+ if (!ccs_policy_loaded)
29+ panic("MAC Initialization failed.\n");
30+}
31+
32+/*
33+ * Lock for protecting ccs_memory_used.
34+ *
35+ * I don't use atomic_t because it can handle only 16MB in 2.4 kernels.
36+ */
37+static DEFINE_SPINLOCK(ccs_policy_memory_lock);
38+/* Memoy currently used by policy/audit log/query. */
39+unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
40+/* Memory quota for "policy"/"audit log"/"query". */
41+unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
42+
43+/**
44+ * ccs_memory_ok - Check memory quota.
45+ *
46+ * @ptr: Pointer to allocated memory. Maybe NULL.
47+ * @size: Size in byte. Not used if @ptr is NULL.
48+ *
49+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
50+ */
51+bool ccs_memory_ok(const void *ptr, const unsigned int size)
52+{
53+ if (ptr) {
54+ const size_t s = ccs_round2(size);
55+ bool result;
56+ spin_lock(&ccs_policy_memory_lock);
57+ ccs_memory_used[CCS_MEMORY_POLICY] += s;
58+ result = !ccs_memory_quota[CCS_MEMORY_POLICY] ||
59+ ccs_memory_used[CCS_MEMORY_POLICY] <=
60+ ccs_memory_quota[CCS_MEMORY_POLICY];
61+ if (!result)
62+ ccs_memory_used[CCS_MEMORY_POLICY] -= s;
63+ spin_unlock(&ccs_policy_memory_lock);
64+ if (result)
65+ return true;
66+ }
67+ ccs_warn_oom(__func__);
68+ return false;
69+}
70+
71+/**
72+ * ccs_commit_ok - Allocate memory and check memory quota.
73+ *
74+ * @data: Data to copy from.
75+ * @size: Size in byte.
76+ *
77+ * Returns pointer to allocated memory on success, NULL otherwise.
78+ * @data is zero-cleared on success.
79+ */
80+void *ccs_commit_ok(void *data, const unsigned int size)
81+{
82+ void *ptr = kmalloc(size, CCS_GFP_FLAGS);
83+ if (ccs_memory_ok(ptr, size)) {
84+ memmove(ptr, data, size);
85+ memset(data, 0, size);
86+ return ptr;
87+ }
88+ kfree(ptr);
89+ return NULL;
90+}
91+
92+/**
93+ * ccs_memory_free - Free memory for elements.
94+ *
95+ * @ptr: Pointer to allocated memory.
96+ * @size: Size in byte.
97+ *
98+ * Returns nothing.
99+ */
100+void ccs_memory_free(const void *ptr, size_t size)
101+{
102+ size_t s = ccs_round2(size);
103+ spin_lock(&ccs_policy_memory_lock);
104+ ccs_memory_used[CCS_MEMORY_POLICY] -= s;
105+ spin_unlock(&ccs_policy_memory_lock);
106+ kfree(ptr);
107+}
108+
109+/**
110+ * ccs_get_group - Allocate memory for "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group".
111+ *
112+ * @group_name: The name of address group.
113+ * @idx: Index number.
114+ *
115+ * Returns pointer to "struct ccs_group" on success, NULL otherwise.
116+ */
117+struct ccs_group *ccs_get_group(const char *group_name, const u8 idx)
118+{
119+ struct ccs_group e = { };
120+ struct ccs_group *group = NULL;
121+ bool found = false;
122+ if (!ccs_correct_word(group_name) || idx >= CCS_MAX_GROUP)
123+ return NULL;
124+ e.group_name = ccs_get_name(group_name);
125+ if (!e.group_name)
126+ return NULL;
127+ if (mutex_lock_interruptible(&ccs_policy_lock))
128+ goto out;
129+ list_for_each_entry(group, &ccs_group_list[idx], head.list) {
130+ if (e.group_name != group->group_name)
131+ continue;
132+ atomic_inc(&group->head.users);
133+ found = true;
134+ break;
135+ }
136+ if (!found) {
137+ struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
138+ if (entry) {
139+ INIT_LIST_HEAD(&entry->member_list);
140+ atomic_set(&entry->head.users, 1);
141+ list_add_tail_rcu(&entry->head.list,
142+ &ccs_group_list[idx]);
143+ group = entry;
144+ found = true;
145+ }
146+ }
147+ mutex_unlock(&ccs_policy_lock);
148+out:
149+ ccs_put_name(e.group_name);
150+ return found ? group : NULL;
151+}
152+
153+/**
154+ * ccs_get_ipv6_address - Keep the given IPv6 address on the RAM.
155+ *
156+ * @addr: Pointer to "struct in6_addr".
157+ *
158+ * Returns pointer to "struct in6_addr" on success, NULL otherwise.
159+ */
160+const struct in6_addr *ccs_get_ipv6_address(const struct in6_addr *addr)
161+{
162+ struct ccs_ipv6addr *entry;
163+ struct ccs_ipv6addr *ptr = NULL;
164+ int error = -ENOMEM;
165+ if (!addr)
166+ return NULL;
167+ entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
168+ if (mutex_lock_interruptible(&ccs_policy_lock))
169+ goto out;
170+ list_for_each_entry(ptr, &ccs_shared_list[CCS_IPV6ADDRESS_LIST],
171+ head.list) {
172+ if (memcmp(&ptr->addr, addr, sizeof(*addr)))
173+ continue;
174+ atomic_inc(&ptr->head.users);
175+ error = 0;
176+ break;
177+ }
178+ if (error && ccs_memory_ok(entry, sizeof(*entry))) {
179+ ptr = entry;
180+ ptr->addr = *addr;
181+ atomic_set(&ptr->head.users, 1);
182+ list_add_tail(&ptr->head.list,
183+ &ccs_shared_list[CCS_IPV6ADDRESS_LIST]);
184+ entry = NULL;
185+ error = 0;
186+ }
187+ mutex_unlock(&ccs_policy_lock);
188+out:
189+ kfree(entry);
190+ return !error ? &ptr->addr : NULL;
191+}
192+
193+/* The list for "struct ccs_name". */
194+struct list_head ccs_name_list[CCS_MAX_HASH];
195+
196+/**
197+ * ccs_get_name - Allocate memory for string data.
198+ *
199+ * @name: The string to store into the permernent memory.
200+ *
201+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
202+ */
203+const struct ccs_path_info *ccs_get_name(const char *name)
204+{
205+ struct ccs_name *ptr;
206+ unsigned int hash;
207+ int len;
208+ int allocated_len;
209+ struct list_head *head;
210+
211+ if (!name)
212+ return NULL;
213+ len = strlen(name) + 1;
214+ hash = full_name_hash((const unsigned char *) name, len - 1);
215+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(RHEL_MAJOR)
216+ head = &ccs_name_list[hash_long(hash, CCS_HASH_BITS)];
217+#else
218+ head = &ccs_name_list[hash % CCS_MAX_HASH];
219+#endif
220+ if (mutex_lock_interruptible(&ccs_policy_lock))
221+ return NULL;
222+ list_for_each_entry(ptr, head, head.list) {
223+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
224+ continue;
225+ atomic_inc(&ptr->head.users);
226+ goto out;
227+ }
228+ allocated_len = sizeof(*ptr) + len;
229+ ptr = kzalloc(allocated_len, CCS_GFP_FLAGS);
230+ if (ccs_memory_ok(ptr, allocated_len)) {
231+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
232+ memmove((char *) ptr->entry.name, name, len);
233+ atomic_set(&ptr->head.users, 1);
234+ ccs_fill_path_info(&ptr->entry);
235+ ptr->size = allocated_len;
236+ list_add_tail(&ptr->head.list, head);
237+ } else {
238+ kfree(ptr);
239+ ptr = NULL;
240+ }
241+out:
242+ mutex_unlock(&ccs_policy_lock);
243+ return ptr ? &ptr->entry : NULL;
244+}
245+
246+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
247+
248+/* Dummy security context for avoiding NULL pointer dereference. */
249+static struct ccs_security ccs_oom_security = {
250+ .ccs_domain_info = &ccs_kernel_domain
251+};
252+
253+/* Dummy security context for avoiding NULL pointer dereference. */
254+static struct ccs_security ccs_default_security = {
255+ .ccs_domain_info = &ccs_kernel_domain
256+};
257+
258+/* List of "struct ccs_security". */
259+struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
260+/* Lock for protecting ccs_task_security_list[]. */
261+DEFINE_SPINLOCK(ccs_task_security_list_lock);
262+
263+/**
264+ * ccs_add_task_security - Add "struct ccs_security" to list.
265+ *
266+ * @ptr: Pointer to "struct ccs_security".
267+ * @list: Pointer to "struct list_head".
268+ *
269+ * Returns nothing.
270+ */
271+static void ccs_add_task_security(struct ccs_security *ptr,
272+ struct list_head *list)
273+{
274+ unsigned long flags;
275+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
276+ list_add_rcu(&ptr->list, list);
277+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
278+}
279+
280+/**
281+ * __ccs_alloc_task_security - Allocate memory for new tasks.
282+ *
283+ * @task: Pointer to "struct task_struct".
284+ *
285+ * Returns 0 on success, negative value otherwise.
286+ */
287+static int __ccs_alloc_task_security(const struct task_struct *task)
288+{
289+ struct ccs_security *old_security = ccs_current_security();
290+ struct ccs_security *new_security = kzalloc(sizeof(*new_security),
291+ GFP_KERNEL);
292+ struct list_head *list = &ccs_task_security_list
293+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
294+ if (!new_security)
295+ return -ENOMEM;
296+ *new_security = *old_security;
297+ new_security->task = task;
298+ ccs_add_task_security(new_security, list);
299+ return 0;
300+}
301+
302+#if 0
303+/**
304+ * ccs_find_task_security - Find "struct ccs_security" for given task.
305+ *
306+ * @task: Pointer to "struct task_struct".
307+ *
308+ * Returns pointer to "struct ccs_security" on success, &ccs_oom_security on
309+ * out of memory, &ccs_default_security otherwise.
310+ *
311+ * If @task is current thread and "struct ccs_security" for current thread was
312+ * not found, I try to allocate it. But if allocation failed, current thread
313+ * will be killed by SIGKILL. Note that if current->pid == 1, sending SIGKILL
314+ * won't work.
315+ */
316+struct ccs_security *ccs_find_task_security(const struct task_struct *task)
317+{
318+ struct ccs_security *ptr;
319+ struct list_head *list = &ccs_task_security_list
320+ [hash_ptr((void *) task, CCS_TASK_SECURITY_HASH_BITS)];
321+ /* Make sure INIT_LIST_HEAD() in ccs_mm_init() takes effect. */
322+ while (!list->next);
323+ rcu_read_lock();
324+ list_for_each_entry_rcu(ptr, list, list) {
325+ if (ptr->task != task)
326+ continue;
327+ rcu_read_unlock();
328+ return ptr;
329+ }
330+ rcu_read_unlock();
331+ if (task != current)
332+ return &ccs_default_security;
333+ /* Use GFP_ATOMIC because caller may have called rcu_read_lock(). */
334+ ptr = kzalloc(sizeof(*ptr), GFP_ATOMIC);
335+ if (!ptr) {
336+ printk(KERN_WARNING "Unable to allocate memory for pid=%u\n",
337+ task->pid);
338+ send_sig(SIGKILL, current, 0);
339+ return &ccs_oom_security;
340+ }
341+ *ptr = ccs_default_security;
342+ ptr->task = task;
343+ ccs_add_task_security(ptr, list);
344+ return ptr;
345+}
346+#endif
347+
348+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
349+
350+/**
351+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
352+ *
353+ * @rcu: Pointer to "struct rcu_head".
354+ *
355+ * Returns nothing.
356+ */
357+static void ccs_rcu_free(struct rcu_head *rcu)
358+{
359+ struct ccs_security *ptr = container_of(rcu, typeof(*ptr), rcu);
360+ kfree(ptr);
361+}
362+
363+#else
364+
365+/**
366+ * ccs_rcu_free - RCU callback for releasing "struct ccs_security".
367+ *
368+ * @arg: Pointer to "void".
369+ *
370+ * Returns nothing.
371+ */
372+static void ccs_rcu_free(void *arg)
373+{
374+ struct ccs_security *ptr = arg;
375+ kfree(ptr);
376+}
377+
378+#endif
379+
380+/**
381+ * __ccs_free_task_security - Release memory associated with "struct task_struct".
382+ *
383+ * @task: Pointer to "struct task_struct".
384+ *
385+ * Returns nothing.
386+ */
387+static void __ccs_free_task_security(const struct task_struct *task)
388+{
389+ unsigned long flags;
390+ struct ccs_security *ptr = ccs_find_task_security(task);
391+ if (ptr == &ccs_default_security || ptr == &ccs_oom_security)
392+ return;
393+ spin_lock_irqsave(&ccs_task_security_list_lock, flags);
394+ list_del_rcu(&ptr->list);
395+ spin_unlock_irqrestore(&ccs_task_security_list_lock, flags);
396+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8)
397+ call_rcu(&ptr->rcu, ccs_rcu_free);
398+#else
399+ call_rcu(&ptr->rcu, ccs_rcu_free, ptr);
400+#endif
401+}
402+
403+#endif
404+
405+/**
406+ * ccs_mm_init - Initialize mm related code.
407+ *
408+ * Returns nothing.
409+ */
410+void __init ccs_mm_init(void)
411+{
412+ int idx;
413+ for (idx = 0; idx < CCS_MAX_HASH; idx++)
414+ INIT_LIST_HEAD(&ccs_name_list[idx]);
415+ for (idx = 0; idx < CCS_MAX_ACL_GROUPS; idx++) {
416+ INIT_LIST_HEAD(&ccs_acl_group[idx].acl_info_list[0]);
417+ INIT_LIST_HEAD(&ccs_acl_group[idx].acl_info_list[1]);
418+ }
419+ INIT_LIST_HEAD(&ccs_kernel_domain.acl_info_list[0]);
420+ INIT_LIST_HEAD(&ccs_kernel_domain.acl_info_list[1]);
421+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
422+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++)
423+ INIT_LIST_HEAD(&ccs_task_security_list[idx]);
424+#endif
425+ smp_wmb(); /* Avoid out of order execution. */
426+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
427+ ccsecurity_ops.alloc_task_security = __ccs_alloc_task_security;
428+ ccsecurity_ops.free_task_security = __ccs_free_task_security;
429+#endif
430+ ccs_kernel_domain.domainname = ccs_get_name(CCS_ROOT_NAME);
431+ list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
432+ idx = ccs_read_lock();
433+ if (ccs_find_domain(CCS_ROOT_NAME) != &ccs_kernel_domain)
434+ panic("Can't register ccs_kernel_domain");
435+#ifdef CONFIG_CCSECURITY_BUILTIN_INITIALIZERS
436+ {
437+ /* Load built-in policy. */
438+ static char ccs_builtin_initializers[] __initdata
439+ = CONFIG_CCSECURITY_BUILTIN_INITIALIZERS;
440+ char *cp = ccs_builtin_initializers;
441+ ccs_normalize_line(cp);
442+ while (cp && *cp) {
443+ char *cp2 = strchr(cp, ' ');
444+ if (cp2)
445+ *cp2++ = '\0';
446+ ccs_write_transition_control(cp, false,
447+ CCS_TRANSITION_CONTROL_INITIALIZE);
448+ cp = cp2;
449+ }
450+ }
451+#endif
452+ ccs_read_unlock(idx);
453+}
--- tags/patches/1.0.12/util.c (nonexistent)
+++ tags/patches/1.0.12/util.c (revision 197)
@@ -0,0 +1,1114 @@
1+/*
2+ * security/ccsecurity/util.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/* Lock for protecting policy. */
12+DEFINE_MUTEX(ccs_policy_lock);
13+
14+/* Has /sbin/init started? */
15+bool ccs_policy_loaded;
16+
17+/* Mapping table from "enum ccs_mac_index" to "enum ccs_mac_category_index". */
18+const u8 ccs_index2category[CCS_MAX_MAC_INDEX] = {
19+ /* CONFIG::file group */
20+ [CCS_MAC_FILE_EXECUTE] = CCS_MAC_CATEGORY_FILE,
21+ [CCS_MAC_FILE_OPEN] = CCS_MAC_CATEGORY_FILE,
22+ [CCS_MAC_FILE_CREATE] = CCS_MAC_CATEGORY_FILE,
23+ [CCS_MAC_FILE_UNLINK] = CCS_MAC_CATEGORY_FILE,
24+ [CCS_MAC_FILE_GETATTR] = CCS_MAC_CATEGORY_FILE,
25+ [CCS_MAC_FILE_MKDIR] = CCS_MAC_CATEGORY_FILE,
26+ [CCS_MAC_FILE_RMDIR] = CCS_MAC_CATEGORY_FILE,
27+ [CCS_MAC_FILE_MKFIFO] = CCS_MAC_CATEGORY_FILE,
28+ [CCS_MAC_FILE_MKSOCK] = CCS_MAC_CATEGORY_FILE,
29+ [CCS_MAC_FILE_TRUNCATE] = CCS_MAC_CATEGORY_FILE,
30+ [CCS_MAC_FILE_SYMLINK] = CCS_MAC_CATEGORY_FILE,
31+ [CCS_MAC_FILE_MKBLOCK] = CCS_MAC_CATEGORY_FILE,
32+ [CCS_MAC_FILE_MKCHAR] = CCS_MAC_CATEGORY_FILE,
33+ [CCS_MAC_FILE_LINK] = CCS_MAC_CATEGORY_FILE,
34+ [CCS_MAC_FILE_RENAME] = CCS_MAC_CATEGORY_FILE,
35+ [CCS_MAC_FILE_CHMOD] = CCS_MAC_CATEGORY_FILE,
36+ [CCS_MAC_FILE_CHOWN] = CCS_MAC_CATEGORY_FILE,
37+ [CCS_MAC_FILE_CHGRP] = CCS_MAC_CATEGORY_FILE,
38+ [CCS_MAC_FILE_IOCTL] = CCS_MAC_CATEGORY_FILE,
39+ [CCS_MAC_FILE_CHROOT] = CCS_MAC_CATEGORY_FILE,
40+ [CCS_MAC_FILE_MOUNT] = CCS_MAC_CATEGORY_FILE,
41+ [CCS_MAC_FILE_UMOUNT] = CCS_MAC_CATEGORY_FILE,
42+ [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
43+ /* CONFIG::misc group */
44+ [CCS_MAC_ENVIRON] = CCS_MAC_CATEGORY_MISC,
45+ /* CONFIG::network group */
46+ [CCS_MAC_NETWORK_INET_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
47+ [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
48+ [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
49+ [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
50+ [CCS_MAC_NETWORK_INET_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
51+ [CCS_MAC_NETWORK_INET_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
52+ [CCS_MAC_NETWORK_INET_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
53+ [CCS_MAC_NETWORK_INET_RAW_BIND] = CCS_MAC_CATEGORY_NETWORK,
54+ [CCS_MAC_NETWORK_INET_RAW_SEND] = CCS_MAC_CATEGORY_NETWORK,
55+ [CCS_MAC_NETWORK_INET_RAW_RECV] = CCS_MAC_CATEGORY_NETWORK,
56+ [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
57+ [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
58+ [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
59+ [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
60+ [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
61+ [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
62+ [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
63+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = CCS_MAC_CATEGORY_NETWORK,
64+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
65+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
66+ [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
67+ /* CONFIG::ipc group */
68+ [CCS_MAC_SIGNAL] = CCS_MAC_CATEGORY_IPC,
69+ /* CONFIG::capability group */
70+ [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
71+ [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
72+ [CCS_MAC_CAPABILITY_SYS_REBOOT] = CCS_MAC_CATEGORY_CAPABILITY,
73+ [CCS_MAC_CAPABILITY_SYS_VHANGUP] = CCS_MAC_CATEGORY_CAPABILITY,
74+ [CCS_MAC_CAPABILITY_SYS_SETTIME] = CCS_MAC_CATEGORY_CAPABILITY,
75+ [CCS_MAC_CAPABILITY_SYS_NICE] = CCS_MAC_CATEGORY_CAPABILITY,
76+ [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = CCS_MAC_CATEGORY_CAPABILITY,
77+ [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = CCS_MAC_CATEGORY_CAPABILITY,
78+ [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = CCS_MAC_CATEGORY_CAPABILITY,
79+ [CCS_MAC_CAPABILITY_SYS_PTRACE] = CCS_MAC_CATEGORY_CAPABILITY,
80+};
81+
82+/**
83+ * ccs_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
84+ *
85+ * @time: Seconds since 1970/01/01 00:00:00.
86+ * @stamp: Pointer to "struct ccs_time".
87+ *
88+ * Returns nothing.
89+ *
90+ * This function does not handle Y2038 problem.
91+ */
92+void ccs_convert_time(time_t time, struct ccs_time *stamp)
93+{
94+ static const u16 ccs_eom[2][12] = {
95+ { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
96+ { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
97+ };
98+ u16 y;
99+ u8 m;
100+ bool r;
101+ stamp->sec = time % 60;
102+ time /= 60;
103+ stamp->min = time % 60;
104+ time /= 60;
105+ stamp->hour = time % 24;
106+ time /= 24;
107+ for (y = 1970; ; y++) {
108+ const unsigned short days = (y & 3) ? 365 : 366;
109+ if (time < days)
110+ break;
111+ time -= days;
112+ }
113+ r = (y & 3) == 0;
114+ for (m = 0; m < 11 && time >= ccs_eom[r][m]; m++);
115+ if (m)
116+ time -= ccs_eom[r][m - 1];
117+ stamp->year = y;
118+ stamp->month = ++m;
119+ stamp->day = ++time;
120+}
121+
122+/**
123+ * ccs_permstr - Find permission keywords.
124+ *
125+ * @string: String representation for permissions in foo/bar/buz format.
126+ * @keyword: Keyword to find from @string/
127+ *
128+ * Returns ture if @keyword was found in @string, false otherwise.
129+ *
130+ * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
131+ */
132+bool ccs_permstr(const char *string, const char *keyword)
133+{
134+ const char *cp = strstr(string, keyword);
135+ if (cp)
136+ return cp == string || *(cp - 1) == '/';
137+ return false;
138+}
139+
140+/**
141+ * ccs_read_token - Read a word from a line.
142+ *
143+ * @param: Pointer to "struct ccs_acl_param".
144+ *
145+ * Returns a word on success, "" otherwise.
146+ *
147+ * To allow the caller to skip NULL check, this function returns "" rather than
148+ * NULL if there is no more words to read.
149+ */
150+char *ccs_read_token(struct ccs_acl_param *param)
151+{
152+ char *pos = param->data;
153+ char *del = strchr(pos, ' ');
154+ if (del)
155+ *del++ = '\0';
156+ else
157+ del = pos + strlen(pos);
158+ param->data = del;
159+ return pos;
160+}
161+
162+/**
163+ * ccs_get_domainname - Read a domainname from a line.
164+ *
165+ * @param: Pointer to "struct ccs_acl_param".
166+ *
167+ * Returns a domainname on success, NULL otherwise.
168+ */
169+const struct ccs_path_info *ccs_get_domainname(struct ccs_acl_param *param)
170+{
171+ char *start = param->data;
172+ char *pos = start;
173+ while (*pos) {
174+ if (*pos++ != ' ' || *pos++ == '/')
175+ continue;
176+ pos -= 2;
177+ *pos++ = '\0';
178+ break;
179+ }
180+ param->data = pos;
181+ if (ccs_correct_domain(start))
182+ return ccs_get_name(start);
183+ return NULL;
184+}
185+
186+/**
187+ * ccs_parse_ulong - Parse an "unsigned long" value.
188+ *
189+ * @result: Pointer to "unsigned long".
190+ * @str: Pointer to string to parse.
191+ *
192+ * Returns one of values in "enum ccs_value_type".
193+ *
194+ * The @src is updated to point the first character after the value
195+ * on success.
196+ */
197+u8 ccs_parse_ulong(unsigned long *result, char **str)
198+{
199+ const char *cp = *str;
200+ char *ep;
201+ int base = 10;
202+ if (*cp == '0') {
203+ char c = *(cp + 1);
204+ if (c == 'x' || c == 'X') {
205+ base = 16;
206+ cp += 2;
207+ } else if (c >= '0' && c <= '7') {
208+ base = 8;
209+ cp++;
210+ }
211+ }
212+ *result = simple_strtoul(cp, &ep, base);
213+ if (cp == ep)
214+ return CCS_VALUE_TYPE_INVALID;
215+ *str = ep;
216+ switch (base) {
217+ case 16:
218+ return CCS_VALUE_TYPE_HEXADECIMAL;
219+ case 8:
220+ return CCS_VALUE_TYPE_OCTAL;
221+ default:
222+ return CCS_VALUE_TYPE_DECIMAL;
223+ }
224+}
225+
226+/**
227+ * ccs_print_ulong - Print an "unsigned long" value.
228+ *
229+ * @buffer: Pointer to buffer.
230+ * @buffer_len: Size of @buffer.
231+ * @value: An "unsigned long" value.
232+ * @type: Type of @value.
233+ *
234+ * Returns nothing.
235+ */
236+void ccs_print_ulong(char *buffer, const int buffer_len,
237+ const unsigned long value, const u8 type)
238+{
239+ if (type == CCS_VALUE_TYPE_DECIMAL)
240+ snprintf(buffer, buffer_len, "%lu", value);
241+ else if (type == CCS_VALUE_TYPE_OCTAL)
242+ snprintf(buffer, buffer_len, "0%lo", value);
243+ else
244+ snprintf(buffer, buffer_len, "0x%lX", value);
245+}
246+
247+/**
248+ * ccs_parse_name_union - Parse a ccs_name_union.
249+ *
250+ * @filename: Name or name group.
251+ * @ptr: Pointer to "struct ccs_name_union".
252+ *
253+ * Returns true on success, false otherwise.
254+ */
255+bool ccs_parse_name_union(const char *filename, struct ccs_name_union *ptr)
256+{
257+ if (!ccs_correct_word(filename))
258+ return false;
259+ if (filename[0] == '@') {
260+ ptr->group = ccs_get_group(filename + 1, CCS_PATH_GROUP);
261+ ptr->is_group = true;
262+ return ptr->group != NULL;
263+ }
264+ ptr->filename = ccs_get_name(filename);
265+ ptr->is_group = false;
266+ return ptr->filename != NULL;
267+}
268+
269+/**
270+ * ccs_parse_number_union - Parse a ccs_number_union.
271+ *
272+ * @data: Number or number range or number group.
273+ * @ptr: Pointer to "struct ccs_number_union".
274+ *
275+ * Returns true on success, false otherwise.
276+ */
277+bool ccs_parse_number_union(char *data, struct ccs_number_union *ptr)
278+{
279+ u8 type;
280+ unsigned long v;
281+ memset(ptr, 0, sizeof(*ptr));
282+ if (!data[0])
283+ return false;
284+ if (data[0] == '@') {
285+ if (!ccs_correct_word(data))
286+ return false;
287+ ptr->group = ccs_get_group(data + 1, CCS_NUMBER_GROUP);
288+ ptr->is_group = true;
289+ return ptr->group != NULL;
290+ }
291+ type = ccs_parse_ulong(&v, &data);
292+ if (type == CCS_VALUE_TYPE_INVALID)
293+ return false;
294+ ptr->values[0] = v;
295+ ptr->value_type[0] = type;
296+ if (!*data) {
297+ ptr->values[1] = v;
298+ ptr->value_type[1] = type;
299+ return true;
300+ }
301+ if (*data++ != '-')
302+ return false;
303+ type = ccs_parse_ulong(&v, &data);
304+ if (type == CCS_VALUE_TYPE_INVALID || *data)
305+ return false;
306+ ptr->values[1] = v;
307+ ptr->value_type[1] = type;
308+ return true;
309+}
310+
311+/**
312+ * ccs_byte_range - Check whether the string is a \ooo style octal value.
313+ *
314+ * @str: Pointer to the string.
315+ *
316+ * Returns true if @str is a \ooo style octal value, false otherwise.
317+ */
318+static bool ccs_byte_range(const char *str)
319+{
320+ return *str >= '0' && *str++ <= '3' &&
321+ *str >= '0' && *str++ <= '7' &&
322+ *str >= '0' && *str <= '7';
323+}
324+
325+/**
326+ * ccs_decimal - Check whether the character is a decimal character.
327+ *
328+ * @c: The character to check.
329+ *
330+ * Returns true if @c is a decimal character, false otherwise.
331+ */
332+static bool ccs_decimal(const char c)
333+{
334+ return c >= '0' && c <= '9';
335+}
336+
337+/**
338+ * ccs_hexadecimal - Check whether the character is a hexadecimal character.
339+ *
340+ * @c: The character to check.
341+ *
342+ * Returns true if @c is a hexadecimal character, false otherwise.
343+ */
344+static bool ccs_hexadecimal(const char c)
345+{
346+ return (c >= '0' && c <= '9') ||
347+ (c >= 'A' && c <= 'F') ||
348+ (c >= 'a' && c <= 'f');
349+}
350+
351+/**
352+ * ccs_alphabet_char - Check whether the character is an alphabet.
353+ *
354+ * @c: The character to check.
355+ *
356+ * Returns true if @c is an alphabet character, false otherwise.
357+ */
358+static bool ccs_alphabet_char(const char c)
359+{
360+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
361+}
362+
363+/**
364+ * ccs_make_byte - Make byte value from three octal characters.
365+ *
366+ * @c1: The first character.
367+ * @c2: The second character.
368+ * @c3: The third character.
369+ *
370+ * Returns byte value.
371+ */
372+static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
373+{
374+ return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
375+}
376+
377+/**
378+ * ccs_str_starts - Check whether the given string starts with the given keyword.
379+ *
380+ * @src: Pointer to pointer to the string.
381+ * @find: Pointer to the keyword.
382+ *
383+ * Returns true if @src starts with @find, false otherwise.
384+ *
385+ * The @src is updated to point the first character after the @find
386+ * if @src starts with @find.
387+ */
388+bool ccs_str_starts(char **src, const char *find)
389+{
390+ const int len = strlen(find);
391+ char *tmp = *src;
392+ if (strncmp(tmp, find, len))
393+ return false;
394+ tmp += len;
395+ *src = tmp;
396+ return true;
397+}
398+
399+/**
400+ * ccs_normalize_line - Format string.
401+ *
402+ * @buffer: The line to normalize.
403+ *
404+ * Returns nothing.
405+ *
406+ * Leading and trailing whitespaces are removed.
407+ * Multiple whitespaces are packed into single space.
408+ */
409+void ccs_normalize_line(unsigned char *buffer)
410+{
411+ unsigned char *sp = buffer;
412+ unsigned char *dp = buffer;
413+ bool first = true;
414+ while (*sp && (*sp <= ' ' || *sp >= 127))
415+ sp++;
416+ while (*sp) {
417+ if (!first)
418+ *dp++ = ' ';
419+ first = false;
420+ while (*sp > ' ' && *sp < 127)
421+ *dp++ = *sp++;
422+ while (*sp && (*sp <= ' ' || *sp >= 127))
423+ sp++;
424+ }
425+ *dp = '\0';
426+}
427+
428+/**
429+ * ccs_tokenize - Tokenize string.
430+ *
431+ * @buffer: The line to tokenize.
432+ * @w: Pointer to "char *".
433+ * @size: Sizeof @w.
434+ *
435+ * Returns true on success, false otherwise.
436+ */
437+bool ccs_tokenize(char *buffer, char *w[], size_t size)
438+{
439+ int count = size / sizeof(char *);
440+ int i;
441+ for (i = 0; i < count; i++)
442+ w[i] = "";
443+ for (i = 0; i < count; i++) {
444+ char *cp = strchr(buffer, ' ');
445+ if (cp)
446+ *cp = '\0';
447+ w[i] = buffer;
448+ if (!cp)
449+ break;
450+ buffer = cp + 1;
451+ }
452+ return i < count || !*buffer;
453+}
454+
455+/**
456+ * ccs_correct_word2 - Check whether the given string follows the naming rules.
457+ *
458+ * @string: The byte sequence to check. Not '\0'-terminated.
459+ * @len: Length of @string.
460+ *
461+ * Returns true if @string follows the naming rules, false otherwise.
462+ */
463+static bool ccs_correct_word2(const char *string, size_t len)
464+{
465+ const char *const start = string;
466+ bool in_repetition = false;
467+ unsigned char c;
468+ unsigned char d;
469+ unsigned char e;
470+ if (!len)
471+ goto out;
472+ while (len--) {
473+ c = *string++;
474+ if (c == '\\') {
475+ if (!len--)
476+ goto out;
477+ c = *string++;
478+ switch (c) {
479+ case '\\': /* "\\" */
480+ continue;
481+ case '$': /* "\$" */
482+ case '+': /* "\+" */
483+ case '?': /* "\?" */
484+ case '*': /* "\*" */
485+ case '@': /* "\@" */
486+ case 'x': /* "\x" */
487+ case 'X': /* "\X" */
488+ case 'a': /* "\a" */
489+ case 'A': /* "\A" */
490+ case '-': /* "\-" */
491+ continue;
492+ case '{': /* "/\{" */
493+ if (string - 3 < start || *(string - 3) != '/')
494+ break;
495+ in_repetition = true;
496+ continue;
497+ case '}': /* "\}/" */
498+ if (*string != '/')
499+ break;
500+ if (!in_repetition)
501+ break;
502+ in_repetition = false;
503+ continue;
504+ case '0': /* "\ooo" */
505+ case '1':
506+ case '2':
507+ case '3':
508+ if (!len-- || !len--)
509+ break;
510+ d = *string++;
511+ e = *string++;
512+ if (d < '0' || d > '7' || e < '0' || e > '7')
513+ break;
514+ c = ccs_make_byte(c, d, e);
515+ if (c <= ' ' || c >= 127)
516+ continue;
517+ }
518+ goto out;
519+ } else if (in_repetition && c == '/') {
520+ goto out;
521+ } else if (c <= ' ' || c >= 127) {
522+ goto out;
523+ }
524+ }
525+ if (in_repetition)
526+ goto out;
527+ return true;
528+out:
529+ return false;
530+}
531+
532+/**
533+ * ccs_correct_word - Check whether the given string follows the naming rules.
534+ *
535+ * @string: The string to check.
536+ *
537+ * Returns true if @string follows the naming rules, false otherwise.
538+ */
539+bool ccs_correct_word(const char *string)
540+{
541+ return ccs_correct_word2(string, strlen(string));
542+}
543+
544+/**
545+ * ccs_correct_path - Check whether the given pathname follows the naming rules.
546+ *
547+ * @filename: The pathname to check.
548+ *
549+ * Returns true if @filename follows the naming rules, false otherwise.
550+ */
551+bool ccs_correct_path(const char *filename)
552+{
553+ return *filename == '/' && ccs_correct_word(filename);
554+}
555+
556+/**
557+ * ccs_correct_domain - Check whether the given domainname follows the naming rules.
558+ *
559+ * @domainname: The domainname to check.
560+ *
561+ * Returns true if @domainname follows the naming rules, false otherwise.
562+ */
563+bool ccs_correct_domain(const unsigned char *domainname)
564+{
565+ if (!domainname || strncmp(domainname, CCS_ROOT_NAME,
566+ CCS_ROOT_NAME_LEN))
567+ goto out;
568+ domainname += CCS_ROOT_NAME_LEN;
569+ if (!*domainname)
570+ return true;
571+ if (*domainname++ != ' ')
572+ goto out;
573+ while (1) {
574+ const unsigned char *cp = strchr(domainname, ' ');
575+ if (!cp)
576+ break;
577+ if (*domainname != '/' ||
578+ !ccs_correct_word2(domainname, cp - domainname - 1))
579+ goto out;
580+ domainname = cp + 1;
581+ }
582+ return ccs_correct_path(domainname);
583+out:
584+ return false;
585+}
586+
587+/**
588+ * ccs_domain_def - Check whether the given token can be a domainname.
589+ *
590+ * @buffer: The token to check.
591+ *
592+ * Returns true if @buffer possibly be a domainname, false otherwise.
593+ */
594+bool ccs_domain_def(const unsigned char *buffer)
595+{
596+ return !strncmp(buffer, CCS_ROOT_NAME, CCS_ROOT_NAME_LEN);
597+}
598+
599+/**
600+ * ccs_find_domain - Find a domain by the given name.
601+ *
602+ * @domainname: The domainname to find.
603+ *
604+ * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
605+ *
606+ * Caller holds ccs_read_lock().
607+ */
608+struct ccs_domain_info *ccs_find_domain(const char *domainname)
609+{
610+ struct ccs_domain_info *domain;
611+ struct ccs_path_info name;
612+ name.name = domainname;
613+ ccs_fill_path_info(&name);
614+ list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
615+ if (!domain->is_deleted &&
616+ !ccs_pathcmp(&name, domain->domainname))
617+ return domain;
618+ }
619+ return NULL;
620+}
621+
622+/**
623+ * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
624+ *
625+ * @filename: The string to evaluate.
626+ *
627+ * Returns the initial length without a pattern in @filename.
628+ */
629+static int ccs_const_part_length(const char *filename)
630+{
631+ char c;
632+ int len = 0;
633+ if (!filename)
634+ return 0;
635+ while (1) {
636+ c = *filename++;
637+ if (!c)
638+ break;
639+ if (c != '\\') {
640+ len++;
641+ continue;
642+ }
643+ c = *filename++;
644+ switch (c) {
645+ case '\\': /* "\\" */
646+ len += 2;
647+ continue;
648+ case '0': /* "\ooo" */
649+ case '1':
650+ case '2':
651+ case '3':
652+ c = *filename++;
653+ if (c < '0' || c > '7')
654+ break;
655+ c = *filename++;
656+ if (c < '0' || c > '7')
657+ break;
658+ len += 4;
659+ continue;
660+ }
661+ break;
662+ }
663+ return len;
664+}
665+
666+/**
667+ * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
668+ *
669+ * @ptr: Pointer to "struct ccs_path_info" to fill in.
670+ *
671+ * The caller sets "struct ccs_path_info"->name.
672+ */
673+void ccs_fill_path_info(struct ccs_path_info *ptr)
674+{
675+ const char *name = ptr->name;
676+ const int len = strlen(name);
677+ ptr->total_len = len;
678+ ptr->const_len = ccs_const_part_length(name);
679+ ptr->is_dir = len && (name[len - 1] == '/');
680+ ptr->is_patterned = (ptr->const_len < len);
681+ ptr->hash = full_name_hash(name, len);
682+}
683+
684+/**
685+ * ccs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
686+ *
687+ * @filename: The start of string to check.
688+ * @filename_end: The end of string to check.
689+ * @pattern: The start of pattern to compare.
690+ * @pattern_end: The end of pattern to compare.
691+ *
692+ * Returns true if @filename matches @pattern, false otherwise.
693+ */
694+static bool ccs_file_matches_pattern2(const char *filename,
695+ const char *filename_end,
696+ const char *pattern,
697+ const char *pattern_end)
698+{
699+ while (filename < filename_end && pattern < pattern_end) {
700+ char c;
701+ if (*pattern != '\\') {
702+ if (*filename++ != *pattern++)
703+ return false;
704+ continue;
705+ }
706+ c = *filename;
707+ pattern++;
708+ switch (*pattern) {
709+ int i;
710+ int j;
711+ case '?':
712+ if (c == '/') {
713+ return false;
714+ } else if (c == '\\') {
715+ if (filename[1] == '\\')
716+ filename++;
717+ else if (ccs_byte_range(filename + 1))
718+ filename += 3;
719+ else
720+ return false;
721+ }
722+ break;
723+ case '\\':
724+ if (c != '\\')
725+ return false;
726+ if (*++filename != '\\')
727+ return false;
728+ break;
729+ case '+':
730+ if (!ccs_decimal(c))
731+ return false;
732+ break;
733+ case 'x':
734+ if (!ccs_hexadecimal(c))
735+ return false;
736+ break;
737+ case 'a':
738+ if (!ccs_alphabet_char(c))
739+ return false;
740+ break;
741+ case '0':
742+ case '1':
743+ case '2':
744+ case '3':
745+ if (c == '\\' && ccs_byte_range(filename + 1)
746+ && !strncmp(filename + 1, pattern, 3)) {
747+ filename += 3;
748+ pattern += 2;
749+ break;
750+ }
751+ return false; /* Not matched. */
752+ case '*':
753+ case '@':
754+ for (i = 0; i <= filename_end - filename; i++) {
755+ if (ccs_file_matches_pattern2(filename + i,
756+ filename_end,
757+ pattern + 1,
758+ pattern_end))
759+ return true;
760+ c = filename[i];
761+ if (c == '.' && *pattern == '@')
762+ break;
763+ if (c != '\\')
764+ continue;
765+ if (filename[i + 1] == '\\')
766+ i++;
767+ else if (ccs_byte_range(filename + i + 1))
768+ i += 3;
769+ else
770+ break; /* Bad pattern. */
771+ }
772+ return false; /* Not matched. */
773+ default:
774+ j = 0;
775+ c = *pattern;
776+ if (c == '$') {
777+ while (ccs_decimal(filename[j]))
778+ j++;
779+ } else if (c == 'X') {
780+ while (ccs_hexadecimal(filename[j]))
781+ j++;
782+ } else if (c == 'A') {
783+ while (ccs_alphabet_char(filename[j]))
784+ j++;
785+ }
786+ for (i = 1; i <= j; i++) {
787+ if (ccs_file_matches_pattern2(filename + i,
788+ filename_end,
789+ pattern + 1,
790+ pattern_end))
791+ return true;
792+ }
793+ return false; /* Not matched or bad pattern. */
794+ }
795+ filename++;
796+ pattern++;
797+ }
798+ while (*pattern == '\\' &&
799+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
800+ pattern += 2;
801+ return filename == filename_end && pattern == pattern_end;
802+}
803+
804+/**
805+ * ccs_file_matches_pattern - Pattern matching without '/' character.
806+ *
807+ * @filename: The start of string to check.
808+ * @filename_end: The end of string to check.
809+ * @pattern: The start of pattern to compare.
810+ * @pattern_end: The end of pattern to compare.
811+ *
812+ * Returns true if @filename matches @pattern, false otherwise.
813+ */
814+static bool ccs_file_matches_pattern(const char *filename,
815+ const char *filename_end,
816+ const char *pattern,
817+ const char *pattern_end)
818+{
819+ const char *pattern_start = pattern;
820+ bool first = true;
821+ bool result;
822+ while (pattern < pattern_end - 1) {
823+ /* Split at "\-" pattern. */
824+ if (*pattern++ != '\\' || *pattern++ != '-')
825+ continue;
826+ result = ccs_file_matches_pattern2(filename, filename_end,
827+ pattern_start, pattern - 2);
828+ if (first)
829+ result = !result;
830+ if (result)
831+ return false;
832+ first = false;
833+ pattern_start = pattern;
834+ }
835+ result = ccs_file_matches_pattern2(filename, filename_end,
836+ pattern_start, pattern_end);
837+ return first ? result : !result;
838+}
839+
840+/**
841+ * ccs_path_matches_pattern2 - Do pathname pattern matching.
842+ *
843+ * @f: The start of string to check.
844+ * @p: The start of pattern to compare.
845+ *
846+ * Returns true if @f matches @p, false otherwise.
847+ */
848+static bool ccs_path_matches_pattern2(const char *f, const char *p)
849+{
850+ const char *f_delimiter;
851+ const char *p_delimiter;
852+ while (*f && *p) {
853+ f_delimiter = strchr(f, '/');
854+ if (!f_delimiter)
855+ f_delimiter = f + strlen(f);
856+ p_delimiter = strchr(p, '/');
857+ if (!p_delimiter)
858+ p_delimiter = p + strlen(p);
859+ if (*p == '\\' && *(p + 1) == '{')
860+ goto recursive;
861+ if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
862+ return false;
863+ f = f_delimiter;
864+ if (*f)
865+ f++;
866+ p = p_delimiter;
867+ if (*p)
868+ p++;
869+ }
870+ /* Ignore trailing "\*" and "\@" in @pattern. */
871+ while (*p == '\\' &&
872+ (*(p + 1) == '*' || *(p + 1) == '@'))
873+ p += 2;
874+ return !*f && !*p;
875+recursive:
876+ /*
877+ * The "\{" pattern is permitted only after '/' character.
878+ * This guarantees that below "*(p - 1)" is safe.
879+ * Also, the "\}" pattern is permitted only before '/' character
880+ * so that "\{" + "\}" pair will not break the "\-" operator.
881+ */
882+ if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
883+ *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
884+ return false; /* Bad pattern. */
885+ do {
886+ /* Compare current component with pattern. */
887+ if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
888+ p_delimiter - 2))
889+ break;
890+ /* Proceed to next component. */
891+ f = f_delimiter;
892+ if (!*f)
893+ break;
894+ f++;
895+ /* Continue comparison. */
896+ if (ccs_path_matches_pattern2(f, p_delimiter + 1))
897+ return true;
898+ f_delimiter = strchr(f, '/');
899+ } while (f_delimiter);
900+ return false; /* Not matched. */
901+}
902+
903+/**
904+ * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
905+ *
906+ * @filename: The filename to check.
907+ * @pattern: The pattern to compare.
908+ *
909+ * Returns true if matches, false otherwise.
910+ *
911+ * The following patterns are available.
912+ * \\ \ itself.
913+ * \ooo Octal representation of a byte.
914+ * \* Zero or more repetitions of characters other than '/'.
915+ * \@ Zero or more repetitions of characters other than '/' or '.'.
916+ * \? 1 byte character other than '/'.
917+ * \$ One or more repetitions of decimal digits.
918+ * \+ 1 decimal digit.
919+ * \X One or more repetitions of hexadecimal digits.
920+ * \x 1 hexadecimal digit.
921+ * \A One or more repetitions of alphabet characters.
922+ * \a 1 alphabet character.
923+ *
924+ * \- Subtraction operator.
925+ *
926+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
927+ * /dir/dir/dir/ ).
928+ */
929+bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
930+ const struct ccs_path_info *pattern)
931+{
932+ const char *f = filename->name;
933+ const char *p = pattern->name;
934+ const int len = pattern->const_len;
935+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
936+ if (!pattern->is_patterned)
937+ return !ccs_pathcmp(filename, pattern);
938+ /* Don't compare directory and non-directory. */
939+ if (filename->is_dir != pattern->is_dir)
940+ return false;
941+ /* Compare the initial length without patterns. */
942+ if (strncmp(f, p, len))
943+ return false;
944+ f += len;
945+ p += len;
946+ return ccs_path_matches_pattern2(f, p);
947+}
948+
949+/**
950+ * ccs_get_exe - Get ccs_realpath() of current process.
951+ *
952+ * Returns the ccs_realpath() of current process on success, NULL otherwise.
953+ *
954+ * This function uses kzalloc(), so the caller must kfree()
955+ * if this function didn't return NULL.
956+ */
957+const char *ccs_get_exe(void)
958+{
959+ struct mm_struct *mm = current->mm;
960+ struct vm_area_struct *vma;
961+ const char *cp = NULL;
962+ if (!mm)
963+ return NULL;
964+ down_read(&mm->mmap_sem);
965+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
966+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
967+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
968+ struct path path = { vma->vm_file->f_vfsmnt,
969+ vma->vm_file->f_dentry };
970+ cp = ccs_realpath_from_path(&path);
971+#else
972+ cp = ccs_realpath_from_path(&vma->vm_file->f_path);
973+#endif
974+ break;
975+ }
976+ }
977+ up_read(&mm->mmap_sem);
978+ return cp;
979+}
980+
981+/**
982+ * ccs_get_config - Get config for specified profile's specified functionality.
983+ *
984+ * @profile: Profile number.
985+ * @index: Index number of functionality.
986+ *
987+ * Returns config.
988+ *
989+ * First, check for CONFIG::category::functionality.
990+ * If CONFIG::category::functionality is set to use default, then check
991+ * CONFIG::category. If CONFIG::category is set to use default, then use
992+ * CONFIG. CONFIG cannot be set to use default.
993+ */
994+u8 ccs_get_config(const u8 profile, const u8 index)
995+{
996+ u8 config;
997+ const struct ccs_profile *p;
998+ if (!ccs_policy_loaded)
999+ return CCS_CONFIG_DISABLED;
1000+ p = ccs_profile(profile);
1001+ config = p->config[index];
1002+ if (config == CCS_CONFIG_USE_DEFAULT)
1003+ config = p->config[ccs_index2category[index]
1004+ + CCS_MAX_MAC_INDEX];
1005+ if (config == CCS_CONFIG_USE_DEFAULT)
1006+ config = p->default_config;
1007+ return config;
1008+}
1009+
1010+/**
1011+ * ccs_init_request_info - Initialize "struct ccs_request_info" members.
1012+ *
1013+ * @r: Pointer to "struct ccs_request_info" to initialize.
1014+ * @index: Index number of functionality.
1015+ *
1016+ * Returns mode.
1017+ *
1018+ * "task auto_domain_transition" keyword is evaluated before returning mode for
1019+ * @index. If "task auto_domain_transition" keyword was specified and
1020+ * transition to that domain failed, the current thread will be killed by
1021+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
1022+ */
1023+int ccs_init_request_info(struct ccs_request_info *r, const u8 index)
1024+{
1025+ u8 i;
1026+ const char *buf;
1027+ for (i = 0; i < 255; i++) {
1028+ struct ccs_domain_info *domain = ccs_current_domain();
1029+ const u8 profile = domain->profile;
1030+ memset(r, 0, sizeof(*r));
1031+ r->profile = profile;
1032+ r->type = index;
1033+ r->mode = ccs_get_mode(profile, index);
1034+ r->param_type = CCS_TYPE_AUTO_TASK_ACL;
1035+ ccs_check_acl(r, NULL);
1036+ if (!r->granted)
1037+ return r->mode;
1038+ buf = container_of(r->matched_acl, typeof(struct ccs_task_acl),
1039+ head)->domainname->name;
1040+ if (!ccs_assign_domain(buf, profile, domain->group, true))
1041+ break;
1042+ }
1043+ ccs_transition_failed(buf);
1044+ return CCS_CONFIG_DISABLED;
1045+}
1046+
1047+/**
1048+ * ccs_domain_quota_ok - Check for domain's quota.
1049+ *
1050+ * @r: Pointer to "struct ccs_request_info".
1051+ *
1052+ * Returns true if the domain is not exceeded quota, false otherwise.
1053+ *
1054+ * Caller holds ccs_read_lock().
1055+ */
1056+bool ccs_domain_quota_ok(struct ccs_request_info *r)
1057+{
1058+ unsigned int count = 0;
1059+ struct ccs_domain_info * const domain = ccs_current_domain();
1060+ struct ccs_acl_info *ptr;
1061+ if (r->mode != CCS_CONFIG_LEARNING)
1062+ return false;
1063+ if (!domain)
1064+ return true;
1065+ list_for_each_entry_srcu(ptr, &domain->acl_info_list[0], list,
1066+ &ccs_ss) {
1067+ u16 perm;
1068+ u8 i;
1069+ if (ptr->is_deleted)
1070+ continue;
1071+ switch (ptr->type) {
1072+ case CCS_TYPE_PATH_ACL:
1073+ perm = container_of(ptr, struct ccs_path_acl,
1074+ head)->perm;
1075+ break;
1076+ case CCS_TYPE_PATH2_ACL:
1077+ perm = container_of(ptr, struct ccs_path2_acl,
1078+ head)->perm;
1079+ break;
1080+ case CCS_TYPE_PATH_NUMBER_ACL:
1081+ perm = container_of(ptr, struct ccs_path_number_acl,
1082+ head)->perm;
1083+ break;
1084+ case CCS_TYPE_MKDEV_ACL:
1085+ perm = container_of(ptr, struct ccs_mkdev_acl,
1086+ head)->perm;
1087+ break;
1088+ case CCS_TYPE_INET_ACL:
1089+ perm = container_of(ptr, struct ccs_inet_acl,
1090+ head)->perm;
1091+ break;
1092+ case CCS_TYPE_UNIX_ACL:
1093+ perm = container_of(ptr, struct ccs_unix_acl,
1094+ head)->perm;
1095+ break;
1096+ default:
1097+ perm = 1;
1098+ }
1099+ for (i = 0; i < 16; i++)
1100+ if (perm & (1 << i))
1101+ count++;
1102+ }
1103+ if (count < ccs_profile(r->profile)->pref[CCS_PREF_MAX_LEARNING_ENTRY])
1104+ return true;
1105+ if (!domain->flags[CCS_DIF_QUOTA_WARNED]) {
1106+ domain->flags[CCS_DIF_QUOTA_WARNED] = true;
1107+ /* r->granted = false; */
1108+ ccs_write_log(r, "%s", ccs_dif[CCS_DIF_QUOTA_WARNED]);
1109+ printk(KERN_WARNING "WARNING: "
1110+ "Domain '%s' has too many ACLs to hold. "
1111+ "Stopped learning mode.\n", domain->domainname->name);
1112+ }
1113+ return false;
1114+}
--- tags/patches/1.0.12/signal.c (nonexistent)
+++ tags/patches/1.0.12/signal.c (revision 197)
@@ -0,0 +1,217 @@
1+/*
2+ * security/ccsecurity/signal.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/* To support PID namespace. */
12+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
13+#define find_task_by_pid ccsecurity_exports.find_task_by_vpid
14+#endif
15+
16+/**
17+ * ccs_audit_signal_log - Audit signal log.
18+ *
19+ * @r: Pointer to "struct ccs_request_info".
20+ *
21+ * Returns 0 on success, negative value otherwise.
22+ */
23+static int ccs_audit_signal_log(struct ccs_request_info *r)
24+{
25+ return ccs_supervisor(r, "ipc signal %d %s\n", r->param.signal.sig,
26+ r->param.signal.dest_pattern);
27+}
28+
29+/**
30+ * ccs_check_signal_acl - Check permission for signal operation.
31+ *
32+ * @r: Pointer to "struct ccs_request_info".
33+ * @ptr: Pointer to "struct ccs_acl_info".
34+ *
35+ * Returns true if granted, false otherwise.
36+ */
37+static bool ccs_check_signal_acl(struct ccs_request_info *r,
38+ const struct ccs_acl_info *ptr)
39+{
40+ const struct ccs_signal_acl *acl =
41+ container_of(ptr, typeof(*acl), head);
42+ if (acl->sig == r->param.signal.sig) {
43+ const int len = acl->domainname->total_len;
44+ if (!strncmp(acl->domainname->name,
45+ r->param.signal.dest_pattern, len)) {
46+ switch (r->param.signal.dest_pattern[len]) {
47+ case ' ':
48+ case '\0':
49+ return true;
50+ }
51+ }
52+ }
53+ return false;
54+}
55+
56+/**
57+ * ccs_signal_acl2 - Check permission for signal.
58+ *
59+ * @sig: Signal number.
60+ * @pid: Target's PID.
61+ *
62+ * Returns 0 on success, negative value otherwise.
63+ *
64+ * Caller holds ccs_read_lock().
65+ */
66+static int ccs_signal_acl2(const int sig, const int pid)
67+{
68+ struct ccs_request_info r;
69+ struct ccs_domain_info *dest = NULL;
70+ int error;
71+ const struct ccs_domain_info * const domain = ccs_current_domain();
72+ if (ccs_init_request_info(&r, CCS_MAC_SIGNAL) == CCS_CONFIG_DISABLED)
73+ return 0;
74+ if (!sig)
75+ return 0; /* No check for NULL signal. */
76+ r.param_type = CCS_TYPE_SIGNAL_ACL;
77+ r.param.signal.sig = sig;
78+ r.param.signal.dest_pattern = domain->domainname->name;
79+ r.granted = true;
80+ if (ccs_sys_getpid() == pid) {
81+ ccs_audit_signal_log(&r);
82+ return 0; /* No check for self process. */
83+ }
84+ { /* Simplified checking. */
85+ struct task_struct *p = NULL;
86+ ccs_tasklist_lock();
87+ if (pid > 0)
88+ p = find_task_by_pid((pid_t) pid);
89+ else if (pid == 0)
90+ p = current;
91+ else if (pid == -1)
92+ dest = &ccs_kernel_domain;
93+ else
94+ p = find_task_by_pid((pid_t) -pid);
95+ if (p)
96+ dest = ccs_task_domain(p);
97+ ccs_tasklist_unlock();
98+ }
99+ if (!dest)
100+ return 0; /* I can't find destinatioin. */
101+ if (domain == dest) {
102+ ccs_audit_signal_log(&r);
103+ return 0; /* No check for self domain. */
104+ }
105+ r.param.signal.dest_pattern = dest->domainname->name;
106+ do {
107+ ccs_check_acl(&r, ccs_check_signal_acl);
108+ error = ccs_audit_signal_log(&r);
109+ } while (error == CCS_RETRY_REQUEST);
110+ return error;
111+}
112+
113+/**
114+ * ccs_signal_acl - Check permission for signal.
115+ *
116+ * @pid: Target's PID.
117+ * @sig: Signal number.
118+ *
119+ * Returns 0 on success, negative value otherwise.
120+ */
121+static int ccs_signal_acl(const int pid, const int sig)
122+{
123+ int error;
124+ if (!sig)
125+ error = 0;
126+ else {
127+ const int idx = ccs_read_lock();
128+ error = ccs_signal_acl2(sig, pid);
129+ ccs_read_unlock(idx);
130+ }
131+ return error;
132+}
133+
134+/**
135+ * ccs_signal_acl0 - Permission check for signal().
136+ *
137+ * @tgid: Unused.
138+ * @pid: Target's PID.
139+ * @sig: Signal number.
140+ *
141+ * Returns 0 on success, negative value otherwise.
142+ */
143+static int ccs_signal_acl0(pid_t tgid, pid_t pid, int sig)
144+{
145+ return ccs_signal_acl(pid, sig);
146+}
147+
148+/**
149+ * ccs_same_signal_acl - Check for duplicated "struct ccs_signal_acl" entry.
150+ *
151+ * @a: Pointer to "struct ccs_acl_info".
152+ * @b: Pointer to "struct ccs_acl_info".
153+ *
154+ * Returns true if @a == @b, false otherwise.
155+ */
156+static bool ccs_same_signal_acl(const struct ccs_acl_info *a,
157+ const struct ccs_acl_info *b)
158+{
159+ const struct ccs_signal_acl *p1 = container_of(a, typeof(*p1), head);
160+ const struct ccs_signal_acl *p2 = container_of(b, typeof(*p2), head);
161+ return p1->head.type == p2->head.type && p1->head.cond == p2->head.cond
162+ && p1->head.type == CCS_TYPE_SIGNAL_ACL && p1->sig == p2->sig
163+ && p1->domainname == p2->domainname;
164+}
165+
166+/**
167+ * ccs_write_signal - Write "struct ccs_signal_acl" list.
168+ *
169+ * @param: Pointer to "struct ccs_acl_param".
170+ *
171+ * Returns 0 on success, negative value otherwise.
172+ */
173+static int ccs_write_signal(struct ccs_acl_param *param)
174+{
175+ struct ccs_signal_acl e = { .head.type = CCS_TYPE_SIGNAL_ACL };
176+ int error;
177+ int sig;
178+ if (sscanf(ccs_read_token(param), "%d", &sig) != 1)
179+ return -EINVAL;
180+ e.sig = sig;
181+ e.domainname = ccs_get_domainname(param);
182+ if (!e.domainname)
183+ error = -EINVAL;
184+ else
185+ error = ccs_update_domain(&e.head, sizeof(e), param,
186+ ccs_same_signal_acl, NULL);
187+ ccs_put_name(e.domainname);
188+ return error;
189+}
190+
191+/**
192+ * ccs_write_ipc - Update ipc related list.
193+ *
194+ * @param: Pointer to "struct ccs_acl_param".
195+ *
196+ * Returns 0 on success, negative value otherwise.
197+ */
198+int ccs_write_ipc(struct ccs_acl_param *param)
199+{
200+ if (ccs_str_starts(&param->data, "signal "))
201+ return ccs_write_signal(param);
202+ return -EINVAL;
203+}
204+
205+/**
206+ * ccs_file_init - Register ipc related hooks.
207+ *
208+ * Returns nothing.
209+ */
210+void __init ccs_signal_init(void)
211+{
212+ ccsecurity_ops.kill_permission = ccs_signal_acl;
213+ ccsecurity_ops.tgkill_permission = ccs_signal_acl0;
214+ ccsecurity_ops.tkill_permission = ccs_signal_acl;
215+ ccsecurity_ops.sigqueue_permission = ccs_signal_acl;
216+ ccsecurity_ops.tgsigqueue_permission = ccs_signal_acl0;
217+}
--- tags/patches/1.0.12/environ.c (nonexistent)
+++ tags/patches/1.0.12/environ.c (revision 197)
@@ -0,0 +1,117 @@
1+/*
2+ * security/ccsecurity/environ.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/**
12+ * ccs_check_env_acl - Check permission for environment variable's name.
13+ *
14+ * @r: Pointer to "struct ccs_request_info".
15+ * @ptr: Pointer to "struct ccs_acl_info".
16+ *
17+ * Returns true if granted, false otherwise.
18+ */
19+static bool ccs_check_env_acl(struct ccs_request_info *r,
20+ const struct ccs_acl_info *ptr)
21+{
22+ const struct ccs_env_acl *acl = container_of(ptr, typeof(*acl), head);
23+ return ccs_path_matches_pattern(r->param.environ.name, acl->env);
24+}
25+
26+/**
27+ * ccs_audit_env_log - Audit environment variable name log.
28+ *
29+ * @r: Pointer to "struct ccs_request_info".
30+ *
31+ * Returns 0 on success, negative value otherwise.
32+ */
33+static int ccs_audit_env_log(struct ccs_request_info *r)
34+{
35+ return ccs_supervisor(r, "misc env %s\n", r->param.environ.name->name);
36+}
37+
38+/**
39+ * ccs_env_perm - Check permission for environment variable's name.
40+ *
41+ * @r: Pointer to "struct ccs_request_info".
42+ * @env: The name of environment variable.
43+ *
44+ * Returns 0 on success, negative value otherwise.
45+ *
46+ * Caller holds ccs_read_lock().
47+ */
48+int ccs_env_perm(struct ccs_request_info *r, const char *env)
49+{
50+ struct ccs_path_info environ;
51+ int error;
52+ if (!env || !*env)
53+ return 0;
54+ environ.name = env;
55+ ccs_fill_path_info(&environ);
56+ r->param_type = CCS_TYPE_ENV_ACL;
57+ r->param.environ.name = &environ;
58+ do {
59+ ccs_check_acl(r, ccs_check_env_acl);
60+ error = ccs_audit_env_log(r);
61+ } while (error == CCS_RETRY_REQUEST);
62+ return error;
63+}
64+
65+/**
66+ * ccs_same_env_acl - Check for duplicated "struct ccs_env_acl" entry.
67+ *
68+ * @a: Pointer to "struct ccs_acl_info".
69+ * @b: Pointer to "struct ccs_acl_info".
70+ *
71+ * Returns true if @a == @b, false otherwise.
72+ */
73+static bool ccs_same_env_acl(const struct ccs_acl_info *a,
74+ const struct ccs_acl_info *b)
75+{
76+ const struct ccs_env_acl *p1 = container_of(a, typeof(*p1), head);
77+ const struct ccs_env_acl *p2 = container_of(b, typeof(*p2), head);
78+ return p1->head.type == p2->head.type && p1->head.cond == p2->head.cond
79+ && p1->head.type == CCS_TYPE_ENV_ACL && p1->env == p2->env;
80+}
81+
82+/**
83+ * ccs_write_env - Write "struct ccs_env_acl" list.
84+ *
85+ * @param: Pointer to "struct ccs_acl_param".
86+ *
87+ * Returns 0 on success, negative value otherwise.
88+ */
89+static int ccs_write_env(struct ccs_acl_param *param)
90+{
91+ struct ccs_env_acl e = { .head.type = CCS_TYPE_ENV_ACL };
92+ int error = -ENOMEM;
93+ const char *data = ccs_read_token(param);
94+ if (!ccs_correct_word(data) || strchr(data, '='))
95+ return -EINVAL;
96+ e.env = ccs_get_name(data);
97+ if (!e.env)
98+ return error;
99+ error = ccs_update_domain(&e.head, sizeof(e), param,
100+ ccs_same_env_acl, NULL);
101+ ccs_put_name(e.env);
102+ return error;
103+}
104+
105+/**
106+ * ccs_write_misc - Update environment variable list.
107+ *
108+ * @param: Pointer to "struct ccs_acl_param".
109+ *
110+ * Returns 0 on success, negative value otherwise.
111+ */
112+int ccs_write_misc(struct ccs_acl_param *param)
113+{
114+ if (ccs_str_starts(&param->data, "env "))
115+ return ccs_write_env(param);
116+ return -EINVAL;
117+}
--- tags/patches/1.0.12/proc_if.c (nonexistent)
+++ tags/patches/1.0.12/proc_if.c (revision 197)
@@ -0,0 +1,379 @@
1+/*
2+ * security/ccsecurity/proc_if.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/**
12+ * ccs_check_task_acl - Check permission for task operation.
13+ *
14+ * @r: Pointer to "struct ccs_request_info".
15+ * @ptr: Pointer to "struct ccs_acl_info".
16+ *
17+ * Returns true if granted, false otherwise.
18+ */
19+static bool ccs_check_task_acl(struct ccs_request_info *r,
20+ const struct ccs_acl_info *ptr)
21+{
22+ const struct ccs_task_acl *acl = container_of(ptr, typeof(*acl), head);
23+ return !ccs_pathcmp(r->param.task.domainname, acl->domainname);
24+}
25+
26+/**
27+ * ccs_write_self - write() for /proc/ccs/self_domain interface.
28+ *
29+ * @file: Pointer to "struct file".
30+ * @buf: Domainname to transit to.
31+ * @count: Size of @buf.
32+ * @ppos: Unused.
33+ *
34+ * Returns @count on success, negative value otherwise.
35+ *
36+ * If domain transition was permitted but the domain transition failed, this
37+ * function returns error rather than terminating current thread with SIGKILL.
38+ */
39+static ssize_t ccs_write_self(struct file *file, const char __user *buf,
40+ size_t count, loff_t *ppos)
41+{
42+ char *data;
43+ int error;
44+ if (!count || count >= CCS_EXEC_TMPSIZE - 10)
45+ return -ENOMEM;
46+ data = kzalloc(count + 1, CCS_GFP_FLAGS);
47+ if (!data)
48+ return -ENOMEM;
49+ if (copy_from_user(data, buf, count)) {
50+ error = -EFAULT;
51+ goto out;
52+ }
53+ ccs_normalize_line(data);
54+ if (ccs_correct_domain(data)) {
55+ const int idx = ccs_read_lock();
56+ struct ccs_path_info name;
57+ struct ccs_request_info r;
58+ name.name = data;
59+ ccs_fill_path_info(&name);
60+ /* Check "task manual_domain_transition" permission. */
61+ ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
62+ r.param_type = CCS_TYPE_MANUAL_TASK_ACL;
63+ r.param.task.domainname = &name;
64+ ccs_check_acl(&r, ccs_check_task_acl);
65+ if (!r.granted)
66+ error = -EPERM;
67+ else
68+ error = ccs_assign_domain(data, r.profile,
69+ ccs_current_domain()->group,
70+ true) ? 0 : -ENOENT;
71+ ccs_read_unlock(idx);
72+ } else
73+ error = -EINVAL;
74+out:
75+ kfree(data);
76+ return error ? error : count;
77+}
78+
79+/**
80+ * ccs_read_self - read() for /proc/ccs/self_domain interface.
81+ *
82+ * @file: Pointer to "struct file".
83+ * @buf: Domainname which current thread belongs to.
84+ * @count: Size of @buf.
85+ * @ppos: Bytes read by now.
86+ *
87+ * Returns read size on success, negative value otherwise.
88+ */
89+static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
90+ loff_t *ppos)
91+{
92+ const char *domain = ccs_current_domain()->domainname->name;
93+ loff_t len = strlen(domain);
94+ loff_t pos = *ppos;
95+ if (pos >= len || !count)
96+ return 0;
97+ len -= pos;
98+ if (count < len)
99+ len = count;
100+ if (copy_to_user(buf, domain + pos, len))
101+ return -EFAULT;
102+ *ppos += len;
103+ return len;
104+}
105+
106+/* Operations for /proc/ccs/self_domain interface. */
107+static
108+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
109+const
110+#endif
111+struct file_operations ccs_self_operations = {
112+ .write = ccs_write_self,
113+ .read = ccs_read_self,
114+};
115+
116+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)
117+#if !defined(RHEL_VERSION) || RHEL_VERSION != 3
118+
119+/**
120+ * PDE - Get "struct proc_dir_entry".
121+ *
122+ * @inode: Pointer to "struct inode".
123+ *
124+ * Returns pointer to "struct proc_dir_entry".
125+ *
126+ * This is for compatibility with older kernels.
127+ */
128+static inline struct proc_dir_entry *PDE(const struct inode *inode)
129+{
130+ return (struct proc_dir_entry *) inode->u.generic_ip;
131+}
132+
133+#endif
134+#endif
135+
136+/**
137+ * ccs_open - open() for /proc/ccs/ interface.
138+ *
139+ * @inode: Pointer to "struct inode".
140+ * @file: Pointer to "struct file".
141+ *
142+ * Returns 0 on success, negative value otherwise.
143+ */
144+static int ccs_open(struct inode *inode, struct file *file)
145+{
146+ return ccs_open_control(((u8 *) PDE(inode)->data) - ((u8 *) NULL),
147+ file);
148+}
149+
150+/**
151+ * ccs_release - close() for /proc/ccs/ interface.
152+ *
153+ * @inode: Pointer to "struct inode".
154+ * @file: Pointer to "struct file".
155+ *
156+ * Returns 0 on success, negative value otherwise.
157+ */
158+static int ccs_release(struct inode *inode, struct file *file)
159+{
160+ return ccs_close_control(file);
161+}
162+
163+/**
164+ * ccs_poll - poll() for /proc/ccs/ interface.
165+ *
166+ * @file: Pointer to "struct file".
167+ * @wait: Pointer to "poll_table".
168+ *
169+ * Returns 0 on success, negative value otherwise.
170+ */
171+static unsigned int ccs_poll(struct file *file, poll_table *wait)
172+{
173+ return ccs_poll_control(file, wait);
174+}
175+
176+/**
177+ * ccs_read - read() for /proc/ccs/ interface.
178+ *
179+ * @file: Pointer to "struct file".
180+ * @buf: Pointer to buffer.
181+ * @count: Size of @buf.
182+ * @ppos: Unused.
183+ *
184+ * Returns bytes read on success, negative value otherwise.
185+ */
186+static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
187+ loff_t *ppos)
188+{
189+ return ccs_read_control(file, buf, count);
190+}
191+
192+/**
193+ * ccs_write - write() for /proc/ccs/ interface.
194+ *
195+ * @file: Pointer to "struct file".
196+ * @buf: Pointer to buffer.
197+ * @count: Size of @buf.
198+ * @ppos: Unused.
199+ *
200+ * Returns @count on success, negative value otherwise.
201+ */
202+static ssize_t ccs_write(struct file *file, const char __user *buf,
203+ size_t count, loff_t *ppos)
204+{
205+ return ccs_write_control(file, buf, count);
206+}
207+
208+/* Operations for /proc/ccs/ interface. */
209+static
210+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
211+const
212+#endif
213+struct file_operations ccs_operations = {
214+ .open = ccs_open,
215+ .release = ccs_release,
216+ .poll = ccs_poll,
217+ .read = ccs_read,
218+ .write = ccs_write,
219+};
220+
221+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
222+
223+struct iattr;
224+
225+/**
226+ * proc_notify_change - Update inode's attributes and reflect to the dentry.
227+ *
228+ * @dentry: Pointer to "struct dentry".
229+ * @iattr: Pointer to "struct iattr".
230+ *
231+ * Returns 0 on success, negative value otherwise.
232+ *
233+ * The 2.4 kernels don't allow chmod()/chown() for files in /proc,
234+ * while the 2.6 kernels allow.
235+ * To permit management of /proc/ccs/ interface by non-root user,
236+ * I modified to allow chmod()/chown() of /proc/ccs/ interface like 2.6 kernels
237+ * by adding "struct inode_operations"->setattr hook.
238+ */
239+static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
240+{
241+ struct inode *inode = dentry->d_inode;
242+ struct proc_dir_entry *de = PDE(inode);
243+ int error;
244+
245+ error = inode_change_ok(inode, iattr);
246+ if (error)
247+ goto out;
248+
249+ error = inode_setattr(inode, iattr);
250+ if (error)
251+ goto out;
252+
253+ de->uid = inode->i_uid;
254+ de->gid = inode->i_gid;
255+ de->mode = inode->i_mode;
256+out:
257+ return error;
258+}
259+
260+/* The inode operations for /proc/ccs/ directory. */
261+static struct inode_operations ccs_dir_inode_operations;
262+
263+/* The inode operations for files under /proc/ccs/ directory. */
264+static struct inode_operations ccs_file_inode_operations;
265+
266+#endif
267+
268+/**
269+ * ccs_create_entry - Create interface files under /proc/ccs/ directory.
270+ *
271+ * @name: The name of the interface file.
272+ * @mode: The permission of the interface file.
273+ * @parent: The parent directory.
274+ * @key: Type of interface.
275+ *
276+ * Returns nothing.
277+ */
278+static void __init ccs_create_entry(const char *name, const mode_t mode,
279+ struct proc_dir_entry *parent,
280+ const u8 key)
281+{
282+ struct proc_dir_entry *entry = create_proc_entry(name, mode, parent);
283+ if (entry) {
284+ entry->proc_fops = &ccs_operations;
285+ entry->data = ((u8 *) NULL) + key;
286+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
287+ if (entry->proc_iops)
288+ ccs_file_inode_operations = *entry->proc_iops;
289+ if (!ccs_file_inode_operations.setattr)
290+ ccs_file_inode_operations.setattr = proc_notify_change;
291+ entry->proc_iops = &ccs_file_inode_operations;
292+#endif
293+ }
294+}
295+
296+/**
297+ * ccs_proc_init - Initialize /proc/ccs/ interface.
298+ *
299+ * Returns 0.
300+ */
301+static void __init ccs_proc_init(void)
302+{
303+ struct proc_dir_entry *ccs_dir = proc_mkdir("ccs", NULL);
304+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
305+ if (ccs_dir->proc_iops)
306+ ccs_dir_inode_operations = *ccs_dir->proc_iops;
307+ if (!ccs_dir_inode_operations.setattr)
308+ ccs_dir_inode_operations.setattr = proc_notify_change;
309+ ccs_dir->proc_iops = &ccs_dir_inode_operations;
310+#endif
311+ ccs_create_entry("query", 0600, ccs_dir, CCS_QUERY);
312+ ccs_create_entry("domain_policy", 0600, ccs_dir, CCS_DOMAINPOLICY);
313+ ccs_create_entry("exception_policy", 0600, ccs_dir,
314+ CCS_EXCEPTIONPOLICY);
315+ ccs_create_entry("audit", 0400, ccs_dir, CCS_AUDIT);
316+ ccs_create_entry(".domain_status", 0600, ccs_dir, CCS_DOMAIN_STATUS);
317+ ccs_create_entry(".process_status", 0600, ccs_dir,
318+ CCS_PROCESS_STATUS);
319+ ccs_create_entry("stat", 0644, ccs_dir, CCS_STAT);
320+ ccs_create_entry("profile", 0600, ccs_dir, CCS_PROFILE);
321+ ccs_create_entry("manager", 0600, ccs_dir, CCS_MANAGER);
322+ ccs_create_entry("version", 0400, ccs_dir, CCS_VERSION);
323+ ccs_create_entry(".execute_handler", 0666, ccs_dir,
324+ CCS_EXECUTE_HANDLER);
325+ {
326+ struct proc_dir_entry *e = create_proc_entry("self_domain",
327+ 0666, ccs_dir);
328+ if (e)
329+ e->proc_fops = &ccs_self_operations;
330+ }
331+}
332+
333+/**
334+ * ccs_init_module - Initialize this module.
335+ *
336+ * Returns 0 on success, negative value otherwise.
337+ */
338+static int __init ccs_init_module(void)
339+{
340+ int i;
341+ for (i = 0; i < CCS_MAX_POLICY; i++)
342+ INIT_LIST_HEAD(&ccs_policy_list[i]);
343+ for (i = 0; i < CCS_MAX_GROUP; i++)
344+ INIT_LIST_HEAD(&ccs_group_list[i]);
345+ for (i = 0; i < CCS_MAX_LIST; i++)
346+ INIT_LIST_HEAD(&ccs_shared_list[i]);
347+ if (ccsecurity_ops.disabled)
348+ return -EINVAL;
349+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
350+ MOD_INC_USE_COUNT;
351+#endif
352+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
353+ if (init_srcu_struct(&ccs_ss))
354+ panic("Out of memory.");
355+#endif
356+ ccs_proc_init();
357+ ccs_mm_init();
358+ ccs_capability_init();
359+ ccs_file_init();
360+ ccs_network_init();
361+ ccs_signal_init();
362+ ccs_mount_init();
363+ ccs_policy_io_init();
364+ ccs_domain_init();
365+#ifdef CONFIG_CCSECURITY_USE_BUILTIN_POLICY
366+ ccs_load_builtin_policy();
367+#endif
368+ return 0;
369+}
370+
371+/**
372+ * ccs_main_init - Initialize this module.
373+ *
374+ * Returns nothing.
375+ */
376+void __init ccs_main_init(void)
377+{
378+ ccs_init_module();
379+}
--- tags/patches/1.0.12/capability.c (nonexistent)
+++ tags/patches/1.0.12/capability.c (revision 197)
@@ -0,0 +1,147 @@
1+/*
2+ * security/ccsecurity/capability.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/*
12+ * Mapping table from "enum ccs_capability_acl_index" to "enum ccs_mac_index".
13+ */
14+const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX] = {
15+ [CCS_USE_ROUTE_SOCKET] = CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
16+ [CCS_USE_PACKET_SOCKET] = CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
17+ [CCS_SYS_REBOOT] = CCS_MAC_CAPABILITY_SYS_REBOOT,
18+ [CCS_SYS_VHANGUP] = CCS_MAC_CAPABILITY_SYS_VHANGUP,
19+ [CCS_SYS_SETTIME] = CCS_MAC_CAPABILITY_SYS_SETTIME,
20+ [CCS_SYS_NICE] = CCS_MAC_CAPABILITY_SYS_NICE,
21+ [CCS_SYS_SETHOSTNAME] = CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
22+ [CCS_USE_KERNEL_MODULE] = CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
23+ [CCS_SYS_KEXEC_LOAD] = CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
24+ [CCS_SYS_PTRACE] = CCS_MAC_CAPABILITY_SYS_PTRACE,
25+};
26+
27+/**
28+ * ccs_audit_capability_log - Audit capability log.
29+ *
30+ * @r: Pointer to "struct ccs_request_info".
31+ *
32+ * Returns 0 on success, negative value otherwise.
33+ */
34+static int ccs_audit_capability_log(struct ccs_request_info *r)
35+{
36+ return ccs_supervisor(r, "capability %s\n", ccs_mac_keywords
37+ [ccs_c2mac[r->param.capability.operation]]);
38+}
39+
40+/**
41+ * ccs_check_capability_acl - Check permission for capability operation.
42+ *
43+ * @r: Pointer to "struct ccs_request_info".
44+ * @ptr: Pointer to "struct ccs_acl_info".
45+ *
46+ * Returns true if granted, false otherwise.
47+ */
48+static bool ccs_check_capability_acl(struct ccs_request_info *r,
49+ const struct ccs_acl_info *ptr)
50+{
51+ const struct ccs_capability_acl *acl =
52+ container_of(ptr, typeof(*acl), head);
53+ return acl->operation == r->param.capability.operation;
54+}
55+
56+/**
57+ * ccs_capable - Check permission for capability.
58+ *
59+ * @operation: Type of operation.
60+ *
61+ * Returns true on success, false otherwise.
62+ */
63+static bool __ccs_capable(const u8 operation)
64+{
65+ struct ccs_request_info r;
66+ int error = 0;
67+ const int idx = ccs_read_lock();
68+ if (ccs_init_request_info(&r, ccs_c2mac[operation])
69+ != CCS_CONFIG_DISABLED) {
70+ r.param_type = CCS_TYPE_CAPABILITY_ACL;
71+ r.param.capability.operation = operation;
72+ do {
73+ ccs_check_acl(&r, ccs_check_capability_acl);
74+ error = ccs_audit_capability_log(&r);
75+ } while (error == CCS_RETRY_REQUEST);
76+ }
77+ ccs_read_unlock(idx);
78+ return !error;
79+}
80+
81+/**
82+ * __ccs_ptrace_permission - Check permission for ptrace().
83+ *
84+ * @request: Unused.
85+ * @pid: Unused.
86+ *
87+ * Returns 0 on success, negative value otherwise.
88+ *
89+ * Since this function is called from location where it is permitted to sleep,
90+ * it is racy to check target process's domainname anyway. Therefore, we don't
91+ * use target process's domainname.
92+ */
93+static int __ccs_ptrace_permission(long request, long pid)
94+{
95+ return __ccs_capable(CCS_SYS_PTRACE) ? 0 : -EPERM;
96+}
97+
98+/**
99+ * ccs_same_capability_acl - Check for duplicated "struct ccs_capability_acl" entry.
100+ *
101+ * @a: Pointer to "struct ccs_acl_info".
102+ * @b: Pointer to "struct ccs_acl_info".
103+ *
104+ * Returns true if @a == @b, false otherwise.
105+ */
106+static bool ccs_same_capability_acl(const struct ccs_acl_info *a,
107+ const struct ccs_acl_info *b)
108+{
109+ const struct ccs_capability_acl *p1 = container_of(a, typeof(*p1),
110+ head);
111+ const struct ccs_capability_acl *p2 = container_of(b, typeof(*p2),
112+ head);
113+ return p1->operation == p2->operation;
114+}
115+
116+/**
117+ * ccs_write_capability - Write "struct ccs_capability_acl" list.
118+ *
119+ * @param: Pointer to "struct ccs_acl_param".
120+ *
121+ * Returns 0 on success, negative value otherwise.
122+ */
123+int ccs_write_capability(struct ccs_acl_param *param)
124+{
125+ struct ccs_capability_acl e = { .head.type = CCS_TYPE_CAPABILITY_ACL };
126+ const char *operation = ccs_read_token(param);
127+ for (e.operation = 0; e.operation < CCS_MAX_CAPABILITY_INDEX;
128+ e.operation++) {
129+ if (strcmp(operation,
130+ ccs_mac_keywords[ccs_c2mac[e.operation]]))
131+ continue;
132+ return ccs_update_domain(&e.head, sizeof(e), param,
133+ ccs_same_capability_acl, NULL);
134+ }
135+ return -EINVAL;
136+}
137+
138+/**
139+ * ccs_capability_init - Register capability related hooks.
140+ *
141+ * Returns nothing.
142+ */
143+void __init ccs_capability_init(void)
144+{
145+ ccsecurity_ops.capable = __ccs_capable;
146+ ccsecurity_ops.ptrace_permission = __ccs_ptrace_permission;
147+}
--- tags/patches/1.0.12/internal.h (nonexistent)
+++ tags/patches/1.0.12/internal.h (revision 197)
@@ -0,0 +1,2121 @@
1+/*
2+ * security/ccsecurity/internal.h
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
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 bool
84+#define bool _Bool
85+#endif
86+#ifndef false
87+#define false 0
88+#endif
89+#ifndef true
90+#define true 1
91+#endif
92+
93+#ifndef __user
94+#define __user
95+#endif
96+
97+#ifndef current_uid
98+#define current_uid() (current->uid)
99+#endif
100+#ifndef current_gid
101+#define current_gid() (current->gid)
102+#endif
103+#ifndef current_euid
104+#define current_euid() (current->euid)
105+#endif
106+#ifndef current_egid
107+#define current_egid() (current->egid)
108+#endif
109+#ifndef current_suid
110+#define current_suid() (current->suid)
111+#endif
112+#ifndef current_sgid
113+#define current_sgid() (current->sgid)
114+#endif
115+#ifndef current_fsuid
116+#define current_fsuid() (current->fsuid)
117+#endif
118+#ifndef current_fsgid
119+#define current_fsgid() (current->fsgid)
120+#endif
121+
122+#ifndef DEFINE_SPINLOCK
123+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
124+#endif
125+
126+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
127+#define mutex semaphore
128+#define mutex_init(mutex) init_MUTEX(mutex)
129+#define mutex_unlock(mutex) up(mutex)
130+#define mutex_lock(mutex) down(mutex)
131+#define mutex_lock_interruptible(mutex) down_interruptible(mutex)
132+#define mutex_trylock(mutex) (!down_trylock(mutex))
133+#define DEFINE_MUTEX(mutexname) DECLARE_MUTEX(mutexname)
134+#endif
135+
136+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
137+#define MS_UNBINDABLE (1<<17) /* change to unbindable */
138+#define MS_PRIVATE (1<<18) /* change to private */
139+#define MS_SLAVE (1<<19) /* change to slave */
140+#define MS_SHARED (1<<20) /* change to shared */
141+#endif
142+
143+#ifndef container_of
144+#define container_of(ptr, type, member) ({ \
145+ const typeof(((type *)0)->member) *__mptr = (ptr); \
146+ (type *)((char *)__mptr - offsetof(type, member)); })
147+#endif
148+
149+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
150+#define smp_read_barrier_depends smp_rmb
151+#endif
152+
153+#ifndef ACCESS_ONCE
154+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
155+#endif
156+
157+#ifndef rcu_dereference
158+#define rcu_dereference(p) ({ \
159+ typeof(p) _________p1 = ACCESS_ONCE(p); \
160+ smp_read_barrier_depends(); /* see RCU */ \
161+ (_________p1); \
162+ })
163+#endif
164+
165+#ifndef rcu_assign_pointer
166+#define rcu_assign_pointer(p, v) \
167+ ({ \
168+ if (!__builtin_constant_p(v) || \
169+ ((v) != NULL)) \
170+ smp_wmb(); /* see RCU */ \
171+ (p) = (v); \
172+ })
173+#endif
174+
175+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
176+
177+/**
178+ * kzalloc() - Allocate memory. The memory is set to zero.
179+ *
180+ * @size: Size to allocate.
181+ * @flags: GFP flags.
182+ *
183+ * Returns pointer to allocated memory on success, NULL otherwise.
184+ *
185+ * This is for compatibility with older kernels.
186+ *
187+ * Since several distributions backported kzalloc(), I define it as a macro
188+ * rather than an inlined function in order to avoid multiple definition error.
189+ */
190+#define kzalloc(size, flags) ({ \
191+ void *ret = kmalloc((size), (flags)); \
192+ if (ret) \
193+ memset(ret, 0, (size)); \
194+ ret; })
195+
196+#endif
197+
198+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
199+
200+/**
201+ * path_put - Drop reference on "struct path".
202+ *
203+ * @path: Pointer to "struct path".
204+ *
205+ * Returns nothing.
206+ *
207+ * This is for compatibility with older kernels.
208+ */
209+static inline void path_put(struct path *path)
210+{
211+ dput(path->dentry);
212+ mntput(path->mnt);
213+}
214+
215+#endif
216+
217+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
218+
219+/**
220+ * __list_add_rcu - Insert a new entry between two known consecutive entries.
221+ *
222+ * @new: Pointer to "struct list_head".
223+ * @prev: Pointer to "struct list_head".
224+ * @next: Pointer to "struct list_head".
225+ *
226+ * Returns nothing.
227+ *
228+ * This is for compatibility with older kernels.
229+ */
230+static inline void __list_add_rcu(struct list_head *new,
231+ struct list_head *prev,
232+ struct list_head *next)
233+{
234+ new->next = next;
235+ new->prev = prev;
236+ rcu_assign_pointer(prev->next, new);
237+ next->prev = new;
238+}
239+
240+/**
241+ * list_add_tail_rcu - Add a new entry to rcu-protected list.
242+ *
243+ * @new: Pointer to "struct list_head".
244+ * @head: Pointer to "struct list_head".
245+ *
246+ * Returns nothing.
247+ *
248+ * This is for compatibility with older kernels.
249+ */
250+static inline void list_add_tail_rcu(struct list_head *new,
251+ struct list_head *head)
252+{
253+ __list_add_rcu(new, head->prev, head);
254+}
255+
256+/**
257+ * list_add_rcu - Add a new entry to rcu-protected list.
258+ *
259+ * @new: Pointer to "struct list_head".
260+ * @head: Pointer to "struct list_head".
261+ *
262+ * Returns nothing.
263+ *
264+ * This is for compatibility with older kernels.
265+ */
266+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
267+{
268+ __list_add_rcu(new, head, head->next);
269+}
270+
271+#endif
272+
273+#ifndef srcu_dereference
274+
275+/**
276+ * srcu_dereference - Fetch SRCU-protected pointer with checking.
277+ *
278+ * @p: The pointer to read, prior to dereferencing.
279+ * @ss: Pointer to "struct srcu_struct".
280+ *
281+ * Returns @p.
282+ *
283+ * This is for compatibility with older kernels.
284+ */
285+#define srcu_dereference(p, ss) rcu_dereference(p)
286+
287+#endif
288+
289+#ifndef list_for_each_entry_srcu
290+
291+/**
292+ * list_for_each_entry_srcu - Iterate over rcu list of given type.
293+ *
294+ * @pos: The type * to use as a loop cursor.
295+ * @head: The head for your list.
296+ * @member: The name of the list_struct within the struct.
297+ * @ss: Pointer to "struct srcu_struct".
298+ *
299+ * As of 2.6.36, this macro is not provided because only TOMOYO wants it.
300+ */
301+#define list_for_each_entry_srcu(pos, head, member, ss) \
302+ for (pos = list_entry(srcu_dereference((head)->next, ss), \
303+ typeof(*pos), member); \
304+ prefetch(pos->member.next), &pos->member != (head); \
305+ pos = list_entry(srcu_dereference(pos->member.next, ss), \
306+ typeof(*pos), member))
307+
308+#endif
309+
310+#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))
311+
312+#ifndef ssleep
313+
314+/**
315+ * ssleep - Sleep for specified seconds.
316+ *
317+ * @secs: Seconds to sleep.
318+ *
319+ * Returns nothing.
320+ *
321+ * This is for compatibility with older kernels.
322+ *
323+ * Since several distributions backported ssleep(), I define it as a macro
324+ * rather than an inlined function in order to avoid multiple definition error.
325+ */
326+#define ssleep(secs) { \
327+ set_current_state(TASK_UNINTERRUPTIBLE); \
328+ schedule_timeout((HZ * secs) + 1); \
329+ }
330+
331+#endif
332+
333+#endif
334+
335+/*
336+ * TOMOYO specific part start.
337+ */
338+
339+#ifndef CONFIG_CCSECURITY
340+#define CONFIG_CCSECURITY
341+#define CONFIG_CCSECURITY_MAX_AUDIT_LOG 1024
342+#define CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY 2048
343+#define CONFIG_CCSECURITY_DEFAULT_LOADER "/sbin/ccs-init"
344+#define CONFIG_CCSECURITY_ALTERNATIVE_TRIGGER "/sbin/ccs-start"
345+#define CONFIG_CCSECURITY_BUILTIN_INITIALIZERS ""
346+#endif
347+#ifndef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
348+#define CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
349+#endif
350+#include "ccsecurity.h"
351+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
352+#error This module supports only 2.6.0 and later kernels.
353+#endif
354+#ifndef CONFIG_SECURITY
355+#error You must choose CONFIG_SECURITY=y for building this module.
356+#endif
357+#ifndef CONFIG_KALLSYMS
358+#error You must choose CONFIG_KALLSYMS=y for building this module.
359+#endif
360+#ifndef CONFIG_PROC_FS
361+#error You must choose CONFIG_PROC_FS=y for building this module.
362+#endif
363+#ifndef CONFIG_MODULES
364+#error You must choose CONFIG_MODULES=y for building this module.
365+#endif
366+
367+/* Enumeration definition for internal use. */
368+
369+/* Index numbers for Access Controls. */
370+enum ccs_acl_entry_type_index {
371+ CCS_TYPE_PATH_ACL,
372+ CCS_TYPE_PATH2_ACL,
373+ CCS_TYPE_PATH_NUMBER_ACL,
374+ CCS_TYPE_MKDEV_ACL,
375+ CCS_TYPE_MOUNT_ACL,
376+ CCS_TYPE_ENV_ACL,
377+ CCS_TYPE_CAPABILITY_ACL,
378+ CCS_TYPE_INET_ACL,
379+ CCS_TYPE_UNIX_ACL,
380+ CCS_TYPE_SIGNAL_ACL,
381+ CCS_TYPE_AUTO_EXECUTE_HANDLER,
382+ CCS_TYPE_DENIED_EXECUTE_HANDLER,
383+ CCS_TYPE_AUTO_TASK_ACL,
384+ CCS_TYPE_MANUAL_TASK_ACL,
385+};
386+
387+/* Index numbers for "struct ccs_condition". */
388+enum ccs_conditions_index {
389+ CCS_TASK_UID, /* current_uid() */
390+ CCS_TASK_EUID, /* current_euid() */
391+ CCS_TASK_SUID, /* current_suid() */
392+ CCS_TASK_FSUID, /* current_fsuid() */
393+ CCS_TASK_GID, /* current_gid() */
394+ CCS_TASK_EGID, /* current_egid() */
395+ CCS_TASK_SGID, /* current_sgid() */
396+ CCS_TASK_FSGID, /* current_fsgid() */
397+ CCS_TASK_PID, /* sys_getpid() */
398+ CCS_TASK_PPID, /* sys_getppid() */
399+ CCS_EXEC_ARGC, /* "struct linux_binprm *"->argc */
400+ CCS_EXEC_ENVC, /* "struct linux_binprm *"->envc */
401+ CCS_TYPE_IS_SOCKET, /* S_IFSOCK */
402+ CCS_TYPE_IS_SYMLINK, /* S_IFLNK */
403+ CCS_TYPE_IS_FILE, /* S_IFREG */
404+ CCS_TYPE_IS_BLOCK_DEV, /* S_IFBLK */
405+ CCS_TYPE_IS_DIRECTORY, /* S_IFDIR */
406+ CCS_TYPE_IS_CHAR_DEV, /* S_IFCHR */
407+ CCS_TYPE_IS_FIFO, /* S_IFIFO */
408+ CCS_MODE_SETUID, /* S_ISUID */
409+ CCS_MODE_SETGID, /* S_ISGID */
410+ CCS_MODE_STICKY, /* S_ISVTX */
411+ CCS_MODE_OWNER_READ, /* S_IRUSR */
412+ CCS_MODE_OWNER_WRITE, /* S_IWUSR */
413+ CCS_MODE_OWNER_EXECUTE, /* S_IXUSR */
414+ CCS_MODE_GROUP_READ, /* S_IRGRP */
415+ CCS_MODE_GROUP_WRITE, /* S_IWGRP */
416+ CCS_MODE_GROUP_EXECUTE, /* S_IXGRP */
417+ CCS_MODE_OTHERS_READ, /* S_IROTH */
418+ CCS_MODE_OTHERS_WRITE, /* S_IWOTH */
419+ CCS_MODE_OTHERS_EXECUTE, /* S_IXOTH */
420+ CCS_TASK_TYPE, /* ((u8) task->ccs_flags) &
421+ CCS_TASK_IS_EXECUTE_HANDLER */
422+ CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
423+ CCS_EXEC_REALPATH,
424+ CCS_SYMLINK_TARGET,
425+ CCS_PATH1_UID,
426+ CCS_PATH1_GID,
427+ CCS_PATH1_INO,
428+ CCS_PATH1_MAJOR,
429+ CCS_PATH1_MINOR,
430+ CCS_PATH1_PERM,
431+ CCS_PATH1_TYPE,
432+ CCS_PATH1_DEV_MAJOR,
433+ CCS_PATH1_DEV_MINOR,
434+ CCS_PATH2_UID,
435+ CCS_PATH2_GID,
436+ CCS_PATH2_INO,
437+ CCS_PATH2_MAJOR,
438+ CCS_PATH2_MINOR,
439+ CCS_PATH2_PERM,
440+ CCS_PATH2_TYPE,
441+ CCS_PATH2_DEV_MAJOR,
442+ CCS_PATH2_DEV_MINOR,
443+ CCS_PATH1_PARENT_UID,
444+ CCS_PATH1_PARENT_GID,
445+ CCS_PATH1_PARENT_INO,
446+ CCS_PATH1_PARENT_PERM,
447+ CCS_PATH2_PARENT_UID,
448+ CCS_PATH2_PARENT_GID,
449+ CCS_PATH2_PARENT_INO,
450+ CCS_PATH2_PARENT_PERM,
451+ CCS_MAX_CONDITION_KEYWORD,
452+ CCS_NUMBER_UNION,
453+ CCS_NAME_UNION,
454+ CCS_ARGV_ENTRY,
455+ CCS_ENVP_ENTRY,
456+};
457+
458+/* Index numbers for domain's attributes. */
459+enum ccs_domain_info_flags_index {
460+ /* Quota warnning flag. */
461+ CCS_DIF_QUOTA_WARNED,
462+ /*
463+ * This domain was unable to create a new domain at
464+ * ccs_find_next_domain() because the name of the domain to be created
465+ * was too long or it could not allocate memory.
466+ * More than one process continued execve() without domain transition.
467+ */
468+ CCS_DIF_TRANSITION_FAILED,
469+ CCS_MAX_DOMAIN_INFO_FLAGS
470+};
471+
472+/* Index numbers for audit type. */
473+enum ccs_grant_log {
474+ /* Follow profile's configuration. */
475+ CCS_GRANTLOG_AUTO,
476+ /* Do not generate grant log. */
477+ CCS_GRANTLOG_NO,
478+ /* Generate grant_log. */
479+ CCS_GRANTLOG_YES,
480+};
481+
482+/* Index numbers for group entries. */
483+enum ccs_group_id {
484+ CCS_PATH_GROUP,
485+ CCS_NUMBER_GROUP,
486+ CCS_ADDRESS_GROUP,
487+ CCS_MAX_GROUP
488+};
489+
490+/* Index numbers for type of IP address. */
491+enum ccs_ip_address_type {
492+ CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP,
493+ CCS_IP_ADDRESS_TYPE_IPv4,
494+ CCS_IP_ADDRESS_TYPE_IPv6,
495+};
496+
497+/* Index numbers for category of functionality. */
498+enum ccs_mac_category_index {
499+ CCS_MAC_CATEGORY_FILE,
500+ CCS_MAC_CATEGORY_NETWORK,
501+ CCS_MAC_CATEGORY_MISC,
502+ CCS_MAC_CATEGORY_IPC,
503+ CCS_MAC_CATEGORY_CAPABILITY,
504+ CCS_MAX_MAC_CATEGORY_INDEX
505+};
506+
507+/* Index numbers for functionality. */
508+enum ccs_mac_index {
509+ CCS_MAC_FILE_EXECUTE,
510+ CCS_MAC_FILE_OPEN,
511+ CCS_MAC_FILE_CREATE,
512+ CCS_MAC_FILE_UNLINK,
513+ CCS_MAC_FILE_GETATTR,
514+ CCS_MAC_FILE_MKDIR,
515+ CCS_MAC_FILE_RMDIR,
516+ CCS_MAC_FILE_MKFIFO,
517+ CCS_MAC_FILE_MKSOCK,
518+ CCS_MAC_FILE_TRUNCATE,
519+ CCS_MAC_FILE_SYMLINK,
520+ CCS_MAC_FILE_MKBLOCK,
521+ CCS_MAC_FILE_MKCHAR,
522+ CCS_MAC_FILE_LINK,
523+ CCS_MAC_FILE_RENAME,
524+ CCS_MAC_FILE_CHMOD,
525+ CCS_MAC_FILE_CHOWN,
526+ CCS_MAC_FILE_CHGRP,
527+ CCS_MAC_FILE_IOCTL,
528+ CCS_MAC_FILE_CHROOT,
529+ CCS_MAC_FILE_MOUNT,
530+ CCS_MAC_FILE_UMOUNT,
531+ CCS_MAC_FILE_PIVOT_ROOT,
532+ CCS_MAC_NETWORK_INET_STREAM_BIND,
533+ CCS_MAC_NETWORK_INET_STREAM_LISTEN,
534+ CCS_MAC_NETWORK_INET_STREAM_CONNECT,
535+ CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
536+ CCS_MAC_NETWORK_INET_DGRAM_BIND,
537+ CCS_MAC_NETWORK_INET_DGRAM_SEND,
538+ CCS_MAC_NETWORK_INET_DGRAM_RECV,
539+ CCS_MAC_NETWORK_INET_RAW_BIND,
540+ CCS_MAC_NETWORK_INET_RAW_SEND,
541+ CCS_MAC_NETWORK_INET_RAW_RECV,
542+ CCS_MAC_NETWORK_UNIX_STREAM_BIND,
543+ CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
544+ CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
545+ CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
546+ CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
547+ CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
548+ CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
549+ CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
550+ CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
551+ CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
552+ CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
553+ CCS_MAC_ENVIRON,
554+ CCS_MAC_SIGNAL,
555+ CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET,
556+ CCS_MAC_CAPABILITY_USE_PACKET_SOCKET,
557+ CCS_MAC_CAPABILITY_SYS_REBOOT,
558+ CCS_MAC_CAPABILITY_SYS_VHANGUP,
559+ CCS_MAC_CAPABILITY_SYS_SETTIME,
560+ CCS_MAC_CAPABILITY_SYS_NICE,
561+ CCS_MAC_CAPABILITY_SYS_SETHOSTNAME,
562+ CCS_MAC_CAPABILITY_USE_KERNEL_MODULE,
563+ CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD,
564+ CCS_MAC_CAPABILITY_SYS_PTRACE,
565+ CCS_MAX_MAC_INDEX
566+};
567+
568+/* Index numbers for /proc/ccs/stat interface. */
569+enum ccs_memory_stat_type {
570+ CCS_MEMORY_POLICY,
571+ CCS_MEMORY_AUDIT,
572+ CCS_MEMORY_QUERY,
573+ CCS_MAX_MEMORY_STAT
574+};
575+
576+/* Index numbers for access controls with one pathname and three numbers. */
577+enum ccs_mkdev_acl_index {
578+ CCS_TYPE_MKBLOCK,
579+ CCS_TYPE_MKCHAR,
580+ CCS_MAX_MKDEV_OPERATION
581+};
582+
583+/* Index numbers for operation mode. */
584+enum ccs_mode_value {
585+ CCS_CONFIG_DISABLED,
586+ CCS_CONFIG_LEARNING,
587+ CCS_CONFIG_PERMISSIVE,
588+ CCS_CONFIG_ENFORCING,
589+ CCS_CONFIG_MAX_MODE,
590+ CCS_CONFIG_WANT_REJECT_LOG = 64,
591+ CCS_CONFIG_WANT_GRANT_LOG = 128,
592+ CCS_CONFIG_USE_DEFAULT = 255,
593+};
594+
595+/* Index numbers for socket operations. */
596+enum ccs_network_acl_index {
597+ CCS_NETWORK_BIND, /* bind() operation. */
598+ CCS_NETWORK_LISTEN, /* listen() operation. */
599+ CCS_NETWORK_CONNECT, /* connect() operation. */
600+ CCS_NETWORK_ACCEPT, /* accept() operation. */
601+ CCS_NETWORK_SEND, /* send() operation. */
602+ CCS_NETWORK_RECV, /* recv() operation. */
603+ CCS_MAX_NETWORK_OPERATION
604+};
605+
606+/* Index numbers for access controls with two pathnames. */
607+enum ccs_path2_acl_index {
608+ CCS_TYPE_LINK,
609+ CCS_TYPE_RENAME,
610+ CCS_TYPE_PIVOT_ROOT,
611+ CCS_MAX_PATH2_OPERATION
612+};
613+
614+/* Index numbers for access controls with one pathname. */
615+enum ccs_path_acl_index {
616+ CCS_TYPE_EXECUTE,
617+ CCS_TYPE_READ,
618+ CCS_TYPE_WRITE,
619+ CCS_TYPE_APPEND,
620+ CCS_TYPE_UNLINK,
621+ CCS_TYPE_GETATTR,
622+ CCS_TYPE_RMDIR,
623+ CCS_TYPE_TRUNCATE,
624+ CCS_TYPE_SYMLINK,
625+ CCS_TYPE_CHROOT,
626+ CCS_TYPE_UMOUNT,
627+ CCS_MAX_PATH_OPERATION
628+};
629+
630+/* Index numbers for access controls with one pathname and one number. */
631+enum ccs_path_number_acl_index {
632+ CCS_TYPE_CREATE,
633+ CCS_TYPE_MKDIR,
634+ CCS_TYPE_MKFIFO,
635+ CCS_TYPE_MKSOCK,
636+ CCS_TYPE_IOCTL,
637+ CCS_TYPE_CHMOD,
638+ CCS_TYPE_CHOWN,
639+ CCS_TYPE_CHGRP,
640+ CCS_MAX_PATH_NUMBER_OPERATION
641+};
642+
643+/* Index numbers for stat(). */
644+enum ccs_path_stat_index {
645+ /* Do not change this order. */
646+ CCS_PATH1,
647+ CCS_PATH1_PARENT,
648+ CCS_PATH2,
649+ CCS_PATH2_PARENT,
650+ CCS_MAX_PATH_STAT
651+};
652+
653+/* Index numbers for entry type. */
654+enum ccs_policy_id {
655+ CCS_ID_RESERVEDPORT,
656+ CCS_ID_GROUP,
657+ CCS_ID_ADDRESS_GROUP,
658+ CCS_ID_PATH_GROUP,
659+ CCS_ID_NUMBER_GROUP,
660+ CCS_ID_AGGREGATOR,
661+ CCS_ID_TRANSITION_CONTROL,
662+ CCS_ID_MANAGER,
663+ CCS_ID_IPV6_ADDRESS,
664+ CCS_ID_CONDITION,
665+ CCS_ID_NAME,
666+ CCS_ID_ACL,
667+ CCS_ID_DOMAIN,
668+ CCS_MAX_POLICY
669+};
670+
671+/* Index numbers for /proc/ccs/stat interface. */
672+enum ccs_policy_stat_type {
673+ /* Do not change this order. */
674+ CCS_STAT_POLICY_UPDATES,
675+ CCS_STAT_POLICY_LEARNING, /* == CCS_CONFIG_LEARNING */
676+ CCS_STAT_POLICY_PERMISSIVE, /* == CCS_CONFIG_PERMISSIVE */
677+ CCS_STAT_POLICY_ENFORCING, /* == CCS_CONFIG_ENFORCING */
678+ CCS_MAX_POLICY_STAT
679+};
680+
681+/* Index numbers for profile's PREFERENCE values. */
682+enum ccs_pref_index {
683+ CCS_PREF_MAX_AUDIT_LOG,
684+ CCS_PREF_MAX_LEARNING_ENTRY,
685+ CCS_PREF_ENFORCING_PENALTY,
686+ CCS_MAX_PREF
687+};
688+
689+/* Index numbers for /proc/ccs/ interfaces. */
690+enum ccs_proc_interface_index {
691+ CCS_DOMAINPOLICY,
692+ CCS_EXCEPTIONPOLICY,
693+ CCS_DOMAIN_STATUS,
694+ CCS_PROCESS_STATUS,
695+ CCS_STAT,
696+ CCS_AUDIT,
697+ CCS_VERSION,
698+ CCS_PROFILE,
699+ CCS_QUERY,
700+ CCS_MANAGER,
701+ CCS_EXECUTE_HANDLER,
702+};
703+
704+/* Index numbers for shared entries. */
705+enum ccs_shared_acl_id {
706+ CCS_CONDITION_LIST,
707+ CCS_IPV6ADDRESS_LIST,
708+ CCS_MAX_LIST
709+};
710+
711+/* Index numbers for special mount operations. */
712+enum ccs_special_mount {
713+ CCS_MOUNT_BIND, /* mount --bind /source /dest */
714+ CCS_MOUNT_MOVE, /* mount --move /old /new */
715+ CCS_MOUNT_REMOUNT, /* mount -o remount /dir */
716+ CCS_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
717+ CCS_MOUNT_MAKE_PRIVATE, /* mount --make-private /dir */
718+ CCS_MOUNT_MAKE_SLAVE, /* mount --make-slave /dir */
719+ CCS_MOUNT_MAKE_SHARED, /* mount --make-shared /dir */
720+ CCS_MAX_SPECIAL_MOUNT
721+};
722+
723+/* Index numbers for domain transition control keywords. */
724+enum ccs_transition_type {
725+ /* Do not change this order, */
726+ CCS_TRANSITION_CONTROL_NO_INITIALIZE,
727+ CCS_TRANSITION_CONTROL_INITIALIZE,
728+ CCS_TRANSITION_CONTROL_NO_KEEP,
729+ CCS_TRANSITION_CONTROL_KEEP,
730+ CCS_MAX_TRANSITION_TYPE
731+};
732+
733+/* Index numbers for type of numeric values. */
734+enum ccs_value_type {
735+ CCS_VALUE_TYPE_INVALID,
736+ CCS_VALUE_TYPE_DECIMAL,
737+ CCS_VALUE_TYPE_OCTAL,
738+ CCS_VALUE_TYPE_HEXADECIMAL,
739+};
740+
741+/* Constants definition for internal use. */
742+
743+/*
744+ * TOMOYO uses this hash only when appending a string into the string table.
745+ * Frequency of appending strings is very low. So we don't need large (e.g.
746+ * 64k) hash size. 256 will be sufficient.
747+ */
748+#define CCS_HASH_BITS 8
749+#define CCS_MAX_HASH (1u << CCS_HASH_BITS)
750+
751+/*
752+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
753+ * Therefore, we don't need SOCK_MAX.
754+ */
755+#define CCS_SOCK_MAX 6
756+
757+/* A domain definition starts with <kernel>. */
758+#define CCS_ROOT_NAME "<kernel>"
759+#define CCS_ROOT_NAME_LEN (sizeof(CCS_ROOT_NAME) - 1)
760+
761+/* Size of temporary buffer for execve() operation. */
762+#define CCS_EXEC_TMPSIZE 4096
763+
764+/* Profile number is an integer between 0 and 255. */
765+#define CCS_MAX_PROFILES 256
766+
767+/* Group number is an integer between 0 and 255. */
768+#define CCS_MAX_ACL_GROUPS 256
769+
770+/* Current thread is doing open(O_RDONLY | O_TRUNC) ? */
771+#define CCS_OPEN_FOR_READ_TRUNCATE 1
772+/* Current thread is doing open(3) ? */
773+#define CCS_OPEN_FOR_IOCTL_ONLY 2
774+/* Current thread is doing do_execve() ? */
775+#define CCS_TASK_IS_IN_EXECVE 4
776+/* Current thread is running as an execute handler program? */
777+#define CCS_TASK_IS_EXECUTE_HANDLER 8
778+/* Current thread is allowed to modify policy via /proc/ccs/ interface? */
779+#define CCS_TASK_IS_MANAGER 16
780+
781+/*
782+ * Retry this request. Returned by ccs_supervisor() if policy violation has
783+ * occurred in enforcing mode and the userspace daemon decided to retry.
784+ *
785+ * We must choose a positive value in order to distinguish "granted" (which is
786+ * 0) and "rejected" (which is a negative value) and "retry".
787+ */
788+#define CCS_RETRY_REQUEST 1
789+
790+/* Ignore gfp flags which are not supported. */
791+#ifndef __GFP_HIGHIO
792+#define __GFP_HIGHIO 0
793+#endif
794+#ifndef __GFP_NOWARN
795+#define __GFP_NOWARN 0
796+#endif
797+#ifndef __GFP_NORETRY
798+#define __GFP_NORETRY 0
799+#endif
800+#ifndef __GFP_NOMEMALLOC
801+#define __GFP_NOMEMALLOC 0
802+#endif
803+
804+/* The gfp flags used by TOMOYO. */
805+#define CCS_GFP_FLAGS (__GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_NOWARN | \
806+ __GFP_NORETRY | __GFP_NOMEMALLOC)
807+
808+/* Size of read buffer for /proc/ccs/ interface. */
809+#define CCS_MAX_IO_READ_QUEUE 64
810+
811+/* Structure definition for internal use. */
812+
813+/* Common header for holding ACL entries. */
814+struct ccs_acl_head {
815+ struct list_head list;
816+ bool is_deleted;
817+} __attribute__((__packed__));
818+
819+/* Common header for shared entries. */
820+struct ccs_shared_acl_head {
821+ struct list_head list;
822+ atomic_t users;
823+} __attribute__((__packed__));
824+
825+/* Common header for individual entries. */
826+struct ccs_acl_info {
827+ struct list_head list;
828+ struct ccs_condition *cond; /* Maybe NULL. */
829+ bool is_deleted;
830+ u8 type; /* = one of values in "enum ccs_acl_entry_type_index" */
831+} __attribute__((__packed__));
832+
833+/* Structure for holding a word. */
834+struct ccs_name_union {
835+ /* Either @filename or @group is NULL. */
836+ const struct ccs_path_info *filename;
837+ struct ccs_group *group;
838+ /* True if @group != NULL, false if @filename != NULL. */
839+ u8 is_group;
840+};
841+
842+/* Structure for holding a number. */
843+struct ccs_number_union {
844+ unsigned long values[2];
845+ struct ccs_group *group; /* Maybe NULL. */
846+ /* One of values in "enum ccs_value_type". */
847+ u8 value_type[2];
848+ /* True if @group != NULL, false otherwise. */
849+ u8 is_group;
850+};
851+
852+/* Structure for "path_group"/"number_group"/"address_group" directive. */
853+struct ccs_group {
854+ struct ccs_shared_acl_head head;
855+ /* Name of group (without leading '@'). */
856+ const struct ccs_path_info *group_name;
857+ /*
858+ * List of "struct ccs_path_group" or "struct ccs_number_group" or
859+ * "struct ccs_address_group".
860+ */
861+ struct list_head member_list;
862+};
863+
864+/* Structure for "path_group" directive. */
865+struct ccs_path_group {
866+ struct ccs_acl_head head;
867+ const struct ccs_path_info *member_name;
868+};
869+
870+/* Structure for "number_group" directive. */
871+struct ccs_number_group {
872+ struct ccs_acl_head head;
873+ struct ccs_number_union number;
874+};
875+
876+/* Structure for "address_group" directive. */
877+struct ccs_address_group {
878+ struct ccs_acl_head head;
879+ bool is_ipv6; /* True if IPv6 address, false if IPv4 address. */
880+ union {
881+ u32 ipv4; /* Host byte order */
882+ const struct in6_addr *ipv6; /* Network byte order */
883+ } min, max;
884+};
885+
886+/* Subset of "struct stat". Used by conditional ACL and audit logs. */
887+struct ccs_mini_stat {
888+ uid_t uid;
889+ gid_t gid;
890+ ino_t ino;
891+ mode_t mode;
892+ dev_t dev;
893+ dev_t rdev;
894+};
895+
896+/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
897+struct ccs_page_dump {
898+ struct page *page; /* Previously dumped page. */
899+ char *data; /* Contents of "page". Size is PAGE_SIZE. */
900+};
901+
902+/* Structure for attribute checks in addition to pathname checks. */
903+struct ccs_obj_info {
904+ /* True if ccs_get_attributes() was already called, false otherwise. */
905+ bool validate_done;
906+ /* True if @stat[] is valid. */
907+ bool stat_valid[CCS_MAX_PATH_STAT];
908+ /* First pathname. Initialized with { NULL, NULL } if no path. */
909+ struct path path1;
910+ /* Second pathname. Initialized with { NULL, NULL } if no path. */
911+ struct path path2;
912+ /*
913+ * Information on @path1, @path1's parent directory, @path2, @path2's
914+ * parent directory.
915+ */
916+ struct ccs_mini_stat stat[CCS_MAX_PATH_STAT];
917+ /*
918+ * Content of symbolic link to be created. NULL for operations other
919+ * than symlink().
920+ */
921+ struct ccs_path_info *symlink_target;
922+};
923+
924+/* Structure for entries which follows "struct ccs_condition". */
925+struct ccs_condition_element {
926+ /*
927+ * Left hand operand. A "struct ccs_argv" for CCS_ARGV_ENTRY, a
928+ * "struct ccs_envp" for CCS_ENVP_ENTRY is attached to the tail
929+ * of the array of this struct.
930+ */
931+ u8 left;
932+ /*
933+ * Right hand operand. A "struct ccs_number_union" for
934+ * CCS_NUMBER_UNION, a "struct ccs_name_union" for CCS_NAME_UNION is
935+ * attached to the tail of the array of this struct.
936+ */
937+ u8 right;
938+ /* Equation operator. True if equals or overlaps, false otherwise. */
939+ bool equals;
940+};
941+
942+/* Structure for optional arguments. */
943+struct ccs_condition {
944+ struct ccs_shared_acl_head head;
945+ u32 size; /* Memory size allocated for this entry. */
946+ u16 condc; /* Number of conditions in this struct. */
947+ u16 numbers_count; /* Number of "struct ccs_number_union values". */
948+ u16 names_count; /* Number of "struct ccs_name_union names". */
949+ u16 argc; /* Number of "struct ccs_argv". */
950+ u16 envc; /* Number of "struct ccs_envp". */
951+ u8 grant_log; /* One of values in "enum ccs_grant_log". */
952+ const struct ccs_path_info *transit; /* Maybe NULL. */
953+ /*
954+ * struct ccs_condition_element condition[condc];
955+ * struct ccs_number_union values[numbers_count];
956+ * struct ccs_name_union names[names_count];
957+ * struct ccs_argv argv[argc];
958+ * struct ccs_envp envp[envc];
959+ */
960+};
961+
962+struct ccs_execve;
963+
964+/* Structure for request info. */
965+struct ccs_request_info {
966+ /*
967+ * For holding parameters specific to operations which deal files.
968+ * NULL if not dealing files.
969+ */
970+ struct ccs_obj_info *obj;
971+ /*
972+ * For holding parameters specific to execve() request.
973+ * NULL if not dealing do_execve().
974+ */
975+ struct ccs_execve *ee;
976+ /*
977+ * For holding parameters.
978+ * Pointers in this union are not NULL except path->matched_path.
979+ */
980+ union {
981+ struct {
982+ const struct ccs_path_info *filename;
983+ /*
984+ * For using wildcards at ccs_find_next_domain().
985+ *
986+ * The matched_acl cannot be used because it may refer
987+ * a "struct ccs_path_acl" with ->is_group == true.
988+ * We want to use exact "struct ccs_path_info" rather
989+ * than "struct ccs_path_acl".
990+ */
991+ const struct ccs_path_info *matched_path;
992+ /* One of values in "enum ccs_path_acl_index". */
993+ u8 operation;
994+ } path;
995+ struct {
996+ const struct ccs_path_info *filename1;
997+ const struct ccs_path_info *filename2;
998+ /* One of values in "enum ccs_path2_acl_index". */
999+ u8 operation;
1000+ } path2;
1001+ struct {
1002+ const struct ccs_path_info *filename;
1003+ unsigned int mode;
1004+ unsigned int major;
1005+ unsigned int minor;
1006+ /* One of values in "enum ccs_mkdev_acl_index". */
1007+ u8 operation;
1008+ } mkdev;
1009+ struct {
1010+ const struct ccs_path_info *filename;
1011+ unsigned long number;
1012+ /*
1013+ * One of values in "enum ccs_path_number_acl_index".
1014+ */
1015+ u8 operation;
1016+ } path_number;
1017+ struct {
1018+ const u32 *address;
1019+ u32 ip;
1020+ u16 port;
1021+ /* One of values smaller than CCS_SOCK_MAX. */
1022+ u8 protocol;
1023+ /* One of values in "enum ccs_network_acl_index". */
1024+ u8 operation;
1025+ bool is_ipv6;
1026+ } inet_network;
1027+ struct {
1028+ const struct ccs_path_info *address;
1029+ /* One of values smaller than CCS_SOCK_MAX. */
1030+ u8 protocol;
1031+ /* One of values in "enum ccs_network_acl_index". */
1032+ u8 operation;
1033+ } unix_network;
1034+ struct {
1035+ const struct ccs_path_info *name;
1036+ } environ;
1037+ struct {
1038+ /* One of values in "enum ccs_capability_acl_index". */
1039+ u8 operation;
1040+ } capability;
1041+ struct {
1042+ const char *dest_pattern;
1043+ int sig;
1044+ } signal;
1045+ struct {
1046+ const struct ccs_path_info *type;
1047+ const struct ccs_path_info *dir;
1048+ const struct ccs_path_info *dev;
1049+ unsigned long flags;
1050+ int need_dev;
1051+ } mount;
1052+ struct {
1053+ const struct ccs_path_info *domainname;
1054+ } task;
1055+ } param;
1056+ u8 param_type; /* One of values in "enum ccs_acl_entry_type_index". */
1057+ bool granted; /* True if granted, false otherwise. */
1058+ /* True if current thread should not be carried sleep penalty. */
1059+ bool dont_sleep_on_enforce_error;
1060+ /*
1061+ * For updating current->ccs_domain_info at ccs_update_task_domain().
1062+ * Initialized to NULL at ccs_init_request_info().
1063+ * Matching "struct ccs_acl_info" is copied if access request was
1064+ * granted. Re-initialized to NULL at ccs_update_task_domain().
1065+ */
1066+ struct ccs_acl_info *matched_acl;
1067+ /*
1068+ * For counting number of retries made for this request.
1069+ * This counter is incremented whenever ccs_supervisor() returned
1070+ * CCS_RETRY_REQUEST.
1071+ */
1072+ u8 retry;
1073+ /*
1074+ * For holding profile number used for this request.
1075+ * One of values between 0 and CCS_MAX_PROFILES - 1.
1076+ */
1077+ u8 profile;
1078+ /*
1079+ * For holding operation mode used for this request.
1080+ * One of CCS_CONFIG_DISABLED, CCS_CONFIG_LEARNING,
1081+ * CCS_CONFIG_PERMISSIVE, CCS_CONFIG_ENFORCING.
1082+ */
1083+ u8 mode;
1084+ /*
1085+ * For holding operation index used for this request.
1086+ * Used by ccs_init_request_info() / ccs_get_mode() /
1087+ * ccs_write_log(). One of values in "enum ccs_mac_index".
1088+ */
1089+ u8 type;
1090+};
1091+
1092+/* Structure for holding a token. */
1093+struct ccs_path_info {
1094+ const char *name;
1095+ u32 hash; /* = full_name_hash(name, strlen(name)) */
1096+ u16 total_len; /* = strlen(name) */
1097+ u16 const_len; /* = ccs_const_part_length(name) */
1098+ bool is_dir; /* = ccs_strendswith(name, "/") */
1099+ bool is_patterned; /* = const_len < total_len */
1100+};
1101+
1102+/* Structure for execve() operation. */
1103+struct ccs_execve {
1104+ struct ccs_request_info r;
1105+ struct ccs_obj_info obj;
1106+ struct linux_binprm *bprm;
1107+ struct ccs_domain_info *previous_domain;
1108+ int reader_idx;
1109+ /* For execute_handler */
1110+ const struct ccs_path_info *handler;
1111+ char *handler_path; /* = kstrdup(handler->name, CCS_GFP_FLAGS) */
1112+ /* For dumping argv[] and envp[]. */
1113+ struct ccs_page_dump dump;
1114+ /* For temporary use. */
1115+ char *tmp; /* Size is CCS_EXEC_TMPSIZE bytes */
1116+};
1117+
1118+/* Structure for domain information. */
1119+struct ccs_domain_info {
1120+ struct list_head list;
1121+ struct list_head acl_info_list[2];
1122+ /* Name of this domain. Never NULL. */
1123+ const struct ccs_path_info *domainname;
1124+ u8 profile; /* Profile number to use. */
1125+ u8 group;
1126+ bool is_deleted; /* Delete flag. */
1127+ bool flags[CCS_MAX_DOMAIN_INFO_FLAGS];
1128+};
1129+
1130+/*
1131+ * Structure for "initialize_domain"/"no_initialize_domain" and
1132+ * "keep_domain"/"no_keep_domain" keyword.
1133+ */
1134+struct ccs_transition_control {
1135+ struct ccs_acl_head head;
1136+ u8 type; /* = one of values in "enum ccs_transition_type" */
1137+ bool is_last_name; /* True if the domainname is ccs_last_word(). */
1138+ const struct ccs_path_info *domainname;
1139+ const struct ccs_path_info *program;
1140+};
1141+
1142+/* Structure for "aggregator" keyword. */
1143+struct ccs_aggregator {
1144+ struct ccs_acl_head head;
1145+ const struct ccs_path_info *original_name;
1146+ const struct ccs_path_info *aggregated_name;
1147+};
1148+
1149+/* Structure for "deny_autobind" keyword. */
1150+struct ccs_reserved {
1151+ struct ccs_acl_head head;
1152+ u16 min_port; /* Start of port number range. */
1153+ u16 max_port; /* End of port number range. */
1154+};
1155+
1156+/* Structure for policy manager. */
1157+struct ccs_manager {
1158+ struct ccs_acl_head head;
1159+ bool is_domain; /* True if manager is a domainname. */
1160+ /* A path to program or a domainname. */
1161+ const struct ccs_path_info *manager;
1162+};
1163+
1164+/* Structure for argv[]. */
1165+struct ccs_argv {
1166+ unsigned int index;
1167+ const struct ccs_path_info *value;
1168+ bool is_not;
1169+};
1170+
1171+/* Structure for envp[]. */
1172+struct ccs_envp {
1173+ const struct ccs_path_info *name;
1174+ const struct ccs_path_info *value;
1175+ bool is_not;
1176+};
1177+
1178+/*
1179+ * Structure for "task auto_execute_handler" and "task denied_execute_handler"
1180+ * directive.
1181+ *
1182+ * If "task auto_execute_handler" directive exists and the current process is
1183+ * not an execute handler, all execve() requests are replaced by execve()
1184+ * requests of a program specified by "task auto_execute_handler" directive.
1185+ * If the current process is an execute handler, "task auto_execute_handler"
1186+ * and "task denied_execute_handler" directives are ignored.
1187+ * The program specified by "task execute_handler" validates execve()
1188+ * parameters and executes the original execve() requests if appropriate.
1189+ *
1190+ * "task denied_execute_handler" directive is used only when execve() request
1191+ * was rejected in enforcing mode (i.e. CONFIG::file::execute={ mode=enforcing
1192+ * }). The program specified by "task denied_execute_handler" does whatever it
1193+ * wants to do (e.g. silently terminate, change firewall settings, redirect the
1194+ * user to honey pot etc.).
1195+ */
1196+struct ccs_handler_acl {
1197+ struct ccs_acl_info head; /* type = CCS_TYPE_*_EXECUTE_HANDLER */
1198+ const struct ccs_path_info *handler; /* Pointer to single pathname. */
1199+};
1200+
1201+/*
1202+ * Structure for "task auto_domain_transition" and
1203+ * "task manual_domain_transition" directive.
1204+ */
1205+struct ccs_task_acl {
1206+ struct ccs_acl_info head; /* type = CCS_TYPE_*_TASK_ACL */
1207+ /* Pointer to domainname. */
1208+ const struct ccs_path_info *domainname;
1209+};
1210+
1211+/*
1212+ * Structure for "file execute", "file read", "file write", "file append",
1213+ * "file unlink", "file getattr", "file rmdir", "file truncate",
1214+ * "file symlink", "file chroot" and "file unmount" directive.
1215+ */
1216+struct ccs_path_acl {
1217+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_ACL */
1218+ u16 perm; /* Bitmask of values in "enum ccs_path_acl_index". */
1219+ struct ccs_name_union name;
1220+};
1221+
1222+/*
1223+ * Structure for "file rename", "file link" and "file pivot_root" directive.
1224+ */
1225+struct ccs_path2_acl {
1226+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH2_ACL */
1227+ u8 perm; /* Bitmask of values in "enum ccs_path2_acl_index". */
1228+ struct ccs_name_union name1;
1229+ struct ccs_name_union name2;
1230+};
1231+
1232+/*
1233+ * Structure for "file create", "file mkdir", "file mkfifo", "file mksock",
1234+ * "file ioctl", "file chmod", "file chown" and "file chgrp" directive.
1235+ */
1236+struct ccs_path_number_acl {
1237+ struct ccs_acl_info head; /* type = CCS_TYPE_PATH_NUMBER_ACL */
1238+ u8 perm; /* Bitmask of values in "enum ccs_path_number_acl_index". */
1239+ struct ccs_name_union name;
1240+ struct ccs_number_union number;
1241+};
1242+
1243+/* Structure for "file mkblock" and "file mkchar" directive. */
1244+struct ccs_mkdev_acl {
1245+ struct ccs_acl_info head; /* type = CCS_TYPE_MKDEV_ACL */
1246+ u8 perm; /* Bitmask of values in "enum ccs_mkdev_acl_index". */
1247+ struct ccs_name_union name;
1248+ struct ccs_number_union mode;
1249+ struct ccs_number_union major;
1250+ struct ccs_number_union minor;
1251+};
1252+
1253+/* Structure for "file mount" directive. */
1254+struct ccs_mount_acl {
1255+ struct ccs_acl_info head; /* type = CCS_TYPE_MOUNT_ACL */
1256+ struct ccs_name_union dev_name;
1257+ struct ccs_name_union dir_name;
1258+ struct ccs_name_union fs_type;
1259+ struct ccs_number_union flags;
1260+};
1261+
1262+/* Structure for "misc env" directive in domain policy. */
1263+struct ccs_env_acl {
1264+ struct ccs_acl_info head; /* type = CCS_TYPE_ENV_ACL */
1265+ const struct ccs_path_info *env; /* environment variable */
1266+};
1267+
1268+/* Structure for "capability" directive. */
1269+struct ccs_capability_acl {
1270+ struct ccs_acl_info head; /* type = CCS_TYPE_CAPABILITY_ACL */
1271+ u8 operation; /* one of values in "enum ccs_capability_acl_index". */
1272+};
1273+
1274+/* Structure for "ipc signal" directive. */
1275+struct ccs_signal_acl {
1276+ struct ccs_acl_info head; /* type = CCS_TYPE_SIGNAL_ACL */
1277+ u16 sig;
1278+ /* Pointer to destination pattern. */
1279+ const struct ccs_path_info *domainname;
1280+};
1281+
1282+/* Structure for holding an IPv6 address. */
1283+struct ccs_ipv6addr {
1284+ struct ccs_shared_acl_head head;
1285+ struct in6_addr addr;
1286+};
1287+
1288+/* Structure for "network inet" directive. */
1289+struct ccs_inet_acl {
1290+ struct ccs_acl_info head; /* type = CCS_TYPE_INET_ACL */
1291+ u8 protocol;
1292+ u8 perm; /* Bitmask of values in "enum ccs_network_acl_index" */
1293+ /*
1294+ * address_type takes one of the following constants.
1295+ * CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP
1296+ * if @address points to "address_group" directive.
1297+ * CCS_IP_ADDRESS_TYPE_IPv4
1298+ * if @address points to an IPv4 address.
1299+ * CCS_IP_ADDRESS_TYPE_IPv6
1300+ * if @address points to an IPv6 address.
1301+ */
1302+ u8 address_type;
1303+ union {
1304+ struct {
1305+ /* Start of IPv4 address range. Host endian. */
1306+ u32 min;
1307+ /* End of IPv4 address range. Host endian. */
1308+ u32 max;
1309+ } ipv4;
1310+ struct {
1311+ /* Start of IPv6 address range. Big endian. */
1312+ const struct in6_addr *min;
1313+ /* End of IPv6 address range. Big endian. */
1314+ const struct in6_addr *max;
1315+ } ipv6;
1316+ /* Pointer to address group. */
1317+ struct ccs_group *group;
1318+ } address;
1319+ struct ccs_number_union port;
1320+};
1321+
1322+/* Structure for "network unix" directive. */
1323+struct ccs_unix_acl {
1324+ struct ccs_acl_info head; /* type = CCS_TYPE_UNIX_ACL */
1325+ u8 protocol;
1326+ u8 perm; /* Bitmask of values in "enum ccs_network_acl_index" */
1327+ struct ccs_name_union name;
1328+};
1329+
1330+/* Structure for holding string data. */
1331+struct ccs_name {
1332+ struct ccs_shared_acl_head head;
1333+ int size; /* Memory size allocated for this entry. */
1334+ struct ccs_path_info entry;
1335+};
1336+
1337+/* Structure for holding a line from /proc/ccs/ interface. */
1338+struct ccs_acl_param {
1339+ char *data;
1340+ struct ccs_domain_info *domain;
1341+ bool is_delete;
1342+};
1343+
1344+/* Structure for reading/writing policy via /proc/ccs/ interfaces. */
1345+struct ccs_io_buffer {
1346+ void (*read) (struct ccs_io_buffer *);
1347+ int (*write) (struct ccs_io_buffer *);
1348+ int (*poll) (struct file *file, poll_table *wait);
1349+ /* Exclusive lock for this structure. */
1350+ struct mutex io_sem;
1351+ char __user *read_user_buf;
1352+ size_t read_user_buf_avail;
1353+ struct {
1354+ struct list_head *domain;
1355+ struct list_head *group;
1356+ struct list_head *acl;
1357+ size_t avail;
1358+ unsigned int step;
1359+ unsigned int query_index;
1360+ u16 index;
1361+ u16 cond_index;
1362+ u8 acl_group_index;
1363+ u8 cond_step;
1364+ u8 bit;
1365+ u8 w_pos;
1366+ bool eof;
1367+ bool print_this_domain_only;
1368+ bool print_transition_related_only;
1369+ bool print_cond_part;
1370+ const char *w[CCS_MAX_IO_READ_QUEUE];
1371+ } r;
1372+ struct {
1373+ struct ccs_domain_info *domain;
1374+ size_t avail;
1375+ } w;
1376+ /* Buffer for reading. */
1377+ char *read_buf;
1378+ /* Size of read buffer. */
1379+ size_t readbuf_size;
1380+ /* Buffer for writing. */
1381+ char *write_buf;
1382+ /* Size of write buffer. */
1383+ size_t writebuf_size;
1384+ /* Type of interface. */
1385+ enum ccs_proc_interface_index type;
1386+ /* Users counter protected by ccs_io_buffer_list_lock. */
1387+ u8 users;
1388+ /* List for telling GC not to kfree() elements. */
1389+ struct list_head list;
1390+};
1391+
1392+/* Structure for /proc/ccs/profile interface. */
1393+struct ccs_profile {
1394+ const struct ccs_path_info *comment;
1395+ u8 default_config;
1396+ u8 config[CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX];
1397+ unsigned int pref[CCS_MAX_PREF];
1398+};
1399+
1400+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
1401+struct ccs_time {
1402+ u16 year;
1403+ u8 month;
1404+ u8 day;
1405+ u8 hour;
1406+ u8 min;
1407+ u8 sec;
1408+};
1409+
1410+/* Prototype definition for "struct ccsecurity_operations". */
1411+
1412+void __init ccs_capability_init(void);
1413+void __init ccs_domain_init(void);
1414+void __init ccs_file_init(void);
1415+void __init ccs_mm_init(void);
1416+void __init ccs_mount_init(void);
1417+void __init ccs_network_init(void);
1418+void __init ccs_policy_io_init(void);
1419+void __init ccs_signal_init(void);
1420+
1421+/* Prototype definition for internal use. */
1422+
1423+bool ccs_address_matches_group(const bool is_ipv6, const u32 *address,
1424+ const struct ccs_group *group);
1425+bool ccs_compare_number_union(const unsigned long value,
1426+ const struct ccs_number_union *ptr);
1427+bool ccs_condition(struct ccs_request_info *r,
1428+ const struct ccs_condition *cond);
1429+bool ccs_correct_domain(const unsigned char *domainname);
1430+bool ccs_correct_path(const char *filename);
1431+bool ccs_correct_word(const char *string);
1432+bool ccs_domain_def(const unsigned char *buffer);
1433+bool ccs_domain_quota_ok(struct ccs_request_info *r);
1434+bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1435+ struct ccs_page_dump *dump);
1436+bool ccs_memory_ok(const void *ptr, const unsigned int size);
1437+bool ccs_number_matches_group(const unsigned long min, const unsigned long max,
1438+ const struct ccs_group *group);
1439+bool ccs_parse_name_union(const char *filename, struct ccs_name_union *ptr);
1440+bool ccs_parse_number_union(char *data, struct ccs_number_union *num);
1441+bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
1442+ const struct ccs_path_info *pattern);
1443+bool ccs_permstr(const char *string, const char *keyword);
1444+bool ccs_str_starts(char **src, const char *find);
1445+bool ccs_tokenize(char *buffer, char *w[], size_t size);
1446+char *ccs_encode(const char *str);
1447+char *ccs_encode2(const char *str, int str_len);
1448+char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt,
1449+ va_list args);
1450+char *ccs_read_token(struct ccs_acl_param *param);
1451+char *ccs_realpath_from_path(struct path *path);
1452+const char *ccs_yesno(const unsigned int value);
1453+const char *ccs_get_exe(void);
1454+const struct ccs_path_info *ccs_compare_name_union
1455+(const struct ccs_path_info *name, const struct ccs_name_union *ptr);
1456+const struct ccs_path_info *ccs_get_domainname(struct ccs_acl_param *param);
1457+const struct ccs_path_info *ccs_get_name(const char *name);
1458+const struct ccs_path_info *ccs_path_matches_group
1459+(const struct ccs_path_info *pathname, const struct ccs_group *group);
1460+const struct in6_addr *ccs_get_ipv6_address(const struct in6_addr *addr);
1461+int ccs_close_control(struct file *file);
1462+int ccs_delete_domain(char *data);
1463+int ccs_env_perm(struct ccs_request_info *r, const char *env);
1464+int ccs_get_path(const char *pathname, struct path *path);
1465+int ccs_init_request_info(struct ccs_request_info *r, const u8 index);
1466+int ccs_open_control(const u8 type, struct file *file);
1467+int ccs_parse_ip_address(char *address, u16 *min, u16 *max);
1468+int ccs_path_permission(struct ccs_request_info *r, u8 operation,
1469+ const struct ccs_path_info *filename);
1470+int ccs_poll_control(struct file *file, poll_table *wait);
1471+int ccs_poll_log(struct file *file, poll_table *wait);
1472+int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
1473+ __attribute__ ((format(printf, 2, 3)));
1474+int ccs_symlink_path(const char *pathname, struct ccs_path_info *name);
1475+int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
1476+ struct ccs_acl_param *param,
1477+ bool (*check_duplicate) (const struct ccs_acl_info *,
1478+ const struct ccs_acl_info *),
1479+ bool (*merge_duplicate) (struct ccs_acl_info *,
1480+ struct ccs_acl_info *,
1481+ const bool));
1482+int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
1483+ bool is_delete, struct list_head *list,
1484+ bool (*check_duplicate) (const struct ccs_acl_head *,
1485+ const struct ccs_acl_head *));
1486+int ccs_write_aggregator(char *data, const bool is_delete);
1487+int ccs_write_capability(struct ccs_acl_param *param);
1488+int ccs_write_file(struct ccs_acl_param *param);
1489+int ccs_write_group(char *data, const bool is_delete, const u8 type);
1490+int ccs_write_inet_network(struct ccs_acl_param *param);
1491+int ccs_write_ipc(struct ccs_acl_param *param);
1492+int ccs_write_misc(struct ccs_acl_param *param);
1493+int ccs_write_reserved_port(char *data, const bool is_delete);
1494+int ccs_write_transition_control(char *data, const bool is_delete,
1495+ const u8 type);
1496+int ccs_write_unix_network(struct ccs_acl_param *param);
1497+ssize_t ccs_read_control(struct file *file, char __user *buffer,
1498+ const size_t buffer_len);
1499+ssize_t ccs_write_control(struct file *file, const char __user *buffer,
1500+ const size_t buffer_len);
1501+struct ccs_condition *ccs_get_condition(char *condition);
1502+struct ccs_domain_info *ccs_assign_domain(const char *domainname,
1503+ const u8 profile, const u8 group,
1504+ const bool transit);
1505+struct ccs_domain_info *ccs_find_domain(const char *domainname);
1506+struct ccs_group *ccs_get_group(const char *group_name, const u8 idx);
1507+struct ccs_profile *ccs_profile(const u8 profile);
1508+u8 ccs_get_config(const u8 profile, const u8 index);
1509+u8 ccs_parse_ulong(unsigned long *result, char **str);
1510+void *ccs_commit_ok(void *data, const unsigned int size);
1511+void ccs_check_acl(struct ccs_request_info *r,
1512+ bool (*check_entry) (struct ccs_request_info *,
1513+ const struct ccs_acl_info *));
1514+void ccs_convert_time(time_t time, struct ccs_time *p);
1515+void ccs_del_condition(struct list_head *element);
1516+void ccs_fill_path_info(struct ccs_path_info *ptr);
1517+void ccs_get_attributes(struct ccs_obj_info *obj);
1518+void ccs_memory_free(const void *ptr, size_t size);
1519+void ccs_normalize_line(unsigned char *buffer);
1520+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
1521+void ccs_print_ipv4(char *buffer, const int buffer_len, const u32 min_ip,
1522+ const u32 max_ip);
1523+void ccs_print_ipv6(char *buffer, const int buffer_len,
1524+ const struct in6_addr *min_ip,
1525+ const struct in6_addr *max_ip);
1526+void ccs_print_ulong(char *buffer, const int buffer_len,
1527+ const unsigned long value, const u8 type);
1528+void ccs_put_name_union(struct ccs_name_union *ptr);
1529+void ccs_put_number_union(struct ccs_number_union *ptr);
1530+void ccs_read_log(struct ccs_io_buffer *head);
1531+void ccs_transition_failed(const char *domainname);
1532+void ccs_update_stat(const u8 index);
1533+void ccs_warn_oom(const char *function);
1534+void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...)
1535+ __attribute__ ((format(printf, 2, 3)));
1536+void ccs_write_log2(struct ccs_request_info *r, int len, const char *fmt,
1537+ va_list args);
1538+#ifdef CONFIG_CCSECURITY_USE_BUILTIN_POLICY
1539+void __init ccs_load_builtin_policy(void);
1540+#endif
1541+
1542+/* Variable definition for internal use. */
1543+
1544+extern bool ccs_policy_loaded;
1545+extern const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD];
1546+extern const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS];
1547+extern const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
1548+ + CCS_MAX_MAC_CATEGORY_INDEX];
1549+extern const char * const ccs_mode[CCS_CONFIG_MAX_MODE];
1550+extern const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION];
1551+extern const char * const ccs_proto_keyword[CCS_SOCK_MAX];
1552+extern const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION];
1553+extern const u8 ccs_c2mac[CCS_MAX_CAPABILITY_INDEX];
1554+extern const u8 ccs_index2category[CCS_MAX_MAC_INDEX];
1555+extern const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION];
1556+extern const u8 ccs_pnnn2mac[CCS_MAX_MKDEV_OPERATION];
1557+extern const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION];
1558+extern struct ccs_domain_info ccs_acl_group[CCS_MAX_ACL_GROUPS];
1559+extern struct ccs_domain_info ccs_kernel_domain;
1560+extern struct list_head ccs_domain_list;
1561+extern struct list_head ccs_group_list[CCS_MAX_GROUP];
1562+extern struct list_head ccs_name_list[CCS_MAX_HASH];
1563+extern struct list_head ccs_policy_list[CCS_MAX_POLICY];
1564+extern struct list_head ccs_shared_list[CCS_MAX_LIST];
1565+extern struct mutex ccs_policy_lock;
1566+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1567+extern struct srcu_struct ccs_ss;
1568+#endif
1569+extern unsigned int ccs_memory_quota[CCS_MAX_MEMORY_STAT];
1570+extern unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];
1571+
1572+/* Inlined functions for internal use. */
1573+
1574+/**
1575+ * ccs_pathcmp - strcmp() for "struct ccs_path_info" structure.
1576+ *
1577+ * @a: Pointer to "struct ccs_path_info".
1578+ * @b: Pointer to "struct ccs_path_info".
1579+ *
1580+ * Returns true if @a == @b, false otherwise.
1581+ */
1582+static inline bool ccs_pathcmp(const struct ccs_path_info *a,
1583+ const struct ccs_path_info *b)
1584+{
1585+ return a->hash != b->hash || strcmp(a->name, b->name);
1586+}
1587+
1588+/**
1589+ * ccs_same_name_union - Check for duplicated "struct ccs_name_union" entry.
1590+ *
1591+ * @a: Pointer to "struct ccs_name_union".
1592+ * @b: Pointer to "struct ccs_name_union".
1593+ *
1594+ * Returns true if @a == @b, false otherwise.
1595+ */
1596+static inline bool ccs_same_name_union(const struct ccs_name_union *a,
1597+ const struct ccs_name_union *b)
1598+{
1599+ return a->filename == b->filename && a->group == b->group &&
1600+ a->is_group == b->is_group;
1601+}
1602+
1603+/**
1604+ * ccs_same_number_union - Check for duplicated "struct ccs_number_union" entry.
1605+ *
1606+ * @a: Pointer to "struct ccs_number_union".
1607+ * @b: Pointer to "struct ccs_number_union".
1608+ *
1609+ * Returns true if @a == @b, false otherwise.
1610+ */
1611+static inline bool ccs_same_number_union(const struct ccs_number_union *a,
1612+ const struct ccs_number_union *b)
1613+{
1614+ return a->values[0] == b->values[0] && a->values[1] == b->values[1]
1615+ && a->group == b->group &&
1616+ a->value_type[0] == b->value_type[0] &&
1617+ a->value_type[1] == b->value_type[1] &&
1618+ a->is_group == b->is_group;
1619+}
1620+
1621+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1622+
1623+/**
1624+ * ccs_read_lock - Take lock for protecting policy.
1625+ *
1626+ * Returns index number for ccs_read_unlock().
1627+ */
1628+static inline int ccs_read_lock(void)
1629+{
1630+ return srcu_read_lock(&ccs_ss);
1631+}
1632+
1633+/**
1634+ * ccs_read_unlock - Release lock for protecting policy.
1635+ *
1636+ * @idx: Index number returned by ccs_read_lock().
1637+ *
1638+ * Returns nothing.
1639+ */
1640+static inline void ccs_read_unlock(const int idx)
1641+{
1642+ srcu_read_unlock(&ccs_ss, idx);
1643+}
1644+
1645+#else
1646+
1647+int ccs_lock(void);
1648+void ccs_unlock(const int idx);
1649+
1650+/**
1651+ * ccs_read_lock - Take lock for protecting policy.
1652+ *
1653+ * Returns index number for ccs_read_unlock().
1654+ */
1655+static inline int ccs_read_lock(void)
1656+{
1657+ return ccs_lock();
1658+}
1659+
1660+/**
1661+ * ccs_read_unlock - Release lock for protecting policy.
1662+ *
1663+ * @idx: Index number returned by ccs_read_lock().
1664+ *
1665+ * Returns nothing.
1666+ */
1667+static inline void ccs_read_unlock(const int idx)
1668+{
1669+ ccs_unlock(idx);
1670+}
1671+
1672+#endif
1673+
1674+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
1675+
1676+/**
1677+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
1678+ *
1679+ * Returns nothing.
1680+ */
1681+static inline void ccs_tasklist_lock(void)
1682+{
1683+ rcu_read_lock();
1684+}
1685+
1686+/**
1687+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
1688+ *
1689+ * Returns nothing.
1690+ */
1691+static inline void ccs_tasklist_unlock(void)
1692+{
1693+ rcu_read_unlock();
1694+}
1695+
1696+#else
1697+
1698+/**
1699+ * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
1700+ *
1701+ * Returns nothing.
1702+ */
1703+static inline void ccs_tasklist_lock(void)
1704+{
1705+ read_lock(&tasklist_lock);
1706+}
1707+
1708+/**
1709+ * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
1710+ *
1711+ * Returns nothing.
1712+ */
1713+static inline void ccs_tasklist_unlock(void)
1714+{
1715+ read_unlock(&tasklist_lock);
1716+}
1717+
1718+#endif
1719+
1720+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1721+
1722+/**
1723+ * ccs_sys_getppid - Copy of getppid().
1724+ *
1725+ * Returns parent process's PID.
1726+ *
1727+ * Alpha does not have getppid() defined. To be able to build this module on
1728+ * Alpha, I have to copy getppid() from kernel/timer.c.
1729+ */
1730+static inline pid_t ccs_sys_getppid(void)
1731+{
1732+ pid_t pid;
1733+ rcu_read_lock();
1734+ pid = task_tgid_vnr(current->real_parent);
1735+ rcu_read_unlock();
1736+ return pid;
1737+}
1738+
1739+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1740+
1741+/**
1742+ * ccs_sys_getppid - Copy of getppid().
1743+ *
1744+ * Returns parent process's PID.
1745+ *
1746+ * This function was rewritten to use RCU in 2.6.16.34. However, distributors
1747+ * which use earlier kernels (e.g. 2.6.8/2.6.9) did not backport the bugfix.
1748+ * Therefore, I'm using code for 2.6.16.34 for earlier kernels.
1749+ */
1750+static inline pid_t ccs_sys_getppid(void)
1751+{
1752+ pid_t pid;
1753+ rcu_read_lock();
1754+#if (defined(RHEL_MAJOR) && RHEL_MAJOR == 5) || (defined(AX_MAJOR) && AX_MAJOR == 3)
1755+ pid = rcu_dereference(current->parent)->tgid;
1756+#else
1757+ pid = rcu_dereference(current->real_parent)->tgid;
1758+#endif
1759+ rcu_read_unlock();
1760+ return pid;
1761+}
1762+
1763+#else
1764+
1765+/**
1766+ * ccs_sys_getppid - Copy of getppid().
1767+ *
1768+ * Returns parent process's PID.
1769+ *
1770+ * I can't use code for 2.6.16.34 for 2.4 kernels because 2.4 kernels does not
1771+ * have RCU. Therefore, I'm using pessimistic lock (i.e. tasklist_lock
1772+ * spinlock).
1773+ */
1774+static inline pid_t ccs_sys_getppid(void)
1775+{
1776+ pid_t pid;
1777+ read_lock(&tasklist_lock);
1778+#ifdef TASK_DEAD
1779+ pid = current->group_leader->real_parent->tgid;
1780+#else
1781+ pid = current->p_opptr->pid;
1782+#endif
1783+ read_unlock(&tasklist_lock);
1784+ return pid;
1785+}
1786+
1787+#endif
1788+
1789+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1790+
1791+/**
1792+ * ccs_sys_getpid - Copy of getpid().
1793+ *
1794+ * Returns current thread's PID.
1795+ *
1796+ * Alpha does not have getpid() defined. To be able to build this module on
1797+ * Alpha, I have to copy getpid() from kernel/timer.c.
1798+ */
1799+static inline pid_t ccs_sys_getpid(void)
1800+{
1801+ return task_tgid_vnr(current);
1802+}
1803+
1804+#else
1805+
1806+/**
1807+ * ccs_sys_getpid - Copy of getpid().
1808+ *
1809+ * Returns current thread's PID.
1810+ */
1811+static inline pid_t ccs_sys_getpid(void)
1812+{
1813+ return current->tgid;
1814+}
1815+
1816+#endif
1817+
1818+/**
1819+ * ccs_get_mode - Get mode for specified functionality.
1820+ *
1821+ * @profile: Profile number.
1822+ * @index: Functionality number.
1823+ *
1824+ * Returns mode.
1825+ */
1826+static inline u8 ccs_get_mode(const u8 profile, const u8 index)
1827+{
1828+ return ccs_get_config(profile, index) & (CCS_CONFIG_MAX_MODE - 1);
1829+}
1830+
1831+#if defined(CONFIG_SLOB)
1832+
1833+/**
1834+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
1835+ *
1836+ * @size: Size to be rounded up.
1837+ *
1838+ * Returns @size.
1839+ *
1840+ * Since SLOB does not round up, this function simply returns @size.
1841+ */
1842+static inline int ccs_round2(size_t size)
1843+{
1844+ return size;
1845+}
1846+
1847+#else
1848+
1849+/**
1850+ * ccs_round2 - Round up to power of 2 for calculating memory usage.
1851+ *
1852+ * @size: Size to be rounded up.
1853+ *
1854+ * Returns rounded size.
1855+ *
1856+ * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
1857+ * (e.g.) 128 bytes.
1858+ */
1859+static inline int ccs_round2(size_t size)
1860+{
1861+#if PAGE_SIZE == 4096
1862+ size_t bsize = 32;
1863+#else
1864+ size_t bsize = 64;
1865+#endif
1866+ if (!size)
1867+ return 0;
1868+ while (size > bsize)
1869+ bsize <<= 1;
1870+ return bsize;
1871+}
1872+
1873+#endif
1874+
1875+/**
1876+ * ccs_put_condition - Drop reference on "struct ccs_condition".
1877+ *
1878+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
1879+ *
1880+ * Returns nothing.
1881+ */
1882+static inline void ccs_put_condition(struct ccs_condition *cond)
1883+{
1884+ if (cond)
1885+ atomic_dec(&cond->head.users);
1886+}
1887+
1888+/**
1889+ * ccs_put_group - Drop reference on "struct ccs_group".
1890+ *
1891+ * @group: Pointer to "struct ccs_group". Maybe NULL.
1892+ *
1893+ * Returns nothing.
1894+ */
1895+static inline void ccs_put_group(struct ccs_group *group)
1896+{
1897+ if (group)
1898+ atomic_dec(&group->head.users);
1899+}
1900+
1901+/**
1902+ * ccs_put_ipv6_address - Drop reference on "struct ccs_ipv6addr".
1903+ *
1904+ * @addr: Pointer to "struct in6_addr". Maybe NULL.
1905+ *
1906+ * Returns nothing.
1907+ */
1908+static inline void ccs_put_ipv6_address(const struct in6_addr *addr)
1909+{
1910+ if (addr)
1911+ atomic_dec(&container_of(addr, struct ccs_ipv6addr,
1912+ addr)->head.users);
1913+}
1914+
1915+/**
1916+ * ccs_put_name - Drop reference on "struct ccs_name".
1917+ *
1918+ * @name: Pointer to "struct ccs_path_info". Maybe NULL.
1919+ *
1920+ * Returns nothing.
1921+ */
1922+static inline void ccs_put_name(const struct ccs_path_info *name)
1923+{
1924+ if (name)
1925+ atomic_dec(&container_of(name, struct ccs_name, entry)->
1926+ head.users);
1927+}
1928+
1929+/* For importing variables and functions. */
1930+extern struct ccsecurity_exports ccsecurity_exports;
1931+
1932+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
1933+
1934+/*
1935+ * Structure for holding "struct ccs_domain_info *" and "struct ccs_execve *"
1936+ * and "u32 ccs_flags" for each "struct task_struct".
1937+ *
1938+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
1939+ * are maintained outside that "struct task_struct". Therefore, ccs_security
1940+ * != task_struct . This keeps KABI for distributor's prebuilt kernels but
1941+ * entails slow access.
1942+ *
1943+ * Memory for this structure is allocated when current thread tries to access
1944+ * it. Therefore, if memory allocation failed, current thread will be killed by
1945+ * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
1946+ */
1947+struct ccs_security {
1948+ struct list_head list;
1949+ const struct task_struct *task; /* Maybe NULL. */
1950+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
1951+ const struct cred *cred; /* Maybe NULL. */
1952+#endif
1953+ struct ccs_domain_info *ccs_domain_info;
1954+ u32 ccs_flags;
1955+ struct ccs_execve *ee; /* Maybe NULL. */
1956+ struct rcu_head rcu;
1957+};
1958+
1959+void __init ccs_main_init(void);
1960+bool ccs_used_by_cred(const struct ccs_domain_info *domain);
1961+int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve **eep);
1962+void ccs_finish_execve(int retval, struct ccs_execve *ee);
1963+void ccs_load_policy(const char *filename);
1964+extern spinlock_t ccs_task_security_list_lock;
1965+
1966+#define CCS_TASK_SECURITY_HASH_BITS 12
1967+#define CCS_MAX_TASK_SECURITY_HASH (1u << CCS_TASK_SECURITY_HASH_BITS)
1968+extern struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];
1969+
1970+struct ccs_security *ccs_find_task_security(const struct task_struct *task);
1971+
1972+/**
1973+ * ccs_current_security - Get "struct ccs_security" for current thread.
1974+ *
1975+ * Returns pointer to "struct ccs_security" for current thread.
1976+ */
1977+static inline struct ccs_security *ccs_current_security(void)
1978+{
1979+ return ccs_find_task_security(current);
1980+}
1981+
1982+/**
1983+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
1984+ *
1985+ * @task: Pointer to "struct task_struct".
1986+ *
1987+ * Returns pointer to "struct ccs_security" for specified thread.
1988+ */
1989+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
1990+{
1991+ struct ccs_domain_info *domain;
1992+ rcu_read_lock();
1993+ domain = ccs_find_task_security(task)->ccs_domain_info;
1994+ rcu_read_unlock();
1995+ return domain;
1996+}
1997+
1998+/**
1999+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
2000+ *
2001+ * Returns pointer to "struct ccs_domain_info" for current thread.
2002+ */
2003+static inline struct ccs_domain_info *ccs_current_domain(void)
2004+{
2005+ return ccs_find_task_security(current)->ccs_domain_info;
2006+}
2007+
2008+/**
2009+ * ccs_task_flags - Get flags for specified thread.
2010+ *
2011+ * @task: Pointer to "struct task_struct".
2012+ *
2013+ * Returns flags for specified thread.
2014+ */
2015+static inline u32 ccs_task_flags(struct task_struct *task)
2016+{
2017+ u32 ccs_flags;
2018+ rcu_read_lock();
2019+ ccs_flags = ccs_find_task_security(task)->ccs_flags;
2020+ rcu_read_unlock();
2021+ return ccs_flags;
2022+}
2023+
2024+/**
2025+ * ccs_current_flags - Get flags for current thread.
2026+ *
2027+ * Returns flags for current thread.
2028+ */
2029+static inline u32 ccs_current_flags(void)
2030+{
2031+ return ccs_find_task_security(current)->ccs_flags;
2032+}
2033+
2034+#else
2035+
2036+/*
2037+ * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
2038+ * are maintained inside that "struct task_struct". Therefore, ccs_security ==
2039+ * task_struct . This allows fast access but breaks KABI checks for
2040+ * distributor's prebuilt kernels due to changes in "struct task_struct".
2041+ */
2042+#define ccs_security task_struct
2043+
2044+/**
2045+ * ccs_find_task_security - Find "struct ccs_security" for given task.
2046+ *
2047+ * @task: Pointer to "struct task_struct".
2048+ *
2049+ * Returns pointer to "struct ccs_security".
2050+ */
2051+static inline struct ccs_security *ccs_find_task_security(struct task_struct *
2052+ task)
2053+{
2054+ return task;
2055+}
2056+
2057+/**
2058+ * ccs_current_security - Get "struct ccs_security" for current thread.
2059+ *
2060+ * Returns pointer to "struct ccs_security" for current thread.
2061+ */
2062+static inline struct ccs_security *ccs_current_security(void)
2063+{
2064+ return ccs_find_task_security(current);
2065+}
2066+
2067+/**
2068+ * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
2069+ *
2070+ * @task: Pointer to "struct task_struct".
2071+ *
2072+ * Returns pointer to "struct ccs_security" for specified thread.
2073+ */
2074+static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
2075+{
2076+ struct ccs_domain_info *domain = task->ccs_domain_info;
2077+ return domain ? domain : &ccs_kernel_domain;
2078+}
2079+
2080+/**
2081+ * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
2082+ *
2083+ * Returns pointer to "struct ccs_domain_info" for current thread.
2084+ *
2085+ * If current thread does not belong to a domain (which is true for initial
2086+ * init_task in order to hide ccs_kernel_domain from this module), current
2087+ * thread enters into ccs_kernel_domain.
2088+ */
2089+static inline struct ccs_domain_info *ccs_current_domain(void)
2090+{
2091+ struct task_struct *task = current;
2092+ if (!task->ccs_domain_info)
2093+ task->ccs_domain_info = &ccs_kernel_domain;
2094+ return task->ccs_domain_info;
2095+}
2096+
2097+/**
2098+ * ccs_task_flags - Get flags for specified thread.
2099+ *
2100+ * @task: Pointer to "struct task_struct".
2101+ *
2102+ * Returns flags for specified thread.
2103+ */
2104+static inline u32 ccs_task_flags(struct task_struct *task)
2105+{
2106+ return ccs_find_task_security(task)->ccs_flags;
2107+}
2108+
2109+/**
2110+ * ccs_current_flags - Get flags for current thread.
2111+ *
2112+ * Returns flags for current thread.
2113+ */
2114+static inline u32 ccs_current_flags(void)
2115+{
2116+ return ccs_find_task_security(current)->ccs_flags;
2117+}
2118+
2119+#endif
2120+
2121+#endif
--- tags/patches/1.0.12/ccsecurity.h (nonexistent)
+++ tags/patches/1.0.12/ccsecurity.h (revision 197)
@@ -0,0 +1,845 @@
1+/*
2+ * include/linux/ccsecurity.h
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#ifndef _LINUX_CCSECURITY_H
10+#define _LINUX_CCSECURITY_H
11+
12+#include <linux/version.h>
13+
14+#ifndef __user
15+#define __user
16+#endif
17+
18+struct nameidata;
19+struct path;
20+struct dentry;
21+struct vfsmount;
22+struct inode;
23+struct linux_binprm;
24+struct pt_regs;
25+struct file;
26+struct ctl_table;
27+struct socket;
28+struct sockaddr;
29+struct sock;
30+struct sk_buff;
31+struct msghdr;
32+struct pid_namespace;
33+int search_binary_handler(struct linux_binprm *bprm, struct pt_regs *regs);
34+
35+#ifdef CONFIG_CCSECURITY
36+
37+/* For exporting variables and functions. */
38+struct ccsecurity_exports {
39+ void (*load_policy) (const char *filename);
40+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
41+ char *(*__d_path) (const struct path *path, struct path *root,
42+ char *buf, int buflen);
43+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
44+ spinlock_t *vfsmount_lock;
45+#endif
46+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
47+ struct task_struct *(*find_task_by_vpid) (pid_t pid);
48+ struct task_struct *(*find_task_by_pid_ns) (pid_t pid,
49+ struct pid_namespace *ns);
50+#endif
51+};
52+
53+/* For doing access control. */
54+struct ccsecurity_operations {
55+ void (*check_profile) (void);
56+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
57+ int (*chroot_permission) (struct path *path);
58+ int (*pivot_root_permission) (struct path *old_path,
59+ struct path *new_path);
60+ int (*mount_permission) (char *dev_name, struct path *path,
61+ const char *type, unsigned long flags,
62+ void *data_page);
63+#else
64+ int (*chroot_permission) (struct nameidata *nd);
65+ int (*pivot_root_permission) (struct nameidata *old_nd,
66+ struct nameidata *new_nd);
67+ int (*mount_permission) (char *dev_name, struct nameidata *nd,
68+ const char *type, unsigned long flags,
69+ void *data_page);
70+#endif
71+ int (*umount_permission) (struct vfsmount *mnt, int flags);
72+ _Bool (*lport_reserved) (const u16 port);
73+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
74+ void (*save_open_mode) (int mode);
75+ void (*clear_open_mode) (void);
76+ int (*open_permission) (struct dentry *dentry, struct vfsmount *mnt,
77+ const int flag);
78+#else
79+ int (*open_permission) (struct file *file);
80+#endif
81+ int (*ptrace_permission) (long request, long pid);
82+ int (*ioctl_permission) (struct file *filp, unsigned int cmd,
83+ unsigned long arg);
84+ int (*parse_table) (int __user *name, int nlen, void __user *oldval,
85+ void __user *newval, struct ctl_table *table);
86+ _Bool (*capable) (const u8 operation);
87+ int (*mknod_permission) (struct inode *dir, struct dentry *dentry,
88+ struct vfsmount *mnt, unsigned int mode,
89+ unsigned int dev);
90+ int (*mkdir_permission) (struct inode *dir, struct dentry *dentry,
91+ struct vfsmount *mnt, unsigned int mode);
92+ int (*rmdir_permission) (struct inode *dir, struct dentry *dentry,
93+ struct vfsmount *mnt);
94+ int (*unlink_permission) (struct inode *dir, struct dentry *dentry,
95+ struct vfsmount *mnt);
96+ int (*symlink_permission) (struct inode *dir, struct dentry *dentry,
97+ struct vfsmount *mnt, const char *from);
98+ int (*truncate_permission) (struct dentry *dentry,
99+ struct vfsmount *mnt);
100+ int (*rename_permission) (struct inode *old_dir,
101+ struct dentry *old_dentry,
102+ struct inode *new_dir,
103+ struct dentry *new_dentry,
104+ struct vfsmount *mnt);
105+ int (*link_permission) (struct dentry *old_dentry,
106+ struct inode *new_dir,
107+ struct dentry *new_dentry,
108+ struct vfsmount *mnt);
109+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
110+ int (*open_exec_permission) (struct dentry *dentry,
111+ struct vfsmount *mnt);
112+ int (*uselib_permission) (struct dentry *dentry, struct vfsmount *mnt);
113+#endif
114+ int (*fcntl_permission) (struct file *file, unsigned int cmd,
115+ unsigned long arg);
116+ int (*kill_permission) (pid_t pid, int sig);
117+ int (*tgkill_permission) (pid_t tgid, pid_t pid, int sig);
118+ int (*tkill_permission) (pid_t pid, int sig);
119+ int (*socket_create_permission) (int family, int type, int protocol);
120+ int (*socket_listen_permission) (struct socket *sock);
121+ int (*socket_connect_permission) (struct socket *sock,
122+ struct sockaddr *addr, int addr_len);
123+ int (*socket_bind_permission) (struct socket *sock,
124+ struct sockaddr *addr, int addr_len);
125+ int (*socket_post_accept_permission) (struct socket *sock,
126+ struct socket *newsock);
127+ int (*socket_sendmsg_permission) (struct socket *sock,
128+ struct msghdr *msg, int size);
129+ int (*socket_post_recvmsg_permission) (struct sock *sk,
130+ struct sk_buff *skb, int flags);
131+ int (*chown_permission) (struct dentry *dentry, struct vfsmount *mnt,
132+ uid_t user, gid_t group);
133+ int (*chmod_permission) (struct dentry *dentry, struct vfsmount *mnt,
134+ mode_t mode);
135+ int (*getattr_permission) (struct vfsmount *mnt,
136+ struct dentry *dentry);
137+ int (*sigqueue_permission) (pid_t pid, int sig);
138+ int (*tgsigqueue_permission) (pid_t tgid, pid_t pid, int sig);
139+ int (*search_binary_handler) (struct linux_binprm *bprm,
140+ struct pt_regs *regs);
141+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
142+ int (*alloc_task_security) (const struct task_struct *task);
143+ void (*free_task_security) (const struct task_struct *task);
144+#endif
145+ _Bool disabled;
146+};
147+
148+extern struct ccsecurity_operations ccsecurity_ops;
149+
150+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
151+
152+static inline int ccs_chroot_permission(struct path *path)
153+{
154+ int (*func) (struct path *) = ccsecurity_ops.chroot_permission;
155+ return func ? func(path) : 0;
156+}
157+
158+static inline int ccs_pivot_root_permission(struct path *old_path,
159+ struct path *new_path)
160+{
161+ int (*func) (struct path *, struct path *)
162+ = ccsecurity_ops.pivot_root_permission;
163+ return func ? func(old_path, new_path) : 0;
164+}
165+
166+static inline int ccs_mount_permission(char *dev_name, struct path *path,
167+ char *type, unsigned long flags,
168+ void *data_page)
169+{
170+ int (*func) (char *, struct path *, const char *, unsigned long,
171+ void *) = ccsecurity_ops.mount_permission;
172+ return func ? func(dev_name, path, (const char *) type, flags,
173+ data_page) : 0;
174+}
175+
176+#else
177+
178+static inline int ccs_chroot_permission(struct nameidata *nd)
179+{
180+ int (*func) (struct nameidata *) = ccsecurity_ops.chroot_permission;
181+ return func ? func(nd) : 0;
182+}
183+
184+static inline int ccs_pivot_root_permission(struct nameidata *old_nd,
185+ struct nameidata *new_nd)
186+{
187+ int (*func) (struct nameidata *, struct nameidata *)
188+ = ccsecurity_ops.pivot_root_permission;
189+ return func ? func(old_nd, new_nd) : 0;
190+}
191+
192+static inline int ccs_mount_permission(char *dev_name, struct nameidata *nd,
193+ char *type, unsigned long flags,
194+ void *data_page)
195+{
196+ int (*func) (char *, struct nameidata *, const char *, unsigned long,
197+ void *) = ccsecurity_ops.mount_permission;
198+ return func ? func(dev_name, nd, (const char *) type, flags,
199+ data_page) : 0;
200+}
201+
202+#endif
203+
204+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
205+{
206+ int (*func) (struct vfsmount *, int)
207+ = ccsecurity_ops.umount_permission;
208+ return func ? func(mnt, flags) : 0;
209+}
210+
211+static inline _Bool ccs_lport_reserved(const u16 port)
212+{
213+ _Bool (*func) (const u16) = ccsecurity_ops.lport_reserved;
214+ return func ? func(port) : 0;
215+}
216+
217+static inline int ccs_ptrace_permission(long request, long pid)
218+{
219+ int (*func) (long, long) = ccsecurity_ops.ptrace_permission;
220+ return func ? func(request, pid) : 0;
221+}
222+
223+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
224+
225+static inline void ccs_save_open_mode(int mode)
226+{
227+ void (*func) (int) = ccsecurity_ops.save_open_mode;
228+ if (func)
229+ func(mode);
230+}
231+
232+static inline void ccs_clear_open_mode(void)
233+{
234+ void (*func) (void) = ccsecurity_ops.clear_open_mode;
235+ if (func)
236+ func();
237+}
238+
239+static inline int ccs_open_permission(struct dentry *dentry,
240+ struct vfsmount *mnt, const int flag)
241+{
242+ int (*func) (struct dentry *, struct vfsmount *, const int)
243+ = ccsecurity_ops.open_permission;
244+ return func ? func(dentry, mnt, flag) : 0;
245+}
246+
247+#else
248+
249+static inline int ccs_open_permission(struct file *filp)
250+{
251+ int (*func) (struct file *) = ccsecurity_ops.open_permission;
252+ return func ? func(filp) : 0;
253+}
254+
255+#endif
256+
257+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
258+ unsigned long arg)
259+{
260+ int (*func) (struct file *, unsigned int, unsigned long)
261+ = ccsecurity_ops.fcntl_permission;
262+ return func ? func(file, cmd, arg) : 0;
263+}
264+
265+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
266+ unsigned long arg)
267+{
268+ int (*func) (struct file *, unsigned int, unsigned long)
269+ = ccsecurity_ops.ioctl_permission;
270+ return func ? func(filp, cmd, arg) : 0;
271+}
272+
273+static inline int ccs_parse_table(int __user *name, int nlen,
274+ void __user *oldval, void __user *newval,
275+ struct ctl_table *table)
276+{
277+ int (*func) (int __user *, int, void __user *, void __user *,
278+ struct ctl_table *) = ccsecurity_ops.parse_table;
279+ return func ? func(name, nlen, oldval, newval, table) : 0;
280+}
281+
282+static inline _Bool ccs_capable(const u8 operation)
283+{
284+ _Bool (*func) (const u8) = ccsecurity_ops.capable;
285+ return func ? func(operation) : 1;
286+}
287+
288+static inline int ccs_mknod_permission(struct inode *dir,
289+ struct dentry *dentry,
290+ struct vfsmount *mnt, unsigned int mode,
291+ unsigned int dev)
292+{
293+ int (*func) (struct inode *, struct dentry *, struct vfsmount *,
294+ unsigned int, unsigned int)
295+ = ccsecurity_ops.mknod_permission;
296+ return func ? func(dir, dentry, mnt, mode, dev) : 0;
297+}
298+
299+static inline int ccs_mkdir_permission(struct inode *dir,
300+ struct dentry *dentry,
301+ struct vfsmount *mnt, unsigned int mode)
302+{
303+ int (*func) (struct inode *, struct dentry *, struct vfsmount *,
304+ unsigned int) = ccsecurity_ops.mkdir_permission;
305+ return func ? func(dir, dentry, mnt, mode) : 0;
306+}
307+
308+static inline int ccs_rmdir_permission(struct inode *dir,
309+ struct dentry *dentry,
310+ struct vfsmount *mnt)
311+{
312+ int (*func) (struct inode *, struct dentry *, struct vfsmount *)
313+ = ccsecurity_ops.rmdir_permission;
314+ return func ? func(dir, dentry, mnt) : 0;
315+}
316+
317+static inline int ccs_unlink_permission(struct inode *dir,
318+ struct dentry *dentry,
319+ struct vfsmount *mnt)
320+{
321+ int (*func) (struct inode *, struct dentry *, struct vfsmount *)
322+ = ccsecurity_ops.unlink_permission;
323+ return func ? func(dir, dentry, mnt) : 0;
324+}
325+
326+static inline int ccs_symlink_permission(struct inode *dir,
327+ struct dentry *dentry,
328+ struct vfsmount *mnt,
329+ const char *from)
330+{
331+ int (*func) (struct inode *, struct dentry *, struct vfsmount *,
332+ const char *) = ccsecurity_ops.symlink_permission;
333+ return func ? func(dir, dentry, mnt, from) : 0;
334+}
335+
336+static inline int ccs_truncate_permission(struct dentry *dentry,
337+ struct vfsmount *mnt)
338+{
339+ int (*func) (struct dentry *, struct vfsmount *)
340+ = ccsecurity_ops.truncate_permission;
341+ return func ? func(dentry, mnt) : 0;
342+}
343+
344+static inline int ccs_rename_permission(struct inode *old_dir,
345+ struct dentry *old_dentry,
346+ struct inode *new_dir,
347+ struct dentry *new_dentry,
348+ struct vfsmount *mnt)
349+{
350+ int (*func) (struct inode *, struct dentry *, struct inode *,
351+ struct dentry *, struct vfsmount *)
352+ = ccsecurity_ops.rename_permission;
353+ return func ? func(old_dir, old_dentry, new_dir, new_dentry, mnt) : 0;
354+}
355+
356+static inline int ccs_link_permission(struct dentry *old_dentry,
357+ struct inode *new_dir,
358+ struct dentry *new_dentry,
359+ struct vfsmount *mnt)
360+{
361+ int (*func) (struct dentry *, struct inode *, struct dentry *,
362+ struct vfsmount *) = ccsecurity_ops.link_permission;
363+ return func ? func(old_dentry, new_dir, new_dentry, mnt) : 0;
364+}
365+
366+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
367+
368+static inline int ccs_open_exec_permission(struct dentry *dentry,
369+ struct vfsmount *mnt)
370+{
371+ int (*func) (struct dentry *, struct vfsmount *)
372+ = ccsecurity_ops.open_exec_permission;
373+ return func ? func(dentry, mnt) : 0;
374+}
375+
376+static inline int ccs_uselib_permission(struct dentry *dentry,
377+ struct vfsmount *mnt)
378+{
379+ int (*func) (struct dentry *, struct vfsmount *)
380+ = ccsecurity_ops.uselib_permission;
381+ return func ? func(dentry, mnt) : 0;
382+}
383+
384+#endif
385+
386+static inline int ccs_kill_permission(pid_t pid, int sig)
387+{
388+ int (*func) (pid_t, int) = ccsecurity_ops.kill_permission;
389+ return func ? func(pid, sig) : 0;
390+}
391+
392+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
393+{
394+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgkill_permission;
395+ return func ? func(tgid, pid, sig) : 0;
396+}
397+
398+static inline int ccs_tkill_permission(pid_t pid, int sig)
399+{
400+ int (*func) (pid_t, int) = ccsecurity_ops.tkill_permission;
401+ return func ? func(pid, sig) : 0;
402+}
403+
404+static inline int ccs_socket_create_permission(int family, int type,
405+ int protocol)
406+{
407+ int (*func) (int, int, int) = ccsecurity_ops.socket_create_permission;
408+ return func ? func(family, type, protocol) : 0;
409+}
410+
411+static inline int ccs_socket_listen_permission(struct socket *sock)
412+{
413+ int (*func) (struct socket *)
414+ = ccsecurity_ops.socket_listen_permission;
415+ return func ? func(sock) : 0;
416+}
417+
418+static inline int ccs_socket_connect_permission(struct socket *sock,
419+ struct sockaddr *addr,
420+ int addr_len)
421+{
422+ int (*func) (struct socket *, struct sockaddr *, int)
423+ = ccsecurity_ops.socket_connect_permission;
424+ return func ? func(sock, addr, addr_len) : 0;
425+}
426+
427+static inline int ccs_socket_bind_permission(struct socket *sock,
428+ struct sockaddr *addr,
429+ int addr_len)
430+{
431+ int (*func) (struct socket *, struct sockaddr *, int)
432+ = ccsecurity_ops.socket_bind_permission;
433+ return func ? func(sock, addr, addr_len) : 0;
434+}
435+
436+static inline int ccs_socket_post_accept_permission(struct socket *sock,
437+ struct socket *newsock)
438+{
439+ int (*func) (struct socket *, struct socket *)
440+ = ccsecurity_ops.socket_post_accept_permission;
441+ return func ? func(sock, newsock) : 0;
442+}
443+
444+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
445+ struct msghdr *msg,
446+ int size)
447+{
448+ int (*func) (struct socket *, struct msghdr *, int)
449+ = ccsecurity_ops.socket_sendmsg_permission;
450+ return func ? func(sock, msg, size) : 0;
451+}
452+
453+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
454+ struct sk_buff *skb,
455+ int flags)
456+{
457+ int (*func) (struct sock *, struct sk_buff *, int)
458+ = ccsecurity_ops.socket_post_recvmsg_permission;
459+ return func ? func(sk, skb, flags) : 0;
460+}
461+
462+static inline int ccs_chown_permission(struct dentry *dentry,
463+ struct vfsmount *mnt, uid_t user,
464+ gid_t group)
465+{
466+ int (*func) (struct dentry *, struct vfsmount *, uid_t, gid_t)
467+ = ccsecurity_ops.chown_permission;
468+ return func ? func(dentry, mnt, user, group) : 0;
469+}
470+
471+static inline int ccs_chmod_permission(struct dentry *dentry,
472+ struct vfsmount *mnt, mode_t mode)
473+{
474+ int (*func) (struct dentry *, struct vfsmount *, mode_t)
475+ = ccsecurity_ops.chmod_permission;
476+ return func ? func(dentry, mnt, mode) : 0;
477+}
478+
479+static inline int ccs_getattr_permission(struct vfsmount *mnt,
480+ struct dentry *dentry)
481+{
482+ int (*func) (struct vfsmount *, struct dentry *)
483+ = ccsecurity_ops.getattr_permission;
484+ return func ? func(mnt, dentry) : 0;
485+}
486+
487+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
488+{
489+ int (*func) (pid_t, int) = ccsecurity_ops.sigqueue_permission;
490+ return func ? func(pid, sig) : 0;
491+}
492+
493+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
494+{
495+ int (*func) (pid_t, pid_t, int) = ccsecurity_ops.tgsigqueue_permission;
496+ return func ? func(tgid, pid, sig) : 0;
497+}
498+
499+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
500+ struct pt_regs *regs)
501+{
502+ return ccsecurity_ops.search_binary_handler(bprm, regs);
503+}
504+
505+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
506+
507+static inline int ccs_alloc_task_security(const struct task_struct *task)
508+{
509+ int (*func) (const struct task_struct *)
510+ = ccsecurity_ops.alloc_task_security;
511+ return func ? func(task) : 0;
512+}
513+
514+static inline void ccs_free_task_security(const struct task_struct *task)
515+{
516+ void (*func) (const struct task_struct *)
517+ = ccsecurity_ops.free_task_security;
518+ if (func)
519+ func(task);
520+}
521+
522+#else
523+
524+static inline int ccs_alloc_task_security(const struct task_struct *task)
525+{
526+ return 0;
527+}
528+
529+static inline void ccs_free_task_security(const struct task_struct *task)
530+{
531+}
532+
533+#endif
534+
535+#else
536+
537+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
538+
539+static inline int ccs_chroot_permission(struct path *path)
540+{
541+ return 0;
542+}
543+
544+static inline int ccs_pivot_root_permission(struct path *old_path,
545+ struct path *new_path)
546+{
547+ return 0;
548+}
549+
550+static inline int ccs_mount_permission(char *dev_name, struct path *path,
551+ char *type, unsigned long flags,
552+ void *data_page)
553+{
554+ return 0;
555+}
556+
557+#else
558+
559+static inline int ccs_chroot_permission(struct nameidata *nd)
560+{
561+ return 0;
562+}
563+
564+static inline int ccs_pivot_root_permission(struct nameidata *old_nd,
565+ struct nameidata *new_nd)
566+{
567+ return 0;
568+}
569+
570+static inline int ccs_mount_permission(char *dev_name, struct nameidata *nd,
571+ char *type, unsigned long flags,
572+ void *data_page)
573+{
574+ return 0;
575+}
576+
577+#endif
578+
579+static inline int ccs_umount_permission(struct vfsmount *mnt, int flags)
580+{
581+ return 0;
582+}
583+
584+static inline _Bool ccs_lport_reserved(const u16 port)
585+{
586+ return 0;
587+}
588+
589+static inline int ccs_ptrace_permission(long request, long pid)
590+{
591+ return 0;
592+}
593+
594+static inline void ccs_save_open_mode(int mode)
595+{
596+}
597+
598+static inline void ccs_clear_open_mode(void)
599+{
600+}
601+
602+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
603+
604+static inline int ccs_open_permission(struct dentry *dentry,
605+ struct vfsmount *mnt, const int flag)
606+{
607+ return 0;
608+}
609+
610+#else
611+
612+static inline int ccs_open_permission(struct file *filp)
613+{
614+ return 0;
615+}
616+
617+#endif
618+
619+static inline int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
620+ unsigned long arg)
621+{
622+ return 0;
623+}
624+
625+static inline int ccs_parse_table(int __user *name, int nlen,
626+ void __user *oldval, void __user *newval,
627+ struct ctl_table *table)
628+{
629+ return 0;
630+}
631+
632+static inline _Bool ccs_capable(const u8 operation)
633+{
634+ return 1;
635+}
636+
637+static inline int ccs_mknod_permission(struct inode *dir,
638+ struct dentry *dentry,
639+ struct vfsmount *mnt, unsigned int mode,
640+ unsigned int dev)
641+{
642+ return 0;
643+}
644+
645+static inline int ccs_mkdir_permission(struct inode *dir,
646+ struct dentry *dentry,
647+ struct vfsmount *mnt, unsigned int mode)
648+{
649+ return 0;
650+}
651+
652+static inline int ccs_rmdir_permission(struct inode *dir,
653+ struct dentry *dentry,
654+ struct vfsmount *mnt)
655+{
656+ return 0;
657+}
658+
659+static inline int ccs_unlink_permission(struct inode *dir,
660+ struct dentry *dentry,
661+ struct vfsmount *mnt)
662+{
663+ return 0;
664+}
665+
666+static inline int ccs_symlink_permission(struct inode *dir,
667+ struct dentry *dentry,
668+ struct vfsmount *mnt,
669+ const char *from)
670+{
671+ return 0;
672+}
673+
674+static inline int ccs_truncate_permission(struct dentry *dentry,
675+ struct vfsmount *mnt)
676+{
677+ return 0;
678+}
679+
680+static inline int ccs_rename_permission(struct inode *old_dir,
681+ struct dentry *old_dentry,
682+ struct inode *new_dir,
683+ struct dentry *new_dentry,
684+ struct vfsmount *mnt)
685+{
686+ return 0;
687+}
688+
689+static inline int ccs_link_permission(struct dentry *old_dentry,
690+ struct inode *new_dir,
691+ struct dentry *new_dentry,
692+ struct vfsmount *mnt)
693+{
694+ return 0;
695+}
696+
697+static inline int ccs_open_exec_permission(struct dentry *dentry,
698+ struct vfsmount *mnt)
699+{
700+ return 0;
701+}
702+
703+static inline int ccs_uselib_permission(struct dentry *dentry,
704+ struct vfsmount *mnt)
705+{
706+ return 0;
707+}
708+
709+static inline int ccs_fcntl_permission(struct file *file, unsigned int cmd,
710+ unsigned long arg)
711+{
712+ return 0;
713+}
714+
715+static inline int ccs_kill_permission(pid_t pid, int sig)
716+{
717+ return 0;
718+}
719+
720+static inline int ccs_tgkill_permission(pid_t tgid, pid_t pid, int sig)
721+{
722+ return 0;
723+}
724+
725+static inline int ccs_tkill_permission(pid_t pid, int sig)
726+{
727+ return 0;
728+}
729+
730+static inline int ccs_socket_create_permission(int family, int type,
731+ int protocol)
732+{
733+ return 0;
734+}
735+
736+static inline int ccs_socket_listen_permission(struct socket *sock)
737+{
738+ return 0;
739+}
740+
741+static inline int ccs_socket_connect_permission(struct socket *sock,
742+ struct sockaddr *addr,
743+ int addr_len)
744+{
745+ return 0;
746+}
747+
748+static inline int ccs_socket_bind_permission(struct socket *sock,
749+ struct sockaddr *addr,
750+ int addr_len)
751+{
752+ return 0;
753+}
754+
755+static inline int ccs_socket_post_accept_permission(struct socket *sock,
756+ struct socket *newsock)
757+{
758+ return 0;
759+}
760+
761+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
762+ struct msghdr *msg, int size)
763+{
764+ return 0;
765+}
766+
767+static inline int ccs_socket_post_recvmsg_permission(struct sock *sk,
768+ struct sk_buff *skb,
769+ int flags)
770+{
771+ return 0;
772+}
773+
774+static inline int ccs_chown_permission(struct dentry *dentry,
775+ struct vfsmount *mnt, uid_t user,
776+ gid_t group)
777+{
778+ return 0;
779+}
780+
781+static inline int ccs_chmod_permission(struct dentry *dentry,
782+ struct vfsmount *mnt, mode_t mode)
783+{
784+ return 0;
785+}
786+
787+static inline int ccs_getattr_permission(struct vfsmount *mnt,
788+ struct dentry *dentry)
789+{
790+ return 0;
791+}
792+
793+static inline int ccs_sigqueue_permission(pid_t pid, int sig)
794+{
795+ return 0;
796+}
797+
798+static inline int ccs_tgsigqueue_permission(pid_t tgid, pid_t pid, int sig)
799+{
800+ return 0;
801+}
802+
803+static inline int ccs_search_binary_handler(struct linux_binprm *bprm,
804+ struct pt_regs *regs)
805+{
806+ return search_binary_handler(bprm, regs);
807+}
808+
809+static inline int ccs_alloc_task_security(const struct task_struct *task)
810+{
811+ return 0;
812+}
813+
814+static inline void ccs_free_task_security(const struct task_struct *task)
815+{
816+}
817+
818+#endif
819+
820+/* Index numbers for Capability Controls. */
821+enum ccs_capability_acl_index {
822+ /* socket(PF_ROUTE, *, *) */
823+ CCS_USE_ROUTE_SOCKET,
824+ /* socket(PF_PACKET, *, *) */
825+ CCS_USE_PACKET_SOCKET,
826+ /* sys_reboot() */
827+ CCS_SYS_REBOOT,
828+ /* sys_vhangup() */
829+ CCS_SYS_VHANGUP,
830+ /* do_settimeofday(), sys_adjtimex() */
831+ CCS_SYS_SETTIME,
832+ /* sys_nice(), sys_setpriority() */
833+ CCS_SYS_NICE,
834+ /* sys_sethostname(), sys_setdomainname() */
835+ CCS_SYS_SETHOSTNAME,
836+ /* sys_create_module(), sys_init_module(), sys_delete_module() */
837+ CCS_USE_KERNEL_MODULE,
838+ /* sys_kexec_load() */
839+ CCS_SYS_KEXEC_LOAD,
840+ /* sys_ptrace() */
841+ CCS_SYS_PTRACE,
842+ CCS_MAX_CAPABILITY_INDEX
843+};
844+
845+#endif
--- tags/patches/1.0.12/condition.c (nonexistent)
+++ tags/patches/1.0.12/condition.c (revision 197)
@@ -0,0 +1,1095 @@
1+/*
2+ * security/ccsecurity/condition.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/**
12+ * ccs_argv - Check argv[] in "struct linux_binbrm".
13+ *
14+ * @index: Index number of @arg_ptr.
15+ * @arg_ptr: Contents of argv[@index].
16+ * @argc: Length of @argv.
17+ * @argv: Pointer to "struct ccs_argv".
18+ * @checked: Set to true if @argv[@index] was found.
19+ *
20+ * Returns true on success, false otherwise.
21+ */
22+static bool ccs_argv(const unsigned int index, const char *arg_ptr,
23+ const int argc, const struct ccs_argv *argv,
24+ u8 *checked)
25+{
26+ int i;
27+ struct ccs_path_info arg;
28+ arg.name = arg_ptr;
29+ for (i = 0; i < argc; argv++, checked++, i++) {
30+ bool result;
31+ if (index != argv->index)
32+ continue;
33+ *checked = 1;
34+ ccs_fill_path_info(&arg);
35+ result = ccs_path_matches_pattern(&arg, argv->value);
36+ if (argv->is_not)
37+ result = !result;
38+ if (!result)
39+ return false;
40+ }
41+ return true;
42+}
43+
44+/**
45+ * ccs_envp - Check envp[] in "struct linux_binbrm".
46+ *
47+ * @env_name: The name of environment variable.
48+ * @env_value: The value of environment variable.
49+ * @envc: Length of @envp.
50+ * @envp: Pointer to "struct ccs_envp".
51+ * @checked: Set to true if @envp[@env_name] was found.
52+ *
53+ * Returns true on success, false otherwise.
54+ */
55+static bool ccs_envp(const char *env_name, const char *env_value,
56+ const int envc, const struct ccs_envp *envp,
57+ u8 *checked)
58+{
59+ int i;
60+ struct ccs_path_info name;
61+ struct ccs_path_info value;
62+ name.name = env_name;
63+ ccs_fill_path_info(&name);
64+ value.name = env_value;
65+ ccs_fill_path_info(&value);
66+ for (i = 0; i < envc; envp++, checked++, i++) {
67+ bool result;
68+ if (!ccs_path_matches_pattern(&name, envp->name))
69+ continue;
70+ *checked = 1;
71+ if (envp->value) {
72+ result = ccs_path_matches_pattern(&value, envp->value);
73+ if (envp->is_not)
74+ result = !result;
75+ } else {
76+ result = true;
77+ if (!envp->is_not)
78+ result = !result;
79+ }
80+ if (!result)
81+ return false;
82+ }
83+ return true;
84+}
85+
86+/**
87+ * ccs_scan_bprm - Scan "struct linux_binprm".
88+ *
89+ * @ee: Pointer to "struct ccs_execve".
90+ * @argc: Length of @argc.
91+ * @argv: Pointer to "struct ccs_argv".
92+ * @envc: Length of @envp.
93+ * @envp: Poiner to "struct ccs_envp".
94+ *
95+ * Returns true on success, false otherwise.
96+ */
97+static bool ccs_scan_bprm(struct ccs_execve *ee,
98+ const u16 argc, const struct ccs_argv *argv,
99+ const u16 envc, const struct ccs_envp *envp)
100+{
101+ struct linux_binprm *bprm = ee->bprm;
102+ struct ccs_page_dump *dump = &ee->dump;
103+ char *arg_ptr = ee->tmp;
104+ int arg_len = 0;
105+ unsigned long pos = bprm->p;
106+ int offset = pos % PAGE_SIZE;
107+ int argv_count = bprm->argc;
108+ int envp_count = bprm->envc;
109+ bool result = true;
110+ u8 local_checked[32];
111+ u8 *checked;
112+ if (argc + envc <= sizeof(local_checked)) {
113+ checked = local_checked;
114+ memset(local_checked, 0, sizeof(local_checked));
115+ } else {
116+ checked = kzalloc(argc + envc, CCS_GFP_FLAGS);
117+ if (!checked)
118+ return false;
119+ }
120+ while (argv_count || envp_count) {
121+ if (!ccs_dump_page(bprm, pos, dump)) {
122+ result = false;
123+ goto out;
124+ }
125+ pos += PAGE_SIZE - offset;
126+ while (offset < PAGE_SIZE) {
127+ /* Read. */
128+ struct ccs_path_info arg;
129+ const char *kaddr = dump->data;
130+ const unsigned char c = kaddr[offset++];
131+ arg.name = arg_ptr;
132+ if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
133+ if (c == '\\') {
134+ arg_ptr[arg_len++] = '\\';
135+ arg_ptr[arg_len++] = '\\';
136+ } else if (c > ' ' && c < 127) {
137+ arg_ptr[arg_len++] = c;
138+ } else {
139+ arg_ptr[arg_len++] = '\\';
140+ arg_ptr[arg_len++] = (c >> 6) + '0';
141+ arg_ptr[arg_len++] =
142+ ((c >> 3) & 7) + '0';
143+ arg_ptr[arg_len++] = (c & 7) + '0';
144+ }
145+ } else {
146+ arg_ptr[arg_len] = '\0';
147+ }
148+ if (c)
149+ continue;
150+ /* Check. */
151+ if (argv_count) {
152+ if (!ccs_argv(bprm->argc - argv_count,
153+ arg_ptr, argc, argv,
154+ checked)) {
155+ result = false;
156+ break;
157+ }
158+ argv_count--;
159+ } else if (envp_count) {
160+ char *cp = strchr(arg_ptr, '=');
161+ if (cp) {
162+ *cp = '\0';
163+ if (!ccs_envp(arg_ptr, cp + 1,
164+ envc, envp,
165+ checked + argc)) {
166+ result = false;
167+ break;
168+ }
169+ }
170+ envp_count--;
171+ } else {
172+ break;
173+ }
174+ arg_len = 0;
175+ }
176+ offset = 0;
177+ if (!result)
178+ break;
179+ }
180+out:
181+ if (result) {
182+ int i;
183+ /* Check not-yet-checked entries. */
184+ for (i = 0; i < argc; i++) {
185+ if (checked[i])
186+ continue;
187+ /*
188+ * Return true only if all unchecked indexes in
189+ * bprm->argv[] are not matched.
190+ */
191+ if (argv[i].is_not)
192+ continue;
193+ result = false;
194+ break;
195+ }
196+ for (i = 0; i < envc; envp++, i++) {
197+ if (checked[argc + i])
198+ continue;
199+ /*
200+ * Return true only if all unchecked environ variables
201+ * in bprm->envp[] are either undefined or not matched.
202+ */
203+ if ((!envp->value && !envp->is_not) ||
204+ (envp->value && envp->is_not))
205+ continue;
206+ result = false;
207+ break;
208+ }
209+ }
210+ if (checked != local_checked)
211+ kfree(checked);
212+ return result;
213+}
214+
215+/**
216+ * ccs_scan_exec_realpath - Check "exec.realpath" parameter of "struct ccs_condition".
217+ *
218+ * @file: Pointer to "struct file".
219+ * @ptr: Pointer to "struct ccs_name_union".
220+ * @match: True if "exec.realpath=", false if "exec.realpath!=".
221+ *
222+ * Returns true on success, false otherwise.
223+ */
224+static bool ccs_scan_exec_realpath(struct file *file,
225+ const struct ccs_name_union *ptr,
226+ const bool match)
227+{
228+ bool result;
229+ struct ccs_path_info exe;
230+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
231+ struct path path;
232+#endif
233+ if (!file)
234+ return false;
235+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
236+ exe.name = ccs_realpath_from_path(&file->f_path);
237+#else
238+ path.mnt = file->f_vfsmnt;
239+ path.dentry = file->f_dentry;
240+ exe.name = ccs_realpath_from_path(&path);
241+#endif
242+ if (!exe.name)
243+ return false;
244+ ccs_fill_path_info(&exe);
245+ result = ccs_compare_name_union(&exe, ptr);
246+ kfree(exe.name);
247+ return result == match;
248+}
249+
250+/**
251+ * ccs_get_dqword - ccs_get_name() for a quoted string.
252+ *
253+ * @start: String to save.
254+ *
255+ * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
256+ */
257+static const struct ccs_path_info *ccs_get_dqword(char *start)
258+{
259+ char *cp;
260+ if (*start++ != '"')
261+ return NULL;
262+ cp = start;
263+ while (1) {
264+ const char c = *cp++;
265+ if (!c)
266+ return NULL;
267+ if (c != '"' || *cp)
268+ continue;
269+ *(cp - 1) = '\0';
270+ break;
271+ }
272+ if (*start && !ccs_correct_word(start))
273+ return NULL;
274+ return ccs_get_name(start);
275+}
276+
277+/**
278+ * ccs_parse_name_union_quoted - Parse a quoted word.
279+ *
280+ * @filename: A line containing a quoted word.
281+ * @ptr: Pointer to "struct ccs_name_union".
282+ *
283+ * Returns true on success, false otherwise.
284+ */
285+static bool ccs_parse_name_union_quoted(char *filename,
286+ struct ccs_name_union *ptr)
287+{
288+ if (*filename == '@')
289+ return ccs_parse_name_union(filename, ptr);
290+ ptr->is_group = false;
291+ ptr->filename = ccs_get_dqword(filename);
292+ return ptr->filename != NULL;
293+}
294+
295+/**
296+ * ccs_parse_argv - Parse an argv[] condition part.
297+ *
298+ * @start: String to parse.
299+ * @argv: Pointer to "struct ccs_argv".
300+ *
301+ * Returns true on success, false otherwise.
302+ */
303+static bool ccs_parse_argv(char *start, struct ccs_argv *argv)
304+{
305+ unsigned long index;
306+ const struct ccs_path_info *value;
307+ bool is_not;
308+ char c;
309+ if (ccs_parse_ulong(&index, &start) != CCS_VALUE_TYPE_DECIMAL)
310+ goto out;
311+ if (*start++ != ']')
312+ goto out;
313+ c = *start++;
314+ if (c == '=')
315+ is_not = false;
316+ else if (c == '!' && *start++ == '=')
317+ is_not = true;
318+ else
319+ goto out;
320+ value = ccs_get_dqword(start);
321+ if (!value)
322+ goto out;
323+ argv->index = index;
324+ argv->is_not = is_not;
325+ argv->value = value;
326+ return true;
327+out:
328+ return false;
329+}
330+
331+/**
332+ * ccs_parse_envp - Parse an envp[] condition part.
333+ *
334+ * @start: String to parse.
335+ * @envp: Pointer to "struct ccs_envp".
336+ *
337+ * Returns true on success, false otherwise.
338+ */
339+static bool ccs_parse_envp(char *start, struct ccs_envp *envp)
340+{
341+ const struct ccs_path_info *name;
342+ const struct ccs_path_info *value;
343+ bool is_not;
344+ char *cp = start;
345+ /*
346+ * Since environment variable names don't
347+ * contain '=', I can treat '"]=' and '"]!='
348+ * sequences as delimiters.
349+ */
350+ while (1) {
351+ if (!strncmp(start, "\"]=", 3)) {
352+ is_not = false;
353+ *start = '\0';
354+ start += 3;
355+ break;
356+ } else if (!strncmp(start, "\"]!=", 4)) {
357+ is_not = true;
358+ *start = '\0';
359+ start += 4;
360+ break;
361+ } else if (!*start++) {
362+ goto out;
363+ }
364+ }
365+ if (!ccs_correct_word(cp))
366+ goto out;
367+ name = ccs_get_name(cp);
368+ if (!name)
369+ goto out;
370+ if (!strcmp(start, "NULL")) {
371+ value = NULL;
372+ } else {
373+ value = ccs_get_dqword(start);
374+ if (!value) {
375+ ccs_put_name(name);
376+ goto out;
377+ }
378+ }
379+ envp->name = name;
380+ envp->is_not = is_not;
381+ envp->value = value;
382+ return true;
383+out:
384+ return false;
385+}
386+
387+/**
388+ * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
389+ *
390+ * @a: Pointer to "struct ccs_condition".
391+ * @b: Pointer to "struct ccs_condition".
392+ *
393+ * Returns true if @a == @b, false otherwise.
394+ */
395+static inline bool ccs_same_condition(const struct ccs_condition *a,
396+ const struct ccs_condition *b)
397+{
398+ return a->size == b->size && a->condc == b->condc &&
399+ a->numbers_count == b->numbers_count &&
400+ a->names_count == b->names_count &&
401+ a->argc == b->argc && a->envc == b->envc &&
402+ a->grant_log == b->grant_log && a->transit == b->transit &&
403+ !memcmp(a + 1, b + 1, a->size - sizeof(*a));
404+}
405+
406+/**
407+ * ccs_condition_type - Get condition type.
408+ *
409+ * @word: Keyword string.
410+ *
411+ * Returns one of values in "enum ccs_conditions_index" on success,
412+ * CCS_MAX_CONDITION_KEYWORD otherwise.
413+ */
414+static u8 ccs_condition_type(const char *word)
415+{
416+ u8 i;
417+ for (i = 0; i < CCS_MAX_CONDITION_KEYWORD; i++) {
418+ if (!strcmp(word, ccs_condition_keyword[i]))
419+ break;
420+ }
421+ return i;
422+}
423+
424+/* Define this to enable debug mode. */
425+/* #define DEBUG_CONDITION */
426+
427+#ifdef DEBUG_CONDITION
428+#define dprintk printk
429+#else
430+#define dprintk(...) do { } while (0)
431+#endif
432+
433+/**
434+ * ccs_commit_condition - Commit "struct ccs_condition".
435+ *
436+ * @entry: Pointer to "struct ccs_condition".
437+ *
438+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
439+ *
440+ * This function merges duplicated entries. This function returns NULL if
441+ * @entry is not duplicated but memory quota for policy has exceeded.
442+ */
443+static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
444+{
445+ struct ccs_condition *ptr;
446+ bool found = false;
447+ if (mutex_lock_interruptible(&ccs_policy_lock)) {
448+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
449+ ptr = NULL;
450+ found = true;
451+ goto out;
452+ }
453+ list_for_each_entry_srcu(ptr, &ccs_shared_list[CCS_CONDITION_LIST],
454+ head.list, &ccs_ss) {
455+ if (!ccs_same_condition(ptr, entry))
456+ continue;
457+ /* Same entry found. Share this entry. */
458+ atomic_inc(&ptr->head.users);
459+ found = true;
460+ break;
461+ }
462+ if (!found) {
463+ if (ccs_memory_ok(entry, entry->size)) {
464+ atomic_set(&entry->head.users, 1);
465+ list_add_rcu(&entry->head.list,
466+ &ccs_shared_list[CCS_CONDITION_LIST]);
467+ } else {
468+ found = true;
469+ ptr = NULL;
470+ }
471+ }
472+ mutex_unlock(&ccs_policy_lock);
473+out:
474+ if (found) {
475+ ccs_del_condition(&entry->head.list);
476+ kfree(entry);
477+ entry = ptr;
478+ }
479+ return entry;
480+}
481+
482+/**
483+ * ccs_get_condition - Parse condition part.
484+ *
485+ * @condition: Pointer to string to parse.
486+ *
487+ * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
488+ */
489+struct ccs_condition *ccs_get_condition(char *condition)
490+{
491+ char *start;
492+ struct ccs_condition *entry = NULL;
493+ struct ccs_condition_element *condp = NULL;
494+ struct ccs_number_union *numbers_p = NULL;
495+ struct ccs_name_union *names_p = NULL;
496+ struct ccs_argv *argv = NULL;
497+ struct ccs_envp *envp = NULL;
498+ struct ccs_condition e = { };
499+ bool dry_run = true;
500+ char *end_of_string = condition + strlen(condition);
501+rerun:
502+ start = condition;
503+ while (1) {
504+ u8 left = -1;
505+ u8 right = -1;
506+ char *word = start;
507+ char *cp;
508+ char *eq;
509+ bool is_not = false;
510+ if (!*word)
511+ break;
512+ cp = strchr(start, ' ');
513+ if (cp) {
514+ *cp = '\0';
515+ start = cp + 1;
516+ } else {
517+ start = "";
518+ }
519+ dprintk(KERN_WARNING "%u: <%s>\n", __LINE__, word);
520+ if (!strncmp(word, "grant_log=", 10)) {
521+ if (!dry_run) {
522+ word += 10;
523+ if (entry->grant_log != CCS_GRANTLOG_AUTO)
524+ goto out;
525+ else if (!strcmp(word, "yes"))
526+ entry->grant_log = CCS_GRANTLOG_YES;
527+ else if (!strcmp(word, "no"))
528+ entry->grant_log = CCS_GRANTLOG_NO;
529+ else
530+ goto out;
531+ }
532+ continue;
533+ } else if (!strncmp(word, "auto_domain_transition=", 23)) {
534+ if (!dry_run) {
535+ word += 23;
536+ if (entry->transit)
537+ goto out;
538+ entry->transit = ccs_get_dqword(word);
539+ if (!entry->transit ||
540+ entry->transit->name[0] != '/')
541+ goto out;
542+ }
543+ continue;
544+ }
545+ if (!strncmp(word, "exec.argv[", 10)) {
546+ if (dry_run) {
547+ e.argc++;
548+ e.condc++;
549+ } else {
550+ e.argc--;
551+ e.condc--;
552+ left = CCS_ARGV_ENTRY;
553+ if (!ccs_parse_argv(word + 10, argv++))
554+ goto out;
555+ }
556+ goto store_value;
557+ } else if (!strncmp(word, "exec.envp[\"", 11)) {
558+ if (dry_run) {
559+ e.envc++;
560+ e.condc++;
561+ } else {
562+ e.envc--;
563+ e.condc--;
564+ left = CCS_ENVP_ENTRY;
565+ if (!ccs_parse_envp(word + 11, envp++))
566+ goto out;
567+ }
568+ goto store_value;
569+ }
570+ eq = strchr(word, '=');
571+ if (!eq)
572+ goto out;
573+ if (eq > word && *(eq - 1) == '!') {
574+ is_not = true;
575+ eq--;
576+ }
577+ *eq = '\0';
578+ left = ccs_condition_type(word);
579+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, word,
580+ left);
581+ if (left == CCS_MAX_CONDITION_KEYWORD) {
582+ if (dry_run) {
583+ e.numbers_count++;
584+ } else {
585+ e.numbers_count--;
586+ left = CCS_NUMBER_UNION;
587+ if (!ccs_parse_number_union(word, numbers_p))
588+ goto out;
589+ if (numbers_p->is_group)
590+ goto out;
591+ numbers_p++;
592+ }
593+ }
594+ *eq = is_not ? '!' : '=';
595+ word = eq + 1;
596+ if (is_not)
597+ word++;
598+ if (dry_run)
599+ e.condc++;
600+ else
601+ e.condc--;
602+ if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
603+ if (dry_run) {
604+ e.names_count++;
605+ } else {
606+ e.names_count--;
607+ right = CCS_NAME_UNION;
608+ if (!ccs_parse_name_union_quoted(word,
609+ names_p++))
610+ goto out;
611+ }
612+ goto store_value;
613+ }
614+ right = ccs_condition_type(word);
615+ if (right == CCS_MAX_CONDITION_KEYWORD) {
616+ if (dry_run) {
617+ e.numbers_count++;
618+ } else {
619+ e.numbers_count--;
620+ right = CCS_NUMBER_UNION;
621+ if (!ccs_parse_number_union(word, numbers_p++))
622+ goto out;
623+ }
624+ }
625+store_value:
626+ if (dry_run)
627+ continue;
628+ condp->left = left;
629+ condp->right = right;
630+ condp->equals = !is_not;
631+ dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
632+ __LINE__, condp->left, condp->right,
633+ condp->equals);
634+ condp++;
635+ }
636+ dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
637+ __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
638+ e.envc);
639+ if (!dry_run) {
640+ BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
641+ e.condc);
642+ return ccs_commit_condition(entry);
643+ }
644+ e.size = sizeof(*entry)
645+ + e.condc * sizeof(struct ccs_condition_element)
646+ + e.numbers_count * sizeof(struct ccs_number_union)
647+ + e.names_count * sizeof(struct ccs_name_union)
648+ + e.argc * sizeof(struct ccs_argv)
649+ + e.envc * sizeof(struct ccs_envp);
650+ entry = kzalloc(e.size, CCS_GFP_FLAGS);
651+ if (!entry)
652+ return NULL;
653+ *entry = e;
654+ condp = (struct ccs_condition_element *) (entry + 1);
655+ numbers_p = (struct ccs_number_union *) (condp + e.condc);
656+ names_p = (struct ccs_name_union *) (numbers_p + e.numbers_count);
657+ argv = (struct ccs_argv *) (names_p + e.names_count);
658+ envp = (struct ccs_envp *) (argv + e.argc);
659+ for (start = condition; start < end_of_string; start++)
660+ if (!*start)
661+ *start = ' ';
662+ dry_run = false;
663+ goto rerun;
664+out:
665+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
666+ if (entry) {
667+ ccs_del_condition(&entry->head.list);
668+ kfree(entry);
669+ }
670+ return NULL;
671+}
672+
673+/**
674+ * ccs_get_attributes - Revalidate "struct inode".
675+ *
676+ * @obj: Pointer to "struct ccs_obj_info".
677+ *
678+ * Returns nothing.
679+ */
680+void ccs_get_attributes(struct ccs_obj_info *obj)
681+{
682+ u8 i;
683+ struct dentry *dentry = NULL;
684+
685+ for (i = 0; i < CCS_MAX_PATH_STAT; i++) {
686+ struct inode *inode;
687+ switch (i) {
688+ case CCS_PATH1:
689+ dentry = obj->path1.dentry;
690+ if (!dentry)
691+ continue;
692+ break;
693+ case CCS_PATH2:
694+ dentry = obj->path2.dentry;
695+ if (!dentry)
696+ continue;
697+ break;
698+ default:
699+ if (!dentry)
700+ continue;
701+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
702+ spin_lock(&dcache_lock);
703+ dentry = dget(dentry->d_parent);
704+ spin_unlock(&dcache_lock);
705+#else
706+ dentry = dget_parent(dentry);
707+#endif
708+ break;
709+ }
710+ inode = dentry->d_inode;
711+ if (inode) {
712+ struct ccs_mini_stat *stat = &obj->stat[i];
713+ stat->uid = inode->i_uid;
714+ stat->gid = inode->i_gid;
715+ stat->ino = inode->i_ino;
716+ stat->mode = inode->i_mode;
717+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
718+ stat->dev = inode->i_dev;
719+#else
720+ stat->dev = inode->i_sb->s_dev;
721+#endif
722+ stat->rdev = inode->i_rdev;
723+ obj->stat_valid[i] = true;
724+ }
725+ if (i & 1) /* i == CCS_PATH1_PARENT || i == CCS_PATH2_PARENT */
726+ dput(dentry);
727+ }
728+}
729+
730+/**
731+ * ccs_condition - Check condition part.
732+ *
733+ * @r: Pointer to "struct ccs_request_info".
734+ * @cond: Pointer to "struct ccs_condition". Maybe NULL.
735+ *
736+ * Returns true on success, false otherwise.
737+ *
738+ * Caller holds ccs_read_lock().
739+ */
740+bool ccs_condition(struct ccs_request_info *r,
741+ const struct ccs_condition *cond)
742+{
743+ const u32 ccs_flags = ccs_current_flags();
744+ u32 i;
745+ unsigned long min_v[2] = { 0, 0 };
746+ unsigned long max_v[2] = { 0, 0 };
747+ const struct ccs_condition_element *condp;
748+ const struct ccs_number_union *numbers_p;
749+ const struct ccs_name_union *names_p;
750+ const struct ccs_argv *argv;
751+ const struct ccs_envp *envp;
752+ struct ccs_obj_info *obj;
753+ u16 condc;
754+ u16 argc;
755+ u16 envc;
756+ struct linux_binprm *bprm = NULL;
757+ if (!cond)
758+ return true;
759+ condc = cond->condc;
760+ argc = cond->argc;
761+ envc = cond->envc;
762+ obj = r->obj;
763+ if (r->ee)
764+ bprm = r->ee->bprm;
765+ if (!bprm && (argc || envc))
766+ return false;
767+ condp = (struct ccs_condition_element *) (cond + 1);
768+ numbers_p = (const struct ccs_number_union *) (condp + condc);
769+ names_p = (const struct ccs_name_union *)
770+ (numbers_p + cond->numbers_count);
771+ argv = (const struct ccs_argv *) (names_p + cond->names_count);
772+ envp = (const struct ccs_envp *) (argv + argc);
773+ for (i = 0; i < condc; i++) {
774+ const bool match = condp->equals;
775+ const u8 left = condp->left;
776+ const u8 right = condp->right;
777+ bool is_bitop[2] = { false, false };
778+ u8 j;
779+ condp++;
780+ /* Check argv[] and envp[] later. */
781+ if (left == CCS_ARGV_ENTRY || left == CCS_ENVP_ENTRY)
782+ continue;
783+ /* Check string expressions. */
784+ if (right == CCS_NAME_UNION) {
785+ const struct ccs_name_union *ptr = names_p++;
786+ switch (left) {
787+ struct ccs_path_info *symlink;
788+ struct ccs_execve *ee;
789+ struct file *file;
790+ case CCS_SYMLINK_TARGET:
791+ symlink = obj ? obj->symlink_target : NULL;
792+ if (!symlink ||
793+ !ccs_compare_name_union(symlink, ptr)
794+ == match)
795+ goto out;
796+ break;
797+ case CCS_EXEC_REALPATH:
798+ ee = r->ee;
799+ file = ee ? ee->bprm->file : NULL;
800+ if (!ccs_scan_exec_realpath(file, ptr, match))
801+ goto out;
802+ break;
803+ }
804+ continue;
805+ }
806+ /* Check numeric or bit-op expressions. */
807+ for (j = 0; j < 2; j++) {
808+ const u8 index = j ? right : left;
809+ unsigned long value = 0;
810+ switch (index) {
811+ case CCS_TASK_UID:
812+ value = current_uid();
813+ break;
814+ case CCS_TASK_EUID:
815+ value = current_euid();
816+ break;
817+ case CCS_TASK_SUID:
818+ value = current_suid();
819+ break;
820+ case CCS_TASK_FSUID:
821+ value = current_fsuid();
822+ break;
823+ case CCS_TASK_GID:
824+ value = current_gid();
825+ break;
826+ case CCS_TASK_EGID:
827+ value = current_egid();
828+ break;
829+ case CCS_TASK_SGID:
830+ value = current_sgid();
831+ break;
832+ case CCS_TASK_FSGID:
833+ value = current_fsgid();
834+ break;
835+ case CCS_TASK_PID:
836+ value = ccs_sys_getpid();
837+ break;
838+ case CCS_TASK_PPID:
839+ value = ccs_sys_getppid();
840+ break;
841+ case CCS_TYPE_IS_SOCKET:
842+ value = S_IFSOCK;
843+ break;
844+ case CCS_TYPE_IS_SYMLINK:
845+ value = S_IFLNK;
846+ break;
847+ case CCS_TYPE_IS_FILE:
848+ value = S_IFREG;
849+ break;
850+ case CCS_TYPE_IS_BLOCK_DEV:
851+ value = S_IFBLK;
852+ break;
853+ case CCS_TYPE_IS_DIRECTORY:
854+ value = S_IFDIR;
855+ break;
856+ case CCS_TYPE_IS_CHAR_DEV:
857+ value = S_IFCHR;
858+ break;
859+ case CCS_TYPE_IS_FIFO:
860+ value = S_IFIFO;
861+ break;
862+ case CCS_MODE_SETUID:
863+ value = S_ISUID;
864+ break;
865+ case CCS_MODE_SETGID:
866+ value = S_ISGID;
867+ break;
868+ case CCS_MODE_STICKY:
869+ value = S_ISVTX;
870+ break;
871+ case CCS_MODE_OWNER_READ:
872+ value = S_IRUSR;
873+ break;
874+ case CCS_MODE_OWNER_WRITE:
875+ value = S_IWUSR;
876+ break;
877+ case CCS_MODE_OWNER_EXECUTE:
878+ value = S_IXUSR;
879+ break;
880+ case CCS_MODE_GROUP_READ:
881+ value = S_IRGRP;
882+ break;
883+ case CCS_MODE_GROUP_WRITE:
884+ value = S_IWGRP;
885+ break;
886+ case CCS_MODE_GROUP_EXECUTE:
887+ value = S_IXGRP;
888+ break;
889+ case CCS_MODE_OTHERS_READ:
890+ value = S_IROTH;
891+ break;
892+ case CCS_MODE_OTHERS_WRITE:
893+ value = S_IWOTH;
894+ break;
895+ case CCS_MODE_OTHERS_EXECUTE:
896+ value = S_IXOTH;
897+ break;
898+ case CCS_EXEC_ARGC:
899+ if (!bprm)
900+ goto out;
901+ value = bprm->argc;
902+ break;
903+ case CCS_EXEC_ENVC:
904+ if (!bprm)
905+ goto out;
906+ value = bprm->envc;
907+ break;
908+ case CCS_TASK_TYPE:
909+ value = ((u8) ccs_flags)
910+ & CCS_TASK_IS_EXECUTE_HANDLER;
911+ break;
912+ case CCS_TASK_EXECUTE_HANDLER:
913+ value = CCS_TASK_IS_EXECUTE_HANDLER;
914+ break;
915+ case CCS_NUMBER_UNION:
916+ /* Fetch values later. */
917+ break;
918+ default:
919+ if (!obj)
920+ goto out;
921+ if (!obj->validate_done) {
922+ ccs_get_attributes(obj);
923+ obj->validate_done = true;
924+ }
925+ {
926+ u8 stat_index;
927+ struct ccs_mini_stat *stat;
928+ switch (index) {
929+ case CCS_PATH1_UID:
930+ case CCS_PATH1_GID:
931+ case CCS_PATH1_INO:
932+ case CCS_PATH1_MAJOR:
933+ case CCS_PATH1_MINOR:
934+ case CCS_PATH1_TYPE:
935+ case CCS_PATH1_DEV_MAJOR:
936+ case CCS_PATH1_DEV_MINOR:
937+ case CCS_PATH1_PERM:
938+ stat_index = CCS_PATH1;
939+ break;
940+ case CCS_PATH2_UID:
941+ case CCS_PATH2_GID:
942+ case CCS_PATH2_INO:
943+ case CCS_PATH2_MAJOR:
944+ case CCS_PATH2_MINOR:
945+ case CCS_PATH2_TYPE:
946+ case CCS_PATH2_DEV_MAJOR:
947+ case CCS_PATH2_DEV_MINOR:
948+ case CCS_PATH2_PERM:
949+ stat_index = CCS_PATH2;
950+ break;
951+ case CCS_PATH1_PARENT_UID:
952+ case CCS_PATH1_PARENT_GID:
953+ case CCS_PATH1_PARENT_INO:
954+ case CCS_PATH1_PARENT_PERM:
955+ stat_index = CCS_PATH1_PARENT;
956+ break;
957+ case CCS_PATH2_PARENT_UID:
958+ case CCS_PATH2_PARENT_GID:
959+ case CCS_PATH2_PARENT_INO:
960+ case CCS_PATH2_PARENT_PERM:
961+ stat_index = CCS_PATH2_PARENT;
962+ break;
963+ default:
964+ goto out;
965+ }
966+ if (!obj->stat_valid[stat_index])
967+ goto out;
968+ stat = &obj->stat[stat_index];
969+ switch (index) {
970+ case CCS_PATH1_UID:
971+ case CCS_PATH2_UID:
972+ case CCS_PATH1_PARENT_UID:
973+ case CCS_PATH2_PARENT_UID:
974+ value = stat->uid;
975+ break;
976+ case CCS_PATH1_GID:
977+ case CCS_PATH2_GID:
978+ case CCS_PATH1_PARENT_GID:
979+ case CCS_PATH2_PARENT_GID:
980+ value = stat->gid;
981+ break;
982+ case CCS_PATH1_INO:
983+ case CCS_PATH2_INO:
984+ case CCS_PATH1_PARENT_INO:
985+ case CCS_PATH2_PARENT_INO:
986+ value = stat->ino;
987+ break;
988+ case CCS_PATH1_MAJOR:
989+ case CCS_PATH2_MAJOR:
990+ value = MAJOR(stat->dev);
991+ break;
992+ case CCS_PATH1_MINOR:
993+ case CCS_PATH2_MINOR:
994+ value = MINOR(stat->dev);
995+ break;
996+ case CCS_PATH1_TYPE:
997+ case CCS_PATH2_TYPE:
998+ value = stat->mode & S_IFMT;
999+ break;
1000+ case CCS_PATH1_DEV_MAJOR:
1001+ case CCS_PATH2_DEV_MAJOR:
1002+ value = MAJOR(stat->rdev);
1003+ break;
1004+ case CCS_PATH1_DEV_MINOR:
1005+ case CCS_PATH2_DEV_MINOR:
1006+ value = MINOR(stat->rdev);
1007+ break;
1008+ case CCS_PATH1_PERM:
1009+ case CCS_PATH2_PERM:
1010+ case CCS_PATH1_PARENT_PERM:
1011+ case CCS_PATH2_PARENT_PERM:
1012+ value = stat->mode & S_IALLUGO;
1013+ break;
1014+ }
1015+ }
1016+ break;
1017+ }
1018+ max_v[j] = value;
1019+ min_v[j] = value;
1020+ switch (index) {
1021+ case CCS_MODE_SETUID:
1022+ case CCS_MODE_SETGID:
1023+ case CCS_MODE_STICKY:
1024+ case CCS_MODE_OWNER_READ:
1025+ case CCS_MODE_OWNER_WRITE:
1026+ case CCS_MODE_OWNER_EXECUTE:
1027+ case CCS_MODE_GROUP_READ:
1028+ case CCS_MODE_GROUP_WRITE:
1029+ case CCS_MODE_GROUP_EXECUTE:
1030+ case CCS_MODE_OTHERS_READ:
1031+ case CCS_MODE_OTHERS_WRITE:
1032+ case CCS_MODE_OTHERS_EXECUTE:
1033+ is_bitop[j] = true;
1034+ }
1035+ }
1036+ if (left == CCS_NUMBER_UNION) {
1037+ /* Fetch values now. */
1038+ const struct ccs_number_union *ptr = numbers_p++;
1039+ min_v[0] = ptr->values[0];
1040+ max_v[0] = ptr->values[1];
1041+ }
1042+ if (right == CCS_NUMBER_UNION) {
1043+ /* Fetch values now. */
1044+ const struct ccs_number_union *ptr = numbers_p++;
1045+ if (ptr->is_group) {
1046+ if (ccs_number_matches_group(min_v[0],
1047+ max_v[0],
1048+ ptr->group)
1049+ == match)
1050+ continue;
1051+ } else {
1052+ if ((min_v[0] <= ptr->values[1] &&
1053+ max_v[0] >= ptr->values[0]) == match)
1054+ continue;
1055+ }
1056+ goto out;
1057+ }
1058+ /*
1059+ * Bit operation is valid only when counterpart value
1060+ * represents permission.
1061+ */
1062+ if (is_bitop[0] && is_bitop[1]) {
1063+ goto out;
1064+ } else if (is_bitop[0]) {
1065+ switch (right) {
1066+ case CCS_PATH1_PERM:
1067+ case CCS_PATH1_PARENT_PERM:
1068+ case CCS_PATH2_PERM:
1069+ case CCS_PATH2_PARENT_PERM:
1070+ if (!(max_v[0] & max_v[1]) == !match)
1071+ continue;
1072+ }
1073+ goto out;
1074+ } else if (is_bitop[1]) {
1075+ switch (left) {
1076+ case CCS_PATH1_PERM:
1077+ case CCS_PATH1_PARENT_PERM:
1078+ case CCS_PATH2_PERM:
1079+ case CCS_PATH2_PARENT_PERM:
1080+ if (!(max_v[0] & max_v[1]) == !match)
1081+ continue;
1082+ }
1083+ goto out;
1084+ }
1085+ /* Normal value range comparison. */
1086+ if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
1087+ continue;
1088+out:
1089+ return false;
1090+ }
1091+ /* Check argv[] and envp[] now. */
1092+ if (r->ee && (argc || envc))
1093+ return ccs_scan_bprm(r->ee, argc, argv, envc, envp);
1094+ return true;
1095+}
--- tags/patches/1.0.12/gc.c (nonexistent)
+++ tags/patches/1.0.12/gc.c (revision 197)
@@ -0,0 +1,1060 @@
1+/*
2+ * security/ccsecurity/gc.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
12+
13+#ifndef LIST_POISON2
14+#define LIST_POISON2 ((void *) 0x00200200)
15+#endif
16+
17+/**
18+ * list_del_rcu - Deletes entry from list without re-initialization.
19+ *
20+ * @entry: Pointer to "struct list_head".
21+ *
22+ * Returns nothing.
23+ *
24+ * This is for compatibility with older kernels.
25+ */
26+static inline void list_del_rcu(struct list_head *entry)
27+{
28+ __list_del(entry->prev, entry->next);
29+ entry->prev = LIST_POISON2;
30+}
31+
32+#endif
33+
34+#ifndef list_for_each_entry_safe
35+
36+/**
37+ * list_for_each_entry_safe - Iterate over list of given type safe against removal of list entry.
38+ *
39+ * @pos: The "type *" to use as a loop cursor.
40+ * @n: Another "type *" to use as temporary storage.
41+ * @head: Pointer to "struct list_head".
42+ * @member: The name of the list_struct within the struct.
43+ *
44+ * This is for compatibility with older kernels.
45+ */
46+#define list_for_each_entry_safe(pos, n, head, member) \
47+ for (pos = list_entry((head)->next, typeof(*pos), member), \
48+ n = list_entry(pos->member.next, typeof(*pos), member); \
49+ &pos->member != (head); \
50+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
51+
52+#endif
53+
54+/* Size of an element. */
55+static const u8 ccs_element_size[CCS_MAX_POLICY] = {
56+ [CCS_ID_RESERVEDPORT] = sizeof(struct ccs_reserved),
57+ [CCS_ID_GROUP] = sizeof(struct ccs_group),
58+ [CCS_ID_ADDRESS_GROUP] = sizeof(struct ccs_address_group),
59+ [CCS_ID_PATH_GROUP] = sizeof(struct ccs_path_group),
60+ [CCS_ID_NUMBER_GROUP] = sizeof(struct ccs_number_group),
61+ [CCS_ID_AGGREGATOR] = sizeof(struct ccs_aggregator),
62+ [CCS_ID_TRANSITION_CONTROL] = sizeof(struct ccs_transition_control),
63+ [CCS_ID_MANAGER] = sizeof(struct ccs_manager),
64+ [CCS_ID_IPV6_ADDRESS] = sizeof(struct ccs_ipv6addr),
65+ /* [CCS_ID_CONDITION] = "struct ccs_condition"->size, */
66+ /* [CCS_ID_NAME] = "struct ccs_name"->size, */
67+ /* [CCS_ID_ACL] = ccs_acl_size["struct ccs_acl_info"->type], */
68+ [CCS_ID_DOMAIN] = sizeof(struct ccs_domain_info),
69+};
70+
71+/* Size of a domain ACL element. */
72+static const u8 ccs_acl_size[] = {
73+ [CCS_TYPE_PATH_ACL] = sizeof(struct ccs_path_acl),
74+ [CCS_TYPE_PATH2_ACL] = sizeof(struct ccs_path2_acl),
75+ [CCS_TYPE_PATH_NUMBER_ACL] = sizeof(struct ccs_path_number_acl),
76+ [CCS_TYPE_MKDEV_ACL] = sizeof(struct ccs_mkdev_acl),
77+ [CCS_TYPE_MOUNT_ACL] = sizeof(struct ccs_mount_acl),
78+ [CCS_TYPE_INET_ACL] = sizeof(struct ccs_inet_acl),
79+ [CCS_TYPE_UNIX_ACL] = sizeof(struct ccs_unix_acl),
80+ [CCS_TYPE_ENV_ACL] = sizeof(struct ccs_env_acl),
81+ [CCS_TYPE_CAPABILITY_ACL] = sizeof(struct ccs_capability_acl),
82+ [CCS_TYPE_SIGNAL_ACL] = sizeof(struct ccs_signal_acl),
83+ [CCS_TYPE_AUTO_EXECUTE_HANDLER] = sizeof(struct ccs_handler_acl),
84+ [CCS_TYPE_DENIED_EXECUTE_HANDLER] = sizeof(struct ccs_handler_acl),
85+ [CCS_TYPE_AUTO_TASK_ACL] = sizeof(struct ccs_task_acl),
86+ [CCS_TYPE_MANUAL_TASK_ACL] = sizeof(struct ccs_task_acl),
87+};
88+
89+/* The list for "struct ccs_io_buffer". */
90+static LIST_HEAD(ccs_io_buffer_list);
91+/* Lock for protecting ccs_io_buffer_list. */
92+static DEFINE_SPINLOCK(ccs_io_buffer_list_lock);
93+
94+/**
95+ * ccs_struct_used_by_io_buffer - Check whether the list element is used by /proc/ccs/ users or not.
96+ *
97+ * @element: Pointer to "struct list_head".
98+ *
99+ * Returns true if @element is used by /proc/ccs/ users, false otherwise.
100+ */
101+static bool ccs_struct_used_by_io_buffer(const struct list_head *element)
102+{
103+ struct ccs_io_buffer *head;
104+ bool in_use = false;
105+ spin_lock(&ccs_io_buffer_list_lock);
106+ list_for_each_entry(head, &ccs_io_buffer_list, list) {
107+ head->users++;
108+ spin_unlock(&ccs_io_buffer_list_lock);
109+ if (mutex_lock_interruptible(&head->io_sem)) {
110+ in_use = true;
111+ goto out;
112+ }
113+ if (head->r.domain == element || head->r.group == element ||
114+ head->r.acl == element || &head->w.domain->list == element)
115+ in_use = true;
116+ mutex_unlock(&head->io_sem);
117+out:
118+ spin_lock(&ccs_io_buffer_list_lock);
119+ head->users--;
120+ if (in_use)
121+ break;
122+ }
123+ spin_unlock(&ccs_io_buffer_list_lock);
124+ return in_use;
125+}
126+
127+/**
128+ * ccs_name_used_by_io_buffer - Check whether the string is used by /proc/ccs/ users or not.
129+ *
130+ * @string: String to check.
131+ * @size: Memory allocated for @string .
132+ *
133+ * Returns true if @string is used by /proc/ccs/ users, false otherwise.
134+ */
135+static bool ccs_name_used_by_io_buffer(const char *string, const size_t size)
136+{
137+ struct ccs_io_buffer *head;
138+ bool in_use = false;
139+ spin_lock(&ccs_io_buffer_list_lock);
140+ list_for_each_entry(head, &ccs_io_buffer_list, list) {
141+ int i;
142+ head->users++;
143+ spin_unlock(&ccs_io_buffer_list_lock);
144+ if (mutex_lock_interruptible(&head->io_sem)) {
145+ in_use = true;
146+ goto out;
147+ }
148+ for (i = 0; i < CCS_MAX_IO_READ_QUEUE; i++) {
149+ const char *w = head->r.w[i];
150+ if (w < string || w > string + size)
151+ continue;
152+ in_use = true;
153+ break;
154+ }
155+ mutex_unlock(&head->io_sem);
156+out:
157+ spin_lock(&ccs_io_buffer_list_lock);
158+ head->users--;
159+ if (in_use)
160+ break;
161+ }
162+ spin_unlock(&ccs_io_buffer_list_lock);
163+ return in_use;
164+}
165+
166+/* Structure for garbage collection. */
167+struct ccs_gc {
168+ struct list_head list;
169+ enum ccs_policy_id type;
170+ size_t size;
171+ struct list_head *element;
172+};
173+/* List of entries to be deleted. */
174+static LIST_HEAD(ccs_gc_list);
175+/* Length of ccs_gc_list. */
176+static int ccs_gc_list_len;
177+
178+/**
179+ * ccs_add_to_gc - Add an entry to to be deleted list.
180+ *
181+ * @type: One of values in "enum ccs_policy_id".
182+ * @element: Pointer to "struct list_head".
183+ *
184+ * Returns true on success, false otherwise.
185+ *
186+ * Caller holds ccs_policy_lock mutex.
187+ *
188+ * Adding an entry needs kmalloc(). Thus, if we try to add thousands of
189+ * entries at once, it will take too long time. Thus, do not add more than 128
190+ * entries per a scan. But to be able to handle worst case where all entries
191+ * are in-use, we accept one more entry per a scan.
192+ *
193+ * If we use singly linked list using "struct list_head"->prev (which is
194+ * LIST_POISON2), we can avoid kmalloc().
195+ */
196+static bool ccs_add_to_gc(const enum ccs_policy_id type,
197+ struct list_head *element)
198+{
199+ struct ccs_gc *entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
200+ if (!entry)
201+ return false;
202+ entry->type = type;
203+ if (type == CCS_ID_ACL)
204+ entry->size =
205+ ccs_acl_size[container_of(element,
206+ typeof(struct ccs_acl_info),
207+ list)->type];
208+ else if (type == CCS_ID_NAME)
209+ entry->size =
210+ container_of(element, typeof(struct ccs_name),
211+ head.list)->size;
212+ else if (type == CCS_ID_CONDITION)
213+ entry->size =
214+ container_of(element, typeof(struct ccs_condition),
215+ head.list)->size;
216+ else
217+ entry->size = ccs_element_size[type];
218+ entry->element = element;
219+ list_add(&entry->list, &ccs_gc_list);
220+ list_del_rcu(element);
221+ return ccs_gc_list_len++ < 128;
222+}
223+
224+/**
225+ * ccs_element_linked_by_gc - Validate next element of an entry.
226+ *
227+ * @element: Pointer to an element.
228+ * @size: Size of @element in byte.
229+ *
230+ * Returns true if @element is linked by other elements in the garbage
231+ * collector's queue, false otherwise.
232+ */
233+static bool ccs_element_linked_by_gc(const u8 *element, const size_t size)
234+{
235+ struct ccs_gc *p;
236+ list_for_each_entry(p, &ccs_gc_list, list) {
237+ const u8 *ptr = (const u8 *) p->element->next;
238+ if (ptr < element || element + size < ptr)
239+ continue;
240+ return true;
241+ }
242+ return false;
243+}
244+
245+/**
246+ * ccs_del_transition_control - Delete members in "struct ccs_transition_control".
247+ *
248+ * @element: Pointer to "struct list_head".
249+ *
250+ * Returns nothing.
251+ */
252+static inline void ccs_del_transition_control(struct list_head *element)
253+{
254+ struct ccs_transition_control *ptr =
255+ container_of(element, typeof(*ptr), head.list);
256+ ccs_put_name(ptr->domainname);
257+ ccs_put_name(ptr->program);
258+}
259+
260+/**
261+ * ccs_del_aggregator - Delete members in "struct ccs_aggregator".
262+ *
263+ * @element: Pointer to "struct list_head".
264+ *
265+ * Returns nothing.
266+ */
267+static inline void ccs_del_aggregator(struct list_head *element)
268+{
269+ struct ccs_aggregator *ptr =
270+ container_of(element, typeof(*ptr), head.list);
271+ ccs_put_name(ptr->original_name);
272+ ccs_put_name(ptr->aggregated_name);
273+}
274+
275+/**
276+ * ccs_del_manager - Delete members in "struct ccs_manager".
277+ *
278+ * @element: Pointer to "struct list_head".
279+ *
280+ * Returns nothing.
281+ */
282+static inline void ccs_del_manager(struct list_head *element)
283+{
284+ struct ccs_manager *ptr =
285+ container_of(element, typeof(*ptr), head.list);
286+ ccs_put_name(ptr->manager);
287+}
288+
289+/* For compatibility with older kernels. */
290+#ifndef for_each_process
291+#define for_each_process for_each_task
292+#endif
293+
294+/**
295+ * ccs_domain_used_by_task - Check whether the given pointer is referenced by a task.
296+ *
297+ * @domain: Pointer to "struct ccs_domain_info".
298+ *
299+ * Returns true if @domain is in use, false otherwise.
300+ */
301+static bool ccs_domain_used_by_task(struct ccs_domain_info *domain)
302+{
303+ bool in_use = false;
304+ /*
305+ * Don't delete this domain if somebody is doing execve().
306+ *
307+ * Since ccs_finish_execve() first reverts ccs_domain_info and then
308+ * updates ccs_flags, we need smp_rmb() to make sure that GC first
309+ * checks ccs_flags and then checks ccs_domain_info.
310+ */
311+#ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
312+ int idx;
313+ rcu_read_lock();
314+ for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
315+ struct ccs_security *ptr;
316+ struct list_head *list = &ccs_task_security_list[idx];
317+ list_for_each_entry_rcu(ptr, list, list) {
318+ if (!(ptr->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
319+ smp_rmb(); /* Avoid out of order execution. */
320+ if (ptr->ccs_domain_info != domain)
321+ continue;
322+ }
323+ in_use = true;
324+ goto out;
325+ }
326+ }
327+ in_use = ccs_used_by_cred(domain);
328+out:
329+ rcu_read_unlock();
330+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
331+ struct task_struct *g;
332+ struct task_struct *t;
333+ ccs_tasklist_lock();
334+ do_each_thread(g, t) {
335+ if (!(t->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
336+ smp_rmb(); /* Avoid out of order execution. */
337+ if (t->ccs_domain_info != domain)
338+ continue;
339+ }
340+ in_use = true;
341+ goto out;
342+ } while_each_thread(g, t);
343+out:
344+ ccs_tasklist_unlock();
345+#else
346+ struct task_struct *p;
347+ ccs_tasklist_lock();
348+ for_each_process(p) {
349+ if (!(p->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
350+ smp_rmb(); /* Avoid out of order execution. */
351+ if (p->ccs_domain_info != domain)
352+ continue;
353+ }
354+ in_use = true;
355+ break;
356+ }
357+ ccs_tasklist_unlock();
358+#endif
359+ return in_use;
360+}
361+
362+/**
363+ * ccs_del_acl - Delete members in "struct ccs_acl_info".
364+ *
365+ * @element: Pointer to "struct list_head".
366+ *
367+ * Returns nothing.
368+ */
369+static void ccs_del_acl(struct list_head *element)
370+{
371+ struct ccs_acl_info *acl = container_of(element, typeof(*acl), list);
372+ ccs_put_condition(acl->cond);
373+ switch (acl->type) {
374+ case CCS_TYPE_PATH_ACL:
375+ {
376+ struct ccs_path_acl *entry =
377+ container_of(acl, typeof(*entry), head);
378+ ccs_put_name_union(&entry->name);
379+ }
380+ break;
381+ case CCS_TYPE_PATH2_ACL:
382+ {
383+ struct ccs_path2_acl *entry =
384+ container_of(acl, typeof(*entry), head);
385+ ccs_put_name_union(&entry->name1);
386+ ccs_put_name_union(&entry->name2);
387+ }
388+ break;
389+ case CCS_TYPE_PATH_NUMBER_ACL:
390+ {
391+ struct ccs_path_number_acl *entry =
392+ container_of(acl, typeof(*entry), head);
393+ ccs_put_name_union(&entry->name);
394+ ccs_put_number_union(&entry->number);
395+ }
396+ break;
397+ case CCS_TYPE_MKDEV_ACL:
398+ {
399+ struct ccs_mkdev_acl *entry =
400+ container_of(acl, typeof(*entry), head);
401+ ccs_put_name_union(&entry->name);
402+ ccs_put_number_union(&entry->mode);
403+ ccs_put_number_union(&entry->major);
404+ ccs_put_number_union(&entry->minor);
405+ }
406+ break;
407+ case CCS_TYPE_MOUNT_ACL:
408+ {
409+ struct ccs_mount_acl *entry =
410+ container_of(acl, typeof(*entry), head);
411+ ccs_put_name_union(&entry->dev_name);
412+ ccs_put_name_union(&entry->dir_name);
413+ ccs_put_name_union(&entry->fs_type);
414+ ccs_put_number_union(&entry->flags);
415+ }
416+ break;
417+ case CCS_TYPE_INET_ACL:
418+ {
419+ struct ccs_inet_acl *entry =
420+ container_of(acl, typeof(*entry), head);
421+ switch (entry->address_type) {
422+ case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
423+ ccs_put_group(entry->address.group);
424+ break;
425+ case CCS_IP_ADDRESS_TYPE_IPv6:
426+ ccs_put_ipv6_address(entry->address.ipv6.min);
427+ ccs_put_ipv6_address(entry->address.ipv6.max);
428+ break;
429+ }
430+ ccs_put_number_union(&entry->port);
431+ }
432+ break;
433+ case CCS_TYPE_UNIX_ACL:
434+ {
435+ struct ccs_unix_acl *entry =
436+ container_of(acl, typeof(*entry), head);
437+ ccs_put_name_union(&entry->name);
438+ }
439+ break;
440+ case CCS_TYPE_ENV_ACL:
441+ {
442+ struct ccs_env_acl *entry =
443+ container_of(acl, typeof(*entry), head);
444+ ccs_put_name(entry->env);
445+ }
446+ break;
447+ case CCS_TYPE_CAPABILITY_ACL:
448+ {
449+ /* Nothing to do. */
450+ }
451+ break;
452+ case CCS_TYPE_SIGNAL_ACL:
453+ {
454+ struct ccs_signal_acl *entry =
455+ container_of(acl, typeof(*entry), head);
456+ ccs_put_name(entry->domainname);
457+ }
458+ break;
459+ case CCS_TYPE_AUTO_EXECUTE_HANDLER:
460+ case CCS_TYPE_DENIED_EXECUTE_HANDLER:
461+ {
462+ struct ccs_handler_acl *entry =
463+ container_of(acl, typeof(*entry), head);
464+ ccs_put_name(entry->handler);
465+ }
466+ break;
467+ case CCS_TYPE_AUTO_TASK_ACL:
468+ case CCS_TYPE_MANUAL_TASK_ACL:
469+ {
470+ struct ccs_task_acl *entry =
471+ container_of(acl, typeof(*entry), head);
472+ ccs_put_name(entry->domainname);
473+ }
474+ break;
475+ }
476+}
477+
478+/**
479+ * ccs_del_domain - Delete members in "struct ccs_domain_info".
480+ *
481+ * @element: Pointer to "struct list_head".
482+ *
483+ * Returns nothing.
484+ */
485+static inline void ccs_del_domain(struct list_head *element)
486+{
487+ struct ccs_domain_info *domain =
488+ container_of(element, typeof(*domain), list);
489+ struct ccs_acl_info *acl;
490+ struct ccs_acl_info *tmp;
491+ u8 i;
492+ /*
493+ * Since this domain is referenced from none of "struct ccs_io_buffer"
494+ * ccs_gc_list, "struct task_struct", we can delete elements without
495+ * checking for is_deleted flag.
496+ */
497+ for (i = 0; i < 2; i++) {
498+ list_for_each_entry_safe(acl, tmp, &domain->acl_info_list[i],
499+ list) {
500+ ccs_del_acl(&acl->list);
501+ ccs_memory_free(acl, ccs_acl_size[acl->type]);
502+ }
503+ }
504+ ccs_put_name(domain->domainname);
505+}
506+
507+/**
508+ * ccs_del_path_group - Delete members in "struct ccs_path_group".
509+ *
510+ * @element: Pointer to "struct list_head".
511+ *
512+ * Returns nothing.
513+ */
514+static inline void ccs_del_path_group(struct list_head *element)
515+{
516+ struct ccs_path_group *member =
517+ container_of(element, typeof(*member), head.list);
518+ ccs_put_name(member->member_name);
519+}
520+
521+/**
522+ * ccs_del_group - Delete "struct ccs_group".
523+ *
524+ * @element: Pointer to "struct list_head".
525+ *
526+ * Returns nothing.
527+ */
528+static inline void ccs_del_group(struct list_head *element)
529+{
530+ struct ccs_group *group =
531+ container_of(element, typeof(*group), head.list);
532+ ccs_put_name(group->group_name);
533+}
534+
535+/**
536+ * ccs_del_address_group - Delete members in "struct ccs_address_group".
537+ *
538+ * @element: Pointer to "struct list_head".
539+ *
540+ * Returns nothing.
541+ */
542+static inline void ccs_del_address_group(struct list_head *element)
543+{
544+ struct ccs_address_group *member =
545+ container_of(element, typeof(*member), head.list);
546+ if (member->is_ipv6) {
547+ ccs_put_ipv6_address(member->min.ipv6);
548+ ccs_put_ipv6_address(member->max.ipv6);
549+ }
550+}
551+
552+/**
553+ * ccs_del_number_group - Delete members in "struct ccs_number_group".
554+ *
555+ * @element: Pointer to "struct list_head".
556+ *
557+ * Returns nothing.
558+ */
559+static inline void ccs_del_number_group(struct list_head *element)
560+{
561+ /* Nothing to do. */
562+}
563+
564+/**
565+ * ccs_del_reservedport - Delete members in "struct ccs_reserved".
566+ *
567+ * @element: Pointer to "struct list_head".
568+ *
569+ * Returns nothing.
570+ */
571+static inline void ccs_del_reservedport(struct list_head *element)
572+{
573+ /* Nothing to do. */
574+}
575+
576+/**
577+ * ccs_del_ipv6_address - Delete members in "struct ccs_ipv6addr".
578+ *
579+ * @element: Pointer to "struct list_head".
580+ *
581+ * Returns nothing.
582+ */
583+static inline void ccs_del_ipv6_address(struct list_head *element)
584+{
585+ /* Nothing to do. */
586+}
587+
588+/**
589+ * ccs_del_condition - Delete members in "struct ccs_condition".
590+ *
591+ * @element: Pointer to "struct list_head".
592+ *
593+ * Returns nothing.
594+ */
595+void ccs_del_condition(struct list_head *element)
596+{
597+ struct ccs_condition *cond = container_of(element, typeof(*cond),
598+ head.list);
599+ const u16 condc = cond->condc;
600+ const u16 numbers_count = cond->numbers_count;
601+ const u16 names_count = cond->names_count;
602+ const u16 argc = cond->argc;
603+ const u16 envc = cond->envc;
604+ unsigned int i;
605+ const struct ccs_condition_element *condp
606+ = (const struct ccs_condition_element *) (cond + 1);
607+ struct ccs_number_union *numbers_p
608+ = (struct ccs_number_union *) (condp + condc);
609+ struct ccs_name_union *names_p
610+ = (struct ccs_name_union *) (numbers_p + numbers_count);
611+ const struct ccs_argv *argv
612+ = (const struct ccs_argv *) (names_p + names_count);
613+ const struct ccs_envp *envp
614+ = (const struct ccs_envp *) (argv + argc);
615+ for (i = 0; i < numbers_count; i++)
616+ ccs_put_number_union(numbers_p++);
617+ for (i = 0; i < names_count; i++)
618+ ccs_put_name_union(names_p++);
619+ for (i = 0; i < argc; argv++, i++)
620+ ccs_put_name(argv->value);
621+ for (i = 0; i < envc; envp++, i++) {
622+ ccs_put_name(envp->name);
623+ ccs_put_name(envp->value);
624+ }
625+ ccs_put_name(cond->transit);
626+}
627+
628+/**
629+ * ccs_del_name - Delete members in "struct ccs_name".
630+ *
631+ * @element: Pointer to "struct list_head".
632+ *
633+ * Returns nothing.
634+ */
635+static inline void ccs_del_name(struct list_head *element)
636+{
637+ /* Nothing to do. */
638+}
639+
640+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
641+
642+/*
643+ * Lock for syscall users.
644+ *
645+ * This lock is held for only protecting single SRCU section.
646+ */
647+struct srcu_struct ccs_ss;
648+
649+#else
650+
651+/*
652+ * Lock for syscall users.
653+ *
654+ * This lock is used for protecting single SRCU section for 2.6.18 and
655+ * earlier kernels because they don't have SRCU support.
656+ */
657+static struct {
658+ int counter_idx; /* Currently active index (0 or 1). */
659+ int counter[2]; /* Current users. Protected by ccs_counter_lock. */
660+} ccs_counter;
661+/* Lock for protecting ccs_counter. */
662+static DEFINE_SPINLOCK(ccs_counter_lock);
663+
664+/**
665+ * ccs_lock - Alternative for srcu_read_lock().
666+ *
667+ * Returns index number which has to be passed to ccs_unlock().
668+ */
669+int ccs_lock(void)
670+{
671+ int idx;
672+ spin_lock(&ccs_counter_lock);
673+ idx = ccs_counter.counter_idx;
674+ ccs_counter.counter[idx]++;
675+ spin_unlock(&ccs_counter_lock);
676+ return idx;
677+}
678+
679+/**
680+ * ccs_unlock - Alternative for srcu_read_unlock().
681+ *
682+ * @idx: Index number returned by ccs_lock().
683+ *
684+ * Returns nothing.
685+ */
686+void ccs_unlock(const int idx)
687+{
688+ spin_lock(&ccs_counter_lock);
689+ ccs_counter.counter[idx]--;
690+ spin_unlock(&ccs_counter_lock);
691+}
692+
693+/**
694+ * ccs_synchronize_counter - Alternative for synchronize_srcu().
695+ *
696+ * Returns nothing.
697+ */
698+static void ccs_synchronize_counter(void)
699+{
700+ int idx;
701+ int v;
702+ /*
703+ * Change currently active counter's index. Make it visible to other
704+ * threads by doing it with ccs_counter_lock held.
705+ * This function is called by garbage collector thread, and the garbage
706+ * collector thread is exclusive. Therefore, it is guaranteed that
707+ * SRCU grace period has expired when returning from this function.
708+ */
709+ spin_lock(&ccs_counter_lock);
710+ idx = ccs_counter.counter_idx;
711+ ccs_counter.counter_idx ^= 1;
712+ v = ccs_counter.counter[idx];
713+ spin_unlock(&ccs_counter_lock);
714+ /* Wait for previously active counter to become 0. */
715+ while (v) {
716+ ssleep(1);
717+ spin_lock(&ccs_counter_lock);
718+ v = ccs_counter.counter[idx];
719+ spin_unlock(&ccs_counter_lock);
720+ }
721+}
722+
723+#endif
724+
725+/**
726+ * ccs_collect_member - Delete elements with "struct ccs_acl_head".
727+ *
728+ * @id: One of values in "enum ccs_policy_id".
729+ * @member_list: Pointer to "struct list_head".
730+ *
731+ * Returns true if some elements are deleted, false otherwise.
732+ */
733+static bool ccs_collect_member(const enum ccs_policy_id id,
734+ struct list_head *member_list)
735+{
736+ struct ccs_acl_head *member;
737+ list_for_each_entry(member, member_list, list) {
738+ if (!member->is_deleted)
739+ continue;
740+ if (!ccs_add_to_gc(id, &member->list))
741+ return false;
742+ }
743+ return true;
744+}
745+
746+/**
747+ * ccs_collect_acl - Delete elements in "struct ccs_domain_info".
748+ *
749+ * @domain: Pointer to "struct ccs_domain_info".
750+ *
751+ * Returns true if some elements are deleted, false otherwise.
752+ */
753+static bool ccs_collect_acl(struct ccs_domain_info *domain)
754+{
755+ struct ccs_acl_info *acl;
756+ u8 i;
757+ for (i = 0; i < 2; i++) {
758+ list_for_each_entry(acl, &domain->acl_info_list[i], list) {
759+ if (!acl->is_deleted)
760+ continue;
761+ if (!ccs_add_to_gc(CCS_ID_ACL, &acl->list))
762+ return false;
763+ }
764+ }
765+ return true;
766+}
767+
768+/**
769+ * ccs_collect_entry - Scan lists for deleted elements.
770+ *
771+ * Returns nothing.
772+ */
773+static void ccs_collect_entry(void)
774+{
775+ int i;
776+ enum ccs_policy_id id;
777+ int idx;
778+ if (mutex_lock_interruptible(&ccs_policy_lock))
779+ return;
780+ idx = ccs_read_lock();
781+ for (id = 0; id < CCS_MAX_POLICY; id++)
782+ if (!ccs_collect_member(id, &ccs_policy_list[id]))
783+ goto unlock;
784+ for (i = 0; i < CCS_MAX_ACL_GROUPS; i++)
785+ if (!ccs_collect_acl(&ccs_acl_group[i]))
786+ goto unlock;
787+ {
788+ struct ccs_domain_info *domain;
789+ list_for_each_entry(domain, &ccs_domain_list, list) {
790+ if (!ccs_collect_acl(domain))
791+ goto unlock;
792+ if (!domain->is_deleted ||
793+ ccs_domain_used_by_task(domain))
794+ continue;
795+ if (!ccs_add_to_gc(CCS_ID_DOMAIN, &domain->list))
796+ goto unlock;
797+ }
798+ }
799+ for (i = 0; i < CCS_MAX_GROUP; i++) {
800+ struct list_head *list = &ccs_group_list[i];
801+ struct ccs_group *group;
802+ switch (i) {
803+ case 0:
804+ id = CCS_ID_PATH_GROUP;
805+ break;
806+ case 1:
807+ id = CCS_ID_NUMBER_GROUP;
808+ break;
809+ default:
810+ id = CCS_ID_ADDRESS_GROUP;
811+ break;
812+ }
813+ list_for_each_entry(group, list, head.list) {
814+ if (!ccs_collect_member(id, &group->member_list))
815+ goto unlock;
816+ if (!list_empty(&group->member_list) ||
817+ atomic_read(&group->head.users))
818+ continue;
819+ if (!ccs_add_to_gc(CCS_ID_GROUP, &group->head.list))
820+ goto unlock;
821+ }
822+ }
823+ for (i = 0; i < CCS_MAX_LIST + CCS_MAX_HASH; i++) {
824+ struct list_head *list = i < CCS_MAX_LIST ?
825+ &ccs_shared_list[i] : &ccs_name_list[i - CCS_MAX_LIST];
826+ struct ccs_shared_acl_head *ptr;
827+ switch (i) {
828+ case 0:
829+ id = CCS_ID_CONDITION;
830+ break;
831+ case 1:
832+ id = CCS_ID_IPV6_ADDRESS;
833+ break;
834+ default:
835+ id = CCS_ID_NAME;
836+ break;
837+ }
838+ list_for_each_entry(ptr, list, list) {
839+ if (atomic_read(&ptr->users))
840+ continue;
841+ if (!ccs_add_to_gc(id, &ptr->list))
842+ goto unlock;
843+ }
844+ }
845+unlock:
846+ ccs_read_unlock(idx);
847+ mutex_unlock(&ccs_policy_lock);
848+}
849+
850+/**
851+ * ccs_kfree_entry - Delete entries in ccs_gc_list.
852+ *
853+ * Returns true if some entries were kfree()d, false otherwise.
854+ */
855+static bool ccs_kfree_entry(void)
856+{
857+ struct ccs_gc *p;
858+ struct ccs_gc *tmp;
859+ bool result = false;
860+ list_for_each_entry_safe(p, tmp, &ccs_gc_list, list) {
861+ struct list_head * const element = p->element;
862+ /*
863+ * list_del_rcu() in ccs_add_to_gc() guarantees that the list
864+ * element became no longer reachable from the list which the
865+ * element was originally on (e.g. ccs_domain_list). Also,
866+ * synchronize_srcu() in ccs_gc_thread() guarantees that the
867+ * list element became no longer referenced by syscall users.
868+ *
869+ * However, there are three users which may still be using the
870+ * list element. We need to defer until all of these users
871+ * forget the list element.
872+ *
873+ * Firstly, defer until "struct ccs_io_buffer"->r.{domain,
874+ * group,acl} and "struct ccs_io_buffer"->w.domain forget the
875+ * list element.
876+ */
877+ if (ccs_struct_used_by_io_buffer(element))
878+ continue;
879+ /*
880+ * Secondly, defer until all other elements in the ccs_gc_list
881+ * list forget the list element.
882+ */
883+ if (ccs_element_linked_by_gc((const u8 *) element, p->size))
884+ continue;
885+ switch (p->type) {
886+ case CCS_ID_TRANSITION_CONTROL:
887+ ccs_del_transition_control(element);
888+ break;
889+ case CCS_ID_MANAGER:
890+ ccs_del_manager(element);
891+ break;
892+ case CCS_ID_AGGREGATOR:
893+ ccs_del_aggregator(element);
894+ break;
895+ case CCS_ID_GROUP:
896+ ccs_del_group(element);
897+ break;
898+ case CCS_ID_PATH_GROUP:
899+ ccs_del_path_group(element);
900+ break;
901+ case CCS_ID_ADDRESS_GROUP:
902+ ccs_del_address_group(element);
903+ break;
904+ case CCS_ID_NUMBER_GROUP:
905+ ccs_del_number_group(element);
906+ break;
907+ case CCS_ID_RESERVEDPORT:
908+ ccs_del_reservedport(element);
909+ break;
910+ case CCS_ID_IPV6_ADDRESS:
911+ ccs_del_ipv6_address(element);
912+ break;
913+ case CCS_ID_CONDITION:
914+ ccs_del_condition(element);
915+ break;
916+ case CCS_ID_NAME:
917+ /*
918+ * Thirdly, defer until all "struct ccs_io_buffer"
919+ * ->r.w[] forget the list element.
920+ */
921+ if (ccs_name_used_by_io_buffer(
922+ container_of(element, typeof(struct ccs_name),
923+ head.list)->entry.name, p->size))
924+ continue;
925+ ccs_del_name(element);
926+ break;
927+ case CCS_ID_ACL:
928+ ccs_del_acl(element);
929+ break;
930+ case CCS_ID_DOMAIN:
931+ /*
932+ * Thirdly, defer until all "struct task_struct" forget
933+ * the list element.
934+ */
935+ if (ccs_domain_used_by_task(
936+ container_of(element,
937+ typeof(struct ccs_domain_info),
938+ list)))
939+ continue;
940+ ccs_del_domain(element);
941+ break;
942+ case CCS_MAX_POLICY:
943+ break;
944+ }
945+ ccs_memory_free(element, p->size);
946+ list_del(&p->list);
947+ kfree(p);
948+ ccs_gc_list_len--;
949+ result = true;
950+ }
951+ return result;
952+}
953+
954+/**
955+ * ccs_gc_thread - Garbage collector thread function.
956+ *
957+ * @unused: Unused.
958+ *
959+ * In case OOM-killer choose this thread for termination, we create this thread
960+ * as a short live thread whenever /proc/ccs/ interface was close()d.
961+ *
962+ * Returns 0.
963+ */
964+static int ccs_gc_thread(void *unused)
965+{
966+ /* Garbage collector thread is exclusive. */
967+ static DEFINE_MUTEX(ccs_gc_mutex);
968+ if (!mutex_trylock(&ccs_gc_mutex))
969+ goto out;
970+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
971+ daemonize("GC for CCS");
972+#else
973+ daemonize();
974+ reparent_to_init();
975+#if defined(TASK_DEAD)
976+ {
977+ struct task_struct *task = current;
978+ spin_lock_irq(&task->sighand->siglock);
979+ siginitsetinv(&task->blocked, 0);
980+ recalc_sigpending();
981+ spin_unlock_irq(&task->sighand->siglock);
982+ }
983+#else
984+ {
985+ struct task_struct *task = current;
986+ spin_lock_irq(&task->sigmask_lock);
987+ siginitsetinv(&task->blocked, 0);
988+ recalc_sigpending(task);
989+ spin_unlock_irq(&task->sigmask_lock);
990+ }
991+#endif
992+ snprintf(current->comm, sizeof(current->comm) - 1, "GC for CCS");
993+#endif
994+ do {
995+ ccs_collect_entry();
996+ if (list_empty(&ccs_gc_list))
997+ break;
998+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
999+ synchronize_srcu(&ccs_ss);
1000+#else
1001+ ccs_synchronize_counter();
1002+#endif
1003+ } while (ccs_kfree_entry());
1004+ {
1005+ struct ccs_io_buffer *head;
1006+ struct ccs_io_buffer *tmp;
1007+ spin_lock(&ccs_io_buffer_list_lock);
1008+ list_for_each_entry_safe(head, tmp, &ccs_io_buffer_list,
1009+ list) {
1010+ if (head->users)
1011+ continue;
1012+ list_del(&head->list);
1013+ kfree(head->read_buf);
1014+ kfree(head->write_buf);
1015+ kfree(head);
1016+ }
1017+ spin_unlock(&ccs_io_buffer_list_lock);
1018+ }
1019+ mutex_unlock(&ccs_gc_mutex);
1020+out:
1021+ /* This acts as do_exit(0). */
1022+ return 0;
1023+}
1024+
1025+/**
1026+ * ccs_notify_gc - Register/unregister /proc/ccs/ users.
1027+ *
1028+ * @head: Pointer to "struct ccs_io_buffer".
1029+ * @is_register: True if register, false if unregister.
1030+ *
1031+ * Returns nothing.
1032+ */
1033+void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register)
1034+{
1035+ bool is_write = false;
1036+ spin_lock(&ccs_io_buffer_list_lock);
1037+ if (is_register) {
1038+ head->users = 1;
1039+ list_add(&head->list, &ccs_io_buffer_list);
1040+ } else {
1041+ is_write = head->write_buf != NULL;
1042+ if (!--head->users) {
1043+ list_del(&head->list);
1044+ kfree(head->read_buf);
1045+ kfree(head->write_buf);
1046+ kfree(head);
1047+ }
1048+ }
1049+ spin_unlock(&ccs_io_buffer_list_lock);
1050+ if (is_write) {
1051+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 6)
1052+ struct task_struct *task = kthread_create(ccs_gc_thread, NULL,
1053+ "GC for CCS");
1054+ if (!IS_ERR(task))
1055+ wake_up_process(task);
1056+#else
1057+ kernel_thread(ccs_gc_thread, NULL, 0);
1058+#endif
1059+ }
1060+}
--- tags/patches/1.0.12/network.c (nonexistent)
+++ tags/patches/1.0.12/network.c (revision 197)
@@ -0,0 +1,1150 @@
1+/*
2+ * security/ccsecurity/network.c
3+ *
4+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
5+ *
6+ * Version: 1.8.1 2011/04/01
7+ */
8+
9+#include "internal.h"
10+
11+/* Structure for holding inet domain socket's address. */
12+struct ccs_inet_addr_info {
13+ u16 port; /* In network byte order. */
14+ const u32 *address; /* In network byte order. */
15+ bool is_ipv6;
16+};
17+
18+/* Structure for holding unix domain socket's address. */
19+struct ccs_unix_addr_info {
20+ u8 *addr; /* This may not be '\0' terminated string. */
21+ unsigned int addr_len;
22+};
23+
24+/* Structure for holding socket address. */
25+struct ccs_addr_info {
26+ u8 protocol;
27+ u8 operation;
28+ struct ccs_inet_addr_info inet;
29+ struct ccs_unix_addr_info unix0;
30+};
31+
32+/* String table for socket's protocols. */
33+const char * const ccs_proto_keyword[CCS_SOCK_MAX] = {
34+ [SOCK_STREAM] = "stream",
35+ [SOCK_DGRAM] = "dgram",
36+ [SOCK_RAW] = "raw",
37+ [SOCK_SEQPACKET] = "seqpacket",
38+ [0] = " ", /* Dummy for avoiding NULL pointer dereference. */
39+ [4] = " ", /* Dummy for avoiding NULL pointer dereference. */
40+};
41+
42+/* String table for socket's operation. */
43+const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = {
44+ [CCS_NETWORK_BIND] = "bind",
45+ [CCS_NETWORK_LISTEN] = "listen",
46+ [CCS_NETWORK_CONNECT] = "connect",
47+ [CCS_NETWORK_ACCEPT] = "accept",
48+ [CCS_NETWORK_SEND] = "send",
49+ [CCS_NETWORK_RECV] = "recv",
50+};
51+
52+/**
53+ * ccs_parse_ip_address - Parse an IP address.
54+ *
55+ * @address: String to parse.
56+ * @min: Pointer to store min address.
57+ * @max: Pointer to store max address.
58+ *
59+ * Returns CCS_IP_ADDRESS_TYPE_IPv6 if @address is an IPv6,
60+ * CCS_IP_ADDRESS_TYPE_IPv4 if @address is an IPv4,
61+ * CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP otherwise.
62+ */
63+int ccs_parse_ip_address(char *address, u16 *min, u16 *max)
64+{
65+ int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"
66+ "-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
67+ &min[0], &min[1], &min[2], &min[3],
68+ &min[4], &min[5], &min[6], &min[7],
69+ &max[0], &max[1], &max[2], &max[3],
70+ &max[4], &max[5], &max[6], &max[7]);
71+ if (count == 8 || count == 16) {
72+ u8 i;
73+ if (count == 8)
74+ memmove(max, min, sizeof(u16) * 8);
75+ for (i = 0; i < 8; i++) {
76+ min[i] = htons(min[i]);
77+ max[i] = htons(max[i]);
78+ }
79+ return CCS_IP_ADDRESS_TYPE_IPv6;
80+ }
81+ count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
82+ &min[0], &min[1], &min[2], &min[3],
83+ &max[0], &max[1], &max[2], &max[3]);
84+ if (count == 4 || count == 8) {
85+ u32 ip = htonl((((u8) min[0]) << 24) + (((u8) min[1]) << 16)
86+ + (((u8) min[2]) << 8) + (u8) min[3]);
87+ memmove(min, &ip, sizeof(ip));
88+ if (count == 8)
89+ ip = htonl((((u8) max[0]) << 24)
90+ + (((u8) max[1]) << 16)
91+ + (((u8) max[2]) << 8) + (u8) max[3]);
92+ memmove(max, &ip, sizeof(ip));
93+ return CCS_IP_ADDRESS_TYPE_IPv4;
94+ }
95+ return CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
96+}
97+
98+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
99+#if defined(__LITTLE_ENDIAN)
100+#define HIPQUAD(addr) \
101+ ((unsigned char *)&addr)[3], \
102+ ((unsigned char *)&addr)[2], \
103+ ((unsigned char *)&addr)[1], \
104+ ((unsigned char *)&addr)[0]
105+#elif defined(__BIG_ENDIAN)
106+#define HIPQUAD(addr) \
107+ ((unsigned char *)&addr)[0], \
108+ ((unsigned char *)&addr)[1], \
109+ ((unsigned char *)&addr)[2], \
110+ ((unsigned char *)&addr)[3]
111+#else
112+#error "Please fix asm/byteorder.h"
113+#endif /* __LITTLE_ENDIAN */
114+#endif
115+
116+/**
117+ * ccs_print_ipv4 - Print an IPv4 address.
118+ *
119+ * @buffer: Buffer to write to.
120+ * @buffer_len: Size of @buffer.
121+ * @min_ip: Min address in host byte order.
122+ * @max_ip: Max address in host byte order.
123+ *
124+ * Returns nothing.
125+ */
126+void ccs_print_ipv4(char *buffer, const int buffer_len,
127+ const u32 min_ip, const u32 max_ip)
128+{
129+ memset(buffer, 0, buffer_len);
130+ snprintf(buffer, buffer_len - 1, "%u.%u.%u.%u%c%u.%u.%u.%u",
131+ HIPQUAD(min_ip), min_ip == max_ip ? '\0' : '-',
132+ HIPQUAD(max_ip));
133+}
134+
135+#if !defined(NIP6)
136+
137+#define NIP6(addr) \
138+ ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), \
139+ ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \
140+ ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \
141+ ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7])
142+
143+#endif
144+
145+/**
146+ * ccs_print_ipv6 - Print an IPv6 address.
147+ *
148+ * @buffer: Buffer to write to.
149+ * @buffer_len: Size of @buffer.
150+ * @min_ip: Pointer to "struct in6_addr".
151+ * @max_ip: Pointer to "struct in6_addr".
152+ *
153+ * Returns nothing.
154+ */
155+void ccs_print_ipv6(char *buffer, const int buffer_len,
156+ const struct in6_addr *min_ip,
157+ const struct in6_addr *max_ip)
158+{
159+ memset(buffer, 0, buffer_len);
160+ snprintf(buffer, buffer_len - 1,
161+ "%x:%x:%x:%x:%x:%x:%x:%x%c%x:%x:%x:%x:%x:%x:%x:%x",
162+ NIP6(*min_ip), min_ip == max_ip ? '\0' : '-',
163+ NIP6(*max_ip));
164+}
165+
166+/*
167+ * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
168+ * inet domain socket.
169+ */
170+static const u8 ccs_inet2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
171+ [SOCK_STREAM] = {
172+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_STREAM_BIND,
173+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_INET_STREAM_LISTEN,
174+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_INET_STREAM_CONNECT,
175+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_INET_STREAM_ACCEPT,
176+ },
177+ [SOCK_DGRAM] = {
178+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_DGRAM_BIND,
179+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_INET_DGRAM_SEND,
180+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_INET_DGRAM_RECV,
181+ },
182+ [SOCK_RAW] = {
183+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_INET_RAW_BIND,
184+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_INET_RAW_SEND,
185+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_INET_RAW_RECV,
186+ },
187+};
188+
189+/*
190+ * Mapping table from "enum ccs_network_acl_index" to "enum ccs_mac_index" for
191+ * unix domain socket.
192+ */
193+static const u8 ccs_unix2mac[CCS_SOCK_MAX][CCS_MAX_NETWORK_OPERATION] = {
194+ [SOCK_STREAM] = {
195+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_STREAM_BIND,
196+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_UNIX_STREAM_LISTEN,
197+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_STREAM_CONNECT,
198+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT,
199+ },
200+ [SOCK_DGRAM] = {
201+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_DGRAM_BIND,
202+ [CCS_NETWORK_SEND] = CCS_MAC_NETWORK_UNIX_DGRAM_SEND,
203+ [CCS_NETWORK_RECV] = CCS_MAC_NETWORK_UNIX_DGRAM_RECV,
204+ },
205+ [SOCK_SEQPACKET] = {
206+ [CCS_NETWORK_BIND] = CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND,
207+ [CCS_NETWORK_LISTEN] = CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
208+ [CCS_NETWORK_CONNECT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
209+ [CCS_NETWORK_ACCEPT] = CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT,
210+ },
211+};
212+
213+/**
214+ * ccs_same_inet_acl - Check for duplicated "struct ccs_inet_acl" entry.
215+ *
216+ * @a: Pointer to "struct ccs_acl_info".
217+ * @b: Pointer to "struct ccs_acl_info".
218+ *
219+ * Returns true if @a == @b except permission bits, false otherwise.
220+ */
221+static bool ccs_same_inet_acl(const struct ccs_acl_info *a,
222+ const struct ccs_acl_info *b)
223+{
224+ const struct ccs_inet_acl *p1 = container_of(a, typeof(*p1), head);
225+ const struct ccs_inet_acl *p2 = container_of(b, typeof(*p2), head);
226+ return p1->protocol == p2->protocol &&
227+ p1->address_type == p2->address_type &&
228+ p1->address.ipv4.min == p2->address.ipv4.min &&
229+ p1->address.ipv6.min == p2->address.ipv6.min &&
230+ p1->address.ipv4.max == p2->address.ipv4.max &&
231+ p1->address.ipv6.max == p2->address.ipv6.max &&
232+ p1->address.group == p2->address.group &&
233+ ccs_same_number_union(&p1->port, &p2->port);
234+}
235+
236+/**
237+ * ccs_same_unix_acl - Check for duplicated "struct ccs_unix_acl" entry.
238+ *
239+ * @a: Pointer to "struct ccs_acl_info".
240+ * @b: Pointer to "struct ccs_acl_info".
241+ *
242+ * Returns true if @a == @b except permission bits, false otherwise.
243+ */
244+static bool ccs_same_unix_acl(const struct ccs_acl_info *a,
245+ const struct ccs_acl_info *b)
246+{
247+ const struct ccs_unix_acl *p1 = container_of(a, typeof(*p1), head);
248+ const struct ccs_unix_acl *p2 = container_of(b, typeof(*p2), head);
249+ return p1->protocol == p2->protocol &&
250+ ccs_same_name_union(&p1->name, &p2->name);
251+}
252+
253+/**
254+ * ccs_merge_inet_acl - Merge duplicated "struct ccs_inet_acl" entry.
255+ *
256+ * @a: Pointer to "struct ccs_acl_info".
257+ * @b: Pointer to "struct ccs_acl_info".
258+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
259+ *
260+ * Returns true if @a is empty, false otherwise.
261+ */
262+static bool ccs_merge_inet_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
263+ const bool is_delete)
264+{
265+ u8 * const a_perm = &container_of(a, struct ccs_inet_acl, head)->perm;
266+ u8 perm = *a_perm;
267+ const u8 b_perm = container_of(b, struct ccs_inet_acl, head)->perm;
268+ if (is_delete)
269+ perm &= ~b_perm;
270+ else
271+ perm |= b_perm;
272+ *a_perm = perm;
273+ return !perm;
274+}
275+
276+/**
277+ * ccs_merge_unix_acl - Merge duplicated "struct ccs_unix_acl" entry.
278+ *
279+ * @a: Pointer to "struct ccs_acl_info".
280+ * @b: Pointer to "struct ccs_acl_info".
281+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
282+ *
283+ * Returns true if @a is empty, false otherwise.
284+ */
285+static bool ccs_merge_unix_acl(struct ccs_acl_info *a, struct ccs_acl_info *b,
286+ const bool is_delete)
287+{
288+ u8 * const a_perm = &container_of(a, struct ccs_unix_acl, head)->perm;
289+ u8 perm = *a_perm;
290+ const u8 b_perm = container_of(b, struct ccs_unix_acl, head)->perm;
291+ if (is_delete)
292+ perm &= ~b_perm;
293+ else
294+ perm |= b_perm;
295+ *a_perm = perm;
296+ return !perm;
297+}
298+
299+/**
300+ * ccs_write_inet_network - Write "struct ccs_inet_acl" list.
301+ *
302+ * @param: Pointer to "struct ccs_acl_param".
303+ *
304+ * Returns 0 on success, negative value otherwise.
305+ */
306+int ccs_write_inet_network(struct ccs_acl_param *param)
307+{
308+ struct ccs_inet_acl e = { .head.type = CCS_TYPE_INET_ACL };
309+ u16 min_address[8];
310+ u16 max_address[8];
311+ int error = -EINVAL;
312+ u8 type;
313+ const char *protocol = ccs_read_token(param);
314+ const char *operation = ccs_read_token(param);
315+ char *address = ccs_read_token(param);
316+ for (e.protocol = 0; e.protocol < CCS_SOCK_MAX; e.protocol++)
317+ if (!strcmp(protocol, ccs_proto_keyword[e.protocol]))
318+ break;
319+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
320+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
321+ e.perm |= 1 << type;
322+ if (e.protocol == CCS_SOCK_MAX || !e.perm)
323+ return -EINVAL;
324+ switch (ccs_parse_ip_address(address, min_address, max_address)) {
325+ case CCS_IP_ADDRESS_TYPE_IPv6:
326+ e.address_type = CCS_IP_ADDRESS_TYPE_IPv6;
327+ e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *)
328+ min_address);
329+ e.address.ipv6.max = ccs_get_ipv6_address((struct in6_addr *)
330+ max_address);
331+ if (!e.address.ipv6.min || !e.address.ipv6.max)
332+ goto out;
333+ break;
334+ case CCS_IP_ADDRESS_TYPE_IPv4:
335+ e.address_type = CCS_IP_ADDRESS_TYPE_IPv4;
336+ /* use host byte order to allow u32 comparison.*/
337+ e.address.ipv4.min = ntohl(*(u32 *) min_address);
338+ e.address.ipv4.max = ntohl(*(u32 *) max_address);
339+ break;
340+ default:
341+ if (address[0] != '@')
342+ return -EINVAL;
343+ e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP;
344+ e.address.group = ccs_get_group(address + 1,
345+ CCS_ADDRESS_GROUP);
346+ if (!e.address.group)
347+ return -ENOMEM;
348+ break;
349+ }
350+ if (!ccs_parse_number_union(ccs_read_token(param), &e.port))
351+ goto out;
352+ error = ccs_update_domain(&e.head, sizeof(e), param, ccs_same_inet_acl,
353+ ccs_merge_inet_acl);
354+out:
355+ if (e.address_type == CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP)
356+ ccs_put_group(e.address.group);
357+ else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) {
358+ ccs_put_ipv6_address(e.address.ipv6.min);
359+ ccs_put_ipv6_address(e.address.ipv6.max);
360+ }
361+ ccs_put_number_union(&e.port);
362+ return error;
363+}
364+
365+/**
366+ * ccs_write_unix_network - Write "struct ccs_unix_acl" list.
367+ *
368+ * @param: Pointer to "struct ccs_acl_param".
369+ *
370+ * Returns 0 on success, negative value otherwise.
371+ */
372+int ccs_write_unix_network(struct ccs_acl_param *param)
373+{
374+ struct ccs_unix_acl e = { .head.type = CCS_TYPE_UNIX_ACL };
375+ int error;
376+ u8 type;
377+ const char *protocol = ccs_read_token(param);
378+ const char *operation = ccs_read_token(param);
379+ for (e.protocol = 0; e.protocol < CCS_SOCK_MAX; e.protocol++)
380+ if (!strcmp(protocol, ccs_proto_keyword[e.protocol]))
381+ break;
382+ for (type = 0; type < CCS_MAX_NETWORK_OPERATION; type++)
383+ if (ccs_permstr(operation, ccs_socket_keyword[type]))
384+ e.perm |= 1 << type;
385+ if (e.protocol == CCS_SOCK_MAX || !e.perm)
386+ return -EINVAL;
387+ if (!ccs_parse_name_union(ccs_read_token(param), &e.name))
388+ return -EINVAL;
389+ error = ccs_update_domain(&e.head, sizeof(e), param, ccs_same_unix_acl,
390+ ccs_merge_unix_acl);
391+ ccs_put_name_union(&e.name);
392+ return error;
393+}
394+
395+#ifndef CONFIG_NET
396+
397+/**
398+ * ccs_network_init - Dummy initialize function for CONFIG_NET=n case.
399+ *
400+ * Returns nothing.
401+ */
402+void __init ccs_network_init(void)
403+{
404+}
405+
406+#else
407+
408+/**
409+ * ccs_audit_net_log - Audit network log.
410+ *
411+ * @r: Pointer to "struct ccs_request_info".
412+ * @family: Name of socket family ("inet" or "unix").
413+ * @protocol: Name of protocol in @family.
414+ * @operation: Name of socket operation.
415+ * @address: Name of address.
416+ *
417+ * Returns 0 on success, negative value otherwise.
418+ */
419+static int ccs_audit_net_log(struct ccs_request_info *r, const char *family,
420+ const u8 protocol, const u8 operation,
421+ const char *address)
422+{
423+ return ccs_supervisor(r, "network %s %s %s %s\n", family,
424+ ccs_proto_keyword[protocol],
425+ ccs_socket_keyword[operation], address);
426+}
427+
428+/**
429+ * ccs_audit_inet_log - Audit INET network log.
430+ *
431+ * @r: Pointer to "struct ccs_request_info".
432+ *
433+ * Returns 0 on success, negative value otherwise.
434+ */
435+static int ccs_audit_inet_log(struct ccs_request_info *r)
436+{
437+ char buf[128];
438+ int len;
439+ const u32 *address = r->param.inet_network.address;
440+ if (r->param.inet_network.is_ipv6)
441+ ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *)
442+ address, (const struct in6_addr *) address);
443+ else
444+ ccs_print_ipv4(buf, sizeof(buf), r->param.inet_network.ip,
445+ r->param.inet_network.ip);
446+ len = strlen(buf);
447+ snprintf(buf + len, sizeof(buf) - len, " %u",
448+ r->param.inet_network.port);
449+ return ccs_audit_net_log(r, "inet", r->param.inet_network.protocol,
450+ r->param.inet_network.operation, buf);
451+}
452+
453+/**
454+ * ccs_audit_unix_log - Audit UNIX network log.
455+ *
456+ * @r: Pointer to "struct ccs_request_info".
457+ *
458+ * Returns 0 on success, negative value otherwise.
459+ */
460+static int ccs_audit_unix_log(struct ccs_request_info *r)
461+{
462+ return ccs_audit_net_log(r, "unix", r->param.unix_network.protocol,
463+ r->param.unix_network.operation,
464+ r->param.unix_network.address->name);
465+}
466+
467+/**
468+ * ccs_check_inet_acl - Check permission for inet domain socket operation.
469+ *
470+ * @r: Pointer to "struct ccs_request_info".
471+ * @ptr: Pointer to "struct ccs_acl_info".
472+ *
473+ * Returns true if granted, false otherwise.
474+ */
475+static bool ccs_check_inet_acl(struct ccs_request_info *r,
476+ const struct ccs_acl_info *ptr)
477+{
478+ const struct ccs_inet_acl *acl = container_of(ptr, typeof(*acl), head);
479+ bool ret;
480+ if (!(acl->perm & (1 << r->param.inet_network.operation)) ||
481+ !ccs_compare_number_union(r->param.inet_network.port, &acl->port))
482+ return false;
483+ switch (acl->address_type) {
484+ case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
485+ ret = ccs_address_matches_group(r->param.inet_network.is_ipv6,
486+ r->param.inet_network.address,
487+ acl->address.group);
488+ break;
489+ case CCS_IP_ADDRESS_TYPE_IPv4:
490+ ret = !r->param.inet_network.is_ipv6 &&
491+ acl->address.ipv4.min <= r->param.inet_network.ip &&
492+ r->param.inet_network.ip <= acl->address.ipv4.max;
493+ break;
494+ default:
495+ ret = r->param.inet_network.is_ipv6 &&
496+ memcmp(acl->address.ipv6.min,
497+ r->param.inet_network.address, 16) <= 0 &&
498+ memcmp(r->param.inet_network.address,
499+ acl->address.ipv6.max, 16) <= 0;
500+ break;
501+ }
502+ return ret;
503+}
504+
505+/**
506+ * ccs_check_unix_acl - Check permission for unix domain socket operation.
507+ *
508+ * @r: Pointer to "struct ccs_request_info".
509+ * @ptr: Pointer to "struct ccs_acl_info".
510+ *
511+ * Returns true if granted, false otherwise.
512+ */
513+static bool ccs_check_unix_acl(struct ccs_request_info *r,
514+ const struct ccs_acl_info *ptr)
515+{
516+ const struct ccs_unix_acl *acl = container_of(ptr, typeof(*acl), head);
517+ return (acl->perm & (1 << r->param.unix_network.operation)) &&
518+ ccs_compare_name_union(r->param.unix_network.address,
519+ &acl->name);
520+}
521+
522+/**
523+ * ccs_inet_entry - Check permission for INET network operation.
524+ *
525+ * @address: Pointer to "struct ccs_addr_info".
526+ *
527+ * Returns 0 on success, negative value otherwise.
528+ */
529+static int ccs_inet_entry(const struct ccs_addr_info *address)
530+{
531+ const int idx = ccs_read_lock();
532+ struct ccs_request_info r;
533+ int error = 0;
534+ const u8 type = ccs_inet2mac[address->protocol][address->operation];
535+ if (type && ccs_init_request_info(&r, type) != CCS_CONFIG_DISABLED) {
536+ r.param_type = CCS_TYPE_INET_ACL;
537+ r.param.inet_network.prot

Ein Teil der Diff wurde aufgrund der Größenbeschränkung abgeschnitten. Verwenden Sie Ihren lokalen Client, um die vollständige Diff.

Show on old repository browser