diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-07 14:44:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-07 14:44:01 -0500 |
commit | ae5906ceee038ea29ff5162d1bcd18fb50af8b94 (patch) | |
tree | 841a11c6d3c3afcf7e4d57be370ebcf57aab214a | |
parent | 1fc1cd8399ab5541a488a7e47b2f21537dd76c2d (diff) | |
parent | 468e91cecb3218afd684b8c422490dfebe0691bb (diff) |
Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
- Extend LSM stacking to allow sharing of cred, file, ipc, inode, and
task blobs. This paves the way for more full-featured LSMs to be
merged, and is specifically aimed at LandLock and SARA LSMs. This
work is from Casey and Kees.
- There's a new LSM from Micah Morton: "SafeSetID gates the setid
family of syscalls to restrict UID/GID transitions from a given
UID/GID to only those approved by a system-wide whitelist." This
feature is currently shipping in ChromeOS.
* 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (62 commits)
keys: fix missing __user in KEYCTL_PKEY_QUERY
LSM: Update list of SECURITYFS users in Kconfig
LSM: Ignore "security=" when "lsm=" is specified
LSM: Update function documentation for cap_capable
security: mark expected switch fall-throughs and add a missing break
tomoyo: Bump version.
LSM: fix return value check in safesetid_init_securityfs()
LSM: SafeSetID: add selftest
LSM: SafeSetID: remove unused include
LSM: SafeSetID: 'depend' on CONFIG_SECURITY
LSM: Add 'name' field for SafeSetID in DEFINE_LSM
LSM: add SafeSetID module that gates setid calls
LSM: add SafeSetID module that gates setid calls
tomoyo: Allow multiple use_group lines.
tomoyo: Coding style fix.
tomoyo: Swicth from cred->security to task_struct->security.
security: keys: annotate implicit fall throughs
security: keys: annotate implicit fall throughs
security: keys: annotate implicit fall through
capabilities:: annotate implicit fall through
...
78 files changed, 2674 insertions, 1090 deletions
diff --git a/Documentation/admin-guide/LSM/SafeSetID.rst b/Documentation/admin-guide/LSM/SafeSetID.rst new file mode 100644 index 000000000000..212434ef65ad --- /dev/null +++ b/Documentation/admin-guide/LSM/SafeSetID.rst | |||
@@ -0,0 +1,107 @@ | |||
1 | ========= | ||
2 | SafeSetID | ||
3 | ========= | ||
4 | SafeSetID is an LSM module that gates the setid family of syscalls to restrict | ||
5 | UID/GID transitions from a given UID/GID to only those approved by a | ||
6 | system-wide whitelist. These restrictions also prohibit the given UIDs/GIDs | ||
7 | from obtaining auxiliary privileges associated with CAP_SET{U/G}ID, such as | ||
8 | allowing a user to set up user namespace UID mappings. | ||
9 | |||
10 | |||
11 | Background | ||
12 | ========== | ||
13 | In absence of file capabilities, processes spawned on a Linux system that need | ||
14 | to switch to a different user must be spawned with CAP_SETUID privileges. | ||
15 | CAP_SETUID is granted to programs running as root or those running as a non-root | ||
16 | user that have been explicitly given the CAP_SETUID runtime capability. It is | ||
17 | often preferable to use Linux runtime capabilities rather than file | ||
18 | capabilities, since using file capabilities to run a program with elevated | ||
19 | privileges opens up possible security holes since any user with access to the | ||
20 | file can exec() that program to gain the elevated privileges. | ||
21 | |||
22 | While it is possible to implement a tree of processes by giving full | ||
23 | CAP_SET{U/G}ID capabilities, this is often at odds with the goals of running a | ||
24 | tree of processes under non-root user(s) in the first place. Specifically, | ||
25 | since CAP_SETUID allows changing to any user on the system, including the root | ||
26 | user, it is an overpowered capability for what is needed in this scenario, | ||
27 | especially since programs often only call setuid() to drop privileges to a | ||
28 | lesser-privileged user -- not elevate privileges. Unfortunately, there is no | ||
29 | generally feasible way in Linux to restrict the potential UIDs that a user can | ||
30 | switch to through setuid() beyond allowing a switch to any user on the system. | ||
31 | This SafeSetID LSM seeks to provide a solution for restricting setid | ||
32 | capabilities in such a way. | ||
33 | |||
34 | The main use case for this LSM is to allow a non-root program to transition to | ||
35 | other untrusted uids without full blown CAP_SETUID capabilities. The non-root | ||
36 | program would still need CAP_SETUID to do any kind of transition, but the | ||
37 | additional restrictions imposed by this LSM would mean it is a "safer" version | ||
38 | of CAP_SETUID since the non-root program cannot take advantage of CAP_SETUID to | ||
39 | do any unapproved actions (e.g. setuid to uid 0 or create/enter new user | ||
40 | namespace). The higher level goal is to allow for uid-based sandboxing of system | ||
41 | services without having to give out CAP_SETUID all over the place just so that | ||
42 | non-root programs can drop to even-lesser-privileged uids. This is especially | ||
43 | relevant when one non-root daemon on the system should be allowed to spawn other | ||
44 | processes as different uids, but its undesirable to give the daemon a | ||
45 | basically-root-equivalent CAP_SETUID. | ||
46 | |||
47 | |||
48 | Other Approaches Considered | ||
49 | =========================== | ||
50 | |||
51 | Solve this problem in userspace | ||
52 | ------------------------------- | ||
53 | For candidate applications that would like to have restricted setid capabilities | ||
54 | as implemented in this LSM, an alternative option would be to simply take away | ||
55 | setid capabilities from the application completely and refactor the process | ||
56 | spawning semantics in the application (e.g. by using a privileged helper program | ||
57 | to do process spawning and UID/GID transitions). Unfortunately, there are a | ||
58 | number of semantics around process spawning that would be affected by this, such | ||
59 | as fork() calls where the program doesn???t immediately call exec() after the | ||
60 | fork(), parent processes specifying custom environment variables or command line | ||
61 | args for spawned child processes, or inheritance of file handles across a | ||
62 | fork()/exec(). Because of this, as solution that uses a privileged helper in | ||
63 | userspace would likely be less appealing to incorporate into existing projects | ||
64 | that rely on certain process-spawning semantics in Linux. | ||
65 | |||
66 | Use user namespaces | ||
67 | ------------------- | ||
68 | Another possible approach would be to run a given process tree in its own user | ||
69 | namespace and give programs in the tree setid capabilities. In this way, | ||
70 | programs in the tree could change to any desired UID/GID in the context of their | ||
71 | own user namespace, and only approved UIDs/GIDs could be mapped back to the | ||
72 | initial system user namespace, affectively preventing privilege escalation. | ||
73 | Unfortunately, it is not generally feasible to use user namespaces in isolation, | ||
74 | without pairing them with other namespace types, which is not always an option. | ||
75 | Linux checks for capabilities based off of the user namespace that ???owns??? some | ||
76 | entity. For example, Linux has the notion that network namespaces are owned by | ||
77 | the user namespace in which they were created. A consequence of this is that | ||
78 | capability checks for access to a given network namespace are done by checking | ||
79 | whether a task has the given capability in the context of the user namespace | ||
80 | that owns the network namespace -- not necessarily the user namespace under | ||
81 | which the given task runs. Therefore spawning a process in a new user namespace | ||
82 | effectively prevents it from accessing the network namespace owned by the | ||
83 | initial namespace. This is a deal-breaker for any application that expects to | ||
84 | retain the CAP_NET_ADMIN capability for the purpose of adjusting network | ||
85 | configurations. Using user namespaces in isolation causes problems regarding | ||
86 | other system interactions, including use of pid namespaces and device creation. | ||
87 | |||
88 | Use an existing LSM | ||
89 | ------------------- | ||
90 | None of the other in-tree LSMs have the capability to gate setid transitions, or | ||
91 | even employ the security_task_fix_setuid hook at all. SELinux says of that hook: | ||
92 | "Since setuid only affects the current process, and since the SELinux controls | ||
93 | are not based on the Linux identity attributes, SELinux does not need to control | ||
94 | this operation." | ||
95 | |||
96 | |||
97 | Directions for use | ||
98 | ================== | ||
99 | This LSM hooks the setid syscalls to make sure transitions are allowed if an | ||
100 | applicable restriction policy is in place. Policies are configured through | ||
101 | securityfs by writing to the safesetid/add_whitelist_policy and | ||
102 | safesetid/flush_whitelist_policies files at the location where securityfs is | ||
103 | mounted. The format for adding a policy is '<UID>:<UID>', using literal | ||
104 | numbers, such as '123:456'. To flush the policies, any write to the file is | ||
105 | sufficient. Again, configuring a policy for a UID will prevent that UID from | ||
106 | obtaining auxiliary setid privileges, such as allowing a user to set up user | ||
107 | namespace UID mappings. | ||
diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst index c980dfe9abf1..a6ba95fbaa9f 100644 --- a/Documentation/admin-guide/LSM/index.rst +++ b/Documentation/admin-guide/LSM/index.rst | |||
@@ -17,9 +17,8 @@ MAC extensions, other extensions can be built using the LSM to provide | |||
17 | specific changes to system operation when these tweaks are not available | 17 | specific changes to system operation when these tweaks are not available |
18 | in the core functionality of Linux itself. | 18 | in the core functionality of Linux itself. |
19 | 19 | ||
20 | Without a specific LSM built into the kernel, the default LSM will be the | 20 | The Linux capabilities modules will always be included. This may be |
21 | Linux capabilities system. Most LSMs choose to extend the capabilities | 21 | followed by any number of "minor" modules and at most one "major" module. |
22 | system, building their checks on top of the defined capability hooks. | ||
23 | For more details on capabilities, see ``capabilities(7)`` in the Linux | 22 | For more details on capabilities, see ``capabilities(7)`` in the Linux |
24 | man-pages project. | 23 | man-pages project. |
25 | 24 | ||
@@ -30,6 +29,14 @@ order in which checks are made. The capability module will always | |||
30 | be first, followed by any "minor" modules (e.g. Yama) and then | 29 | be first, followed by any "minor" modules (e.g. Yama) and then |
31 | the one "major" module (e.g. SELinux) if there is one configured. | 30 | the one "major" module (e.g. SELinux) if there is one configured. |
32 | 31 | ||
32 | Process attributes associated with "major" security modules should | ||
33 | be accessed and maintained using the special files in ``/proc/.../attr``. | ||
34 | A security module may maintain a module specific subdirectory there, | ||
35 | named after the module. ``/proc/.../attr/smack`` is provided by the Smack | ||
36 | security module and contains all its special files. The files directly | ||
37 | in ``/proc/.../attr`` remain as legacy interfaces for modules that provide | ||
38 | subdirectories. | ||
39 | |||
33 | .. toctree:: | 40 | .. toctree:: |
34 | :maxdepth: 1 | 41 | :maxdepth: 1 |
35 | 42 | ||
@@ -39,3 +46,4 @@ the one "major" module (e.g. SELinux) if there is one configured. | |||
39 | Smack | 46 | Smack |
40 | tomoyo | 47 | tomoyo |
41 | Yama | 48 | Yama |
49 | SafeSetID | ||
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a422560fbc15..42379633801f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -2333,6 +2333,10 @@ | |||
2333 | 2333 | ||
2334 | lsm.debug [SECURITY] Enable LSM initialization debugging output. | 2334 | lsm.debug [SECURITY] Enable LSM initialization debugging output. |
2335 | 2335 | ||
2336 | lsm=lsm1,...,lsmN | ||
2337 | [SECURITY] Choose order of LSM initialization. This | ||
2338 | overrides CONFIG_LSM, and the "security=" parameter. | ||
2339 | |||
2336 | machvec= [IA-64] Force the use of a particular machine-vector | 2340 | machvec= [IA-64] Force the use of a particular machine-vector |
2337 | (machvec) in a generic kernel. | 2341 | (machvec) in a generic kernel. |
2338 | Example: machvec=hpzx1_swiotlb | 2342 | Example: machvec=hpzx1_swiotlb |
@@ -4110,11 +4114,9 @@ | |||
4110 | Note: increases power consumption, thus should only be | 4114 | Note: increases power consumption, thus should only be |
4111 | enabled if running jitter sensitive (HPC/RT) workloads. | 4115 | enabled if running jitter sensitive (HPC/RT) workloads. |
4112 | 4116 | ||
4113 | security= [SECURITY] Choose a security module to enable at boot. | 4117 | security= [SECURITY] Choose a legacy "major" security module to |
4114 | If this boot parameter is not specified, only the first | 4118 | enable at boot. This has been deprecated by the |
4115 | security module asking for security registration will be | 4119 | "lsm=" parameter. |
4116 | loaded. An invalid security module name will be treated | ||
4117 | as if no module has been chosen. | ||
4118 | 4120 | ||
4119 | selinux= [SELINUX] Disable or enable SELinux at boot time. | 4121 | selinux= [SELINUX] Disable or enable SELinux at boot time. |
4120 | Format: { "0" | "1" } | 4122 | Format: { "0" | "1" } |
diff --git a/MAINTAINERS b/MAINTAINERS index da98f27cf1b5..09d47cd02a14 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -15557,12 +15557,11 @@ F: mm/shmem.c | |||
15557 | TOMOYO SECURITY MODULE | 15557 | TOMOYO SECURITY MODULE |
15558 | M: Kentaro Takeda <takedakn@nttdata.co.jp> | 15558 | M: Kentaro Takeda <takedakn@nttdata.co.jp> |
15559 | M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 15559 | M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
15560 | L: tomoyo-dev-en@lists.sourceforge.jp (subscribers-only, for developers in English) | 15560 | L: tomoyo-dev-en@lists.osdn.me (subscribers-only, for developers in English) |
15561 | L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English) | 15561 | L: tomoyo-users-en@lists.osdn.me (subscribers-only, for users in English) |
15562 | L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese) | 15562 | L: tomoyo-dev@lists.osdn.me (subscribers-only, for developers in Japanese) |
15563 | L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese) | 15563 | L: tomoyo-users@lists.osdn.me (subscribers-only, for users in Japanese) |
15564 | W: http://tomoyo.sourceforge.jp/ | 15564 | W: https://tomoyo.osdn.jp/ |
15565 | T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.5.x/tomoyo-lsm/patches/ | ||
15566 | S: Maintained | 15565 | S: Maintained |
15567 | F: security/tomoyo/ | 15566 | F: security/tomoyo/ |
15568 | 15567 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 511b279ec69c..fca9fa5f23d8 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -140,9 +140,13 @@ struct pid_entry { | |||
140 | #define REG(NAME, MODE, fops) \ | 140 | #define REG(NAME, MODE, fops) \ |
141 | NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) | 141 | NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) |
142 | #define ONE(NAME, MODE, show) \ | 142 | #define ONE(NAME, MODE, show) \ |
143 | NOD(NAME, (S_IFREG|(MODE)), \ | 143 | NOD(NAME, (S_IFREG|(MODE)), \ |
144 | NULL, &proc_single_file_operations, \ | 144 | NULL, &proc_single_file_operations, \ |
145 | { .proc_show = show } ) | 145 | { .proc_show = show } ) |
146 | #define ATTR(LSM, NAME, MODE) \ | ||
147 | NOD(NAME, (S_IFREG|(MODE)), \ | ||
148 | NULL, &proc_pid_attr_operations, \ | ||
149 | { .lsm = LSM }) | ||
146 | 150 | ||
147 | /* | 151 | /* |
148 | * Count the number of hardlinks for the pid_entry table, excluding the . | 152 | * Count the number of hardlinks for the pid_entry table, excluding the . |
@@ -2521,7 +2525,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, | |||
2521 | if (!task) | 2525 | if (!task) |
2522 | return -ESRCH; | 2526 | return -ESRCH; |
2523 | 2527 | ||
2524 | length = security_getprocattr(task, | 2528 | length = security_getprocattr(task, PROC_I(inode)->op.lsm, |
2525 | (char*)file->f_path.dentry->d_name.name, | 2529 | (char*)file->f_path.dentry->d_name.name, |
2526 | &p); | 2530 | &p); |
2527 | put_task_struct(task); | 2531 | put_task_struct(task); |
@@ -2570,7 +2574,9 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, | |||
2570 | if (rv < 0) | 2574 | if (rv < 0) |
2571 | goto out_free; | 2575 | goto out_free; |
2572 | 2576 | ||
2573 | rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count); | 2577 | rv = security_setprocattr(PROC_I(inode)->op.lsm, |
2578 | file->f_path.dentry->d_name.name, page, | ||
2579 | count); | ||
2574 | mutex_unlock(¤t->signal->cred_guard_mutex); | 2580 | mutex_unlock(¤t->signal->cred_guard_mutex); |
2575 | out_free: | 2581 | out_free: |
2576 | kfree(page); | 2582 | kfree(page); |
@@ -2584,13 +2590,53 @@ static const struct file_operations proc_pid_attr_operations = { | |||
2584 | .llseek = generic_file_llseek, | 2590 | .llseek = generic_file_llseek, |
2585 | }; | 2591 | }; |
2586 | 2592 | ||
2593 | #define LSM_DIR_OPS(LSM) \ | ||
2594 | static int proc_##LSM##_attr_dir_iterate(struct file *filp, \ | ||
2595 | struct dir_context *ctx) \ | ||
2596 | { \ | ||
2597 | return proc_pident_readdir(filp, ctx, \ | ||
2598 | LSM##_attr_dir_stuff, \ | ||
2599 | ARRAY_SIZE(LSM##_attr_dir_stuff)); \ | ||
2600 | } \ | ||
2601 | \ | ||
2602 | static const struct file_operations proc_##LSM##_attr_dir_ops = { \ | ||
2603 | .read = generic_read_dir, \ | ||
2604 | .iterate = proc_##LSM##_attr_dir_iterate, \ | ||
2605 | .llseek = default_llseek, \ | ||
2606 | }; \ | ||
2607 | \ | ||
2608 | static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \ | ||
2609 | struct dentry *dentry, unsigned int flags) \ | ||
2610 | { \ | ||
2611 | return proc_pident_lookup(dir, dentry, \ | ||
2612 | LSM##_attr_dir_stuff, \ | ||
2613 | ARRAY_SIZE(LSM##_attr_dir_stuff)); \ | ||
2614 | } \ | ||
2615 | \ | ||
2616 | static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ | ||
2617 | .lookup = proc_##LSM##_attr_dir_lookup, \ | ||
2618 | .getattr = pid_getattr, \ | ||
2619 | .setattr = proc_setattr, \ | ||
2620 | } | ||
2621 | |||
2622 | #ifdef CONFIG_SECURITY_SMACK | ||
2623 | static const struct pid_entry smack_attr_dir_stuff[] = { | ||
2624 | ATTR("smack", "current", 0666), | ||
2625 | }; | ||
2626 | LSM_DIR_OPS(smack); | ||
2627 | #endif | ||
2628 | |||
2587 | static const struct pid_entry attr_dir_stuff[] = { | 2629 | static const struct pid_entry attr_dir_stuff[] = { |
2588 | REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2630 | ATTR(NULL, "current", 0666), |
2589 | REG("prev", S_IRUGO, proc_pid_attr_operations), | 2631 | ATTR(NULL, "prev", 0444), |
2590 | REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2632 | ATTR(NULL, "exec", 0666), |
2591 | REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2633 | ATTR(NULL, "fscreate", 0666), |
2592 | REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2634 | ATTR(NULL, "keycreate", 0666), |
2593 | REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2635 | ATTR(NULL, "sockcreate", 0666), |
2636 | #ifdef CONFIG_SECURITY_SMACK | ||
2637 | DIR("smack", 0555, | ||
2638 | proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), | ||
2639 | #endif | ||
2594 | }; | 2640 | }; |
2595 | 2641 | ||
2596 | static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) | 2642 | static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 4fc5a9b68f76..ea575375f210 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -82,6 +82,7 @@ union proc_op { | |||
82 | int (*proc_show)(struct seq_file *m, | 82 | int (*proc_show)(struct seq_file *m, |
83 | struct pid_namespace *ns, struct pid *pid, | 83 | struct pid_namespace *ns, struct pid *pid, |
84 | struct task_struct *task); | 84 | struct task_struct *task); |
85 | const char *lsm; | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | struct proc_inode { | 88 | struct proc_inode { |
diff --git a/include/linux/capability.h b/include/linux/capability.h index f640dcbc880c..c3f9a4d558a0 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -209,6 +209,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, | |||
209 | extern bool capable(int cap); | 209 | extern bool capable(int cap); |
210 | extern bool ns_capable(struct user_namespace *ns, int cap); | 210 | extern bool ns_capable(struct user_namespace *ns, int cap); |
211 | extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); | 211 | extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); |
212 | extern bool ns_capable_setid(struct user_namespace *ns, int cap); | ||
212 | #else | 213 | #else |
213 | static inline bool has_capability(struct task_struct *t, int cap) | 214 | static inline bool has_capability(struct task_struct *t, int cap) |
214 | { | 215 | { |
@@ -240,6 +241,10 @@ static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) | |||
240 | { | 241 | { |
241 | return true; | 242 | return true; |
242 | } | 243 | } |
244 | static inline bool ns_capable_setid(struct user_namespace *ns, int cap) | ||
245 | { | ||
246 | return true; | ||
247 | } | ||
243 | #endif /* CONFIG_MULTIUSER */ | 248 | #endif /* CONFIG_MULTIUSER */ |
244 | extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode); | 249 | extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode); |
245 | extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); | 250 | extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); |
diff --git a/include/linux/cred.h b/include/linux/cred.h index 4907c9df86b3..ddd45bb74887 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/capability.h> | 15 | #include <linux/capability.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
18 | #include <linux/selinux.h> | ||
19 | #include <linux/atomic.h> | 18 | #include <linux/atomic.h> |
20 | #include <linux/uidgid.h> | 19 | #include <linux/uidgid.h> |
21 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9a0bdf91e646..22fc786d723a 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
@@ -1270,7 +1270,7 @@ | |||
1270 | * @cred contains the credentials to use. | 1270 | * @cred contains the credentials to use. |
1271 | * @ns contains the user namespace we want the capability in | 1271 | * @ns contains the user namespace we want the capability in |
1272 | * @cap contains the capability <include/linux/capability.h>. | 1272 | * @cap contains the capability <include/linux/capability.h>. |
1273 | * @audit contains whether to write an audit message or not | 1273 | * @opts contains options for the capable check <include/linux/security.h> |
1274 | * Return 0 if the capability is granted for @tsk. | 1274 | * Return 0 if the capability is granted for @tsk. |
1275 | * @syslog: | 1275 | * @syslog: |
1276 | * Check permission before accessing the kernel message ring or changing | 1276 | * Check permission before accessing the kernel message ring or changing |
@@ -1446,8 +1446,10 @@ union security_list_options { | |||
1446 | const kernel_cap_t *effective, | 1446 | const kernel_cap_t *effective, |
1447 | const kernel_cap_t *inheritable, | 1447 | const kernel_cap_t *inheritable, |
1448 | const kernel_cap_t *permitted); | 1448 | const kernel_cap_t *permitted); |
1449 | int (*capable)(const struct cred *cred, struct user_namespace *ns, | 1449 | int (*capable)(const struct cred *cred, |
1450 | int cap, int audit); | 1450 | struct user_namespace *ns, |
1451 | int cap, | ||
1452 | unsigned int opts); | ||
1451 | int (*quotactl)(int cmds, int type, int id, struct super_block *sb); | 1453 | int (*quotactl)(int cmds, int type, int id, struct super_block *sb); |
1452 | int (*quota_on)(struct dentry *dentry); | 1454 | int (*quota_on)(struct dentry *dentry); |
1453 | int (*syslog)(int type); | 1455 | int (*syslog)(int type); |
@@ -2028,6 +2030,18 @@ struct security_hook_list { | |||
2028 | } __randomize_layout; | 2030 | } __randomize_layout; |
2029 | 2031 | ||
2030 | /* | 2032 | /* |
2033 | * Security blob size or offset data. | ||
2034 | */ | ||
2035 | struct lsm_blob_sizes { | ||
2036 | int lbs_cred; | ||
2037 | int lbs_file; | ||
2038 | int lbs_inode; | ||
2039 | int lbs_ipc; | ||
2040 | int lbs_msg_msg; | ||
2041 | int lbs_task; | ||
2042 | }; | ||
2043 | |||
2044 | /* | ||
2031 | * Initializing a security_hook_list structure takes | 2045 | * Initializing a security_hook_list structure takes |
2032 | * up a lot of space in a source file. This macro takes | 2046 | * up a lot of space in a source file. This macro takes |
2033 | * care of the common case and reduces the amount of | 2047 | * care of the common case and reduces the amount of |
@@ -2042,9 +2056,21 @@ extern char *lsm_names; | |||
2042 | extern void security_add_hooks(struct security_hook_list *hooks, int count, | 2056 | extern void security_add_hooks(struct security_hook_list *hooks, int count, |
2043 | char *lsm); | 2057 | char *lsm); |
2044 | 2058 | ||
2059 | #define LSM_FLAG_LEGACY_MAJOR BIT(0) | ||
2060 | #define LSM_FLAG_EXCLUSIVE BIT(1) | ||
2061 | |||
2062 | enum lsm_order { | ||
2063 | LSM_ORDER_FIRST = -1, /* This is only for capabilities. */ | ||
2064 | LSM_ORDER_MUTABLE = 0, | ||
2065 | }; | ||
2066 | |||
2045 | struct lsm_info { | 2067 | struct lsm_info { |
2046 | const char *name; /* Required. */ | 2068 | const char *name; /* Required. */ |
2069 | enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */ | ||
2070 | unsigned long flags; /* Optional: flags describing LSM */ | ||
2071 | int *enabled; /* Optional: controlled by CONFIG_LSM */ | ||
2047 | int (*init)(void); /* Required. */ | 2072 | int (*init)(void); /* Required. */ |
2073 | struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */ | ||
2048 | }; | 2074 | }; |
2049 | 2075 | ||
2050 | extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; | 2076 | extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; |
@@ -2084,17 +2110,6 @@ static inline void security_delete_hooks(struct security_hook_list *hooks, | |||
2084 | #define __lsm_ro_after_init __ro_after_init | 2110 | #define __lsm_ro_after_init __ro_after_init |
2085 | #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ | 2111 | #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ |
2086 | 2112 | ||
2087 | extern int __init security_module_enable(const char *module); | 2113 | extern int lsm_inode_alloc(struct inode *inode); |
2088 | extern void __init capability_add_hooks(void); | ||
2089 | #ifdef CONFIG_SECURITY_YAMA | ||
2090 | extern void __init yama_add_hooks(void); | ||
2091 | #else | ||
2092 | static inline void __init yama_add_hooks(void) { } | ||
2093 | #endif | ||
2094 | #ifdef CONFIG_SECURITY_LOADPIN | ||
2095 | void __init loadpin_add_hooks(void); | ||
2096 | #else | ||
2097 | static inline void loadpin_add_hooks(void) { }; | ||
2098 | #endif | ||
2099 | 2114 | ||
2100 | #endif /* ! __LINUX_LSM_HOOKS_H */ | 2115 | #endif /* ! __LINUX_LSM_HOOKS_H */ |
diff --git a/include/linux/security.h b/include/linux/security.h index dbfb5a66babb..13537a49ae97 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -54,9 +54,12 @@ struct xattr; | |||
54 | struct xfrm_sec_ctx; | 54 | struct xfrm_sec_ctx; |
55 | struct mm_struct; | 55 | struct mm_struct; |
56 | 56 | ||
57 | /* Default (no) options for the capable function */ | ||
58 | #define CAP_OPT_NONE 0x0 | ||
57 | /* If capable should audit the security request */ | 59 | /* If capable should audit the security request */ |
58 | #define SECURITY_CAP_NOAUDIT 0 | 60 | #define CAP_OPT_NOAUDIT BIT(1) |
59 | #define SECURITY_CAP_AUDIT 1 | 61 | /* If capable is being called by a setid function */ |
62 | #define CAP_OPT_INSETID BIT(2) | ||
60 | 63 | ||
61 | /* LSM Agnostic defines for sb_set_mnt_opts */ | 64 | /* LSM Agnostic defines for sb_set_mnt_opts */ |
62 | #define SECURITY_LSM_NATIVE_LABELS 1 | 65 | #define SECURITY_LSM_NATIVE_LABELS 1 |
@@ -72,7 +75,7 @@ enum lsm_event { | |||
72 | 75 | ||
73 | /* These functions are in security/commoncap.c */ | 76 | /* These functions are in security/commoncap.c */ |
74 | extern int cap_capable(const struct cred *cred, struct user_namespace *ns, | 77 | extern int cap_capable(const struct cred *cred, struct user_namespace *ns, |
75 | int cap, int audit); | 78 | int cap, unsigned int opts); |
76 | extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz); | 79 | extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz); |
77 | extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); | 80 | extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); |
78 | extern int cap_ptrace_traceme(struct task_struct *parent); | 81 | extern int cap_ptrace_traceme(struct task_struct *parent); |
@@ -207,10 +210,10 @@ int security_capset(struct cred *new, const struct cred *old, | |||
207 | const kernel_cap_t *effective, | 210 | const kernel_cap_t *effective, |
208 | const kernel_cap_t *inheritable, | 211 | const kernel_cap_t *inheritable, |
209 | const kernel_cap_t *permitted); | 212 | const kernel_cap_t *permitted); |
210 | int security_capable(const struct cred *cred, struct user_namespace *ns, | 213 | int security_capable(const struct cred *cred, |
211 | int cap); | 214 | struct user_namespace *ns, |
212 | int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, | 215 | int cap, |
213 | int cap); | 216 | unsigned int opts); |
214 | int security_quotactl(int cmds, int type, int id, struct super_block *sb); | 217 | int security_quotactl(int cmds, int type, int id, struct super_block *sb); |
215 | int security_quota_on(struct dentry *dentry); | 218 | int security_quota_on(struct dentry *dentry); |
216 | int security_syslog(int type); | 219 | int security_syslog(int type); |
@@ -366,8 +369,10 @@ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd); | |||
366 | int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, | 369 | int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, |
367 | unsigned nsops, int alter); | 370 | unsigned nsops, int alter); |
368 | void security_d_instantiate(struct dentry *dentry, struct inode *inode); | 371 | void security_d_instantiate(struct dentry *dentry, struct inode *inode); |
369 | int security_getprocattr(struct task_struct *p, char *name, char **value); | 372 | int security_getprocattr(struct task_struct *p, const char *lsm, char *name, |
370 | int security_setprocattr(const char *name, void *value, size_t size); | 373 | char **value); |
374 | int security_setprocattr(const char *lsm, const char *name, void *value, | ||
375 | size_t size); | ||
371 | int security_netlink_send(struct sock *sk, struct sk_buff *skb); | 376 | int security_netlink_send(struct sock *sk, struct sk_buff *skb); |
372 | int security_ismaclabel(const char *name); | 377 | int security_ismaclabel(const char *name); |
373 | int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); | 378 | int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); |
@@ -462,14 +467,11 @@ static inline int security_capset(struct cred *new, | |||
462 | } | 467 | } |
463 | 468 | ||
464 | static inline int security_capable(const struct cred *cred, | 469 | static inline int security_capable(const struct cred *cred, |
465 | struct user_namespace *ns, int cap) | 470 | struct user_namespace *ns, |
471 | int cap, | ||
472 | unsigned int opts) | ||
466 | { | 473 | { |
467 | return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); | 474 | return cap_capable(cred, ns, cap, opts); |
468 | } | ||
469 | |||
470 | static inline int security_capable_noaudit(const struct cred *cred, | ||
471 | struct user_namespace *ns, int cap) { | ||
472 | return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); | ||
473 | } | 475 | } |
474 | 476 | ||
475 | static inline int security_quotactl(int cmds, int type, int id, | 477 | static inline int security_quotactl(int cmds, int type, int id, |
@@ -1112,15 +1114,18 @@ static inline int security_sem_semop(struct kern_ipc_perm *sma, | |||
1112 | return 0; | 1114 | return 0; |
1113 | } | 1115 | } |
1114 | 1116 | ||
1115 | static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode) | 1117 | static inline void security_d_instantiate(struct dentry *dentry, |
1118 | struct inode *inode) | ||
1116 | { } | 1119 | { } |
1117 | 1120 | ||
1118 | static inline int security_getprocattr(struct task_struct *p, char *name, char **value) | 1121 | static inline int security_getprocattr(struct task_struct *p, const char *lsm, |
1122 | char *name, char **value) | ||
1119 | { | 1123 | { |
1120 | return -EINVAL; | 1124 | return -EINVAL; |
1121 | } | 1125 | } |
1122 | 1126 | ||
1123 | static inline int security_setprocattr(char *name, void *value, size_t size) | 1127 | static inline int security_setprocattr(const char *lsm, char *name, |
1128 | void *value, size_t size) | ||
1124 | { | 1129 | { |
1125 | return -EINVAL; | 1130 | return -EINVAL; |
1126 | } | 1131 | } |
diff --git a/include/linux/selinux.h b/include/linux/selinux.h deleted file mode 100644 index 44f459612690..000000000000 --- a/include/linux/selinux.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * SELinux services exported to the rest of the kernel. | ||
3 | * | ||
4 | * Author: James Morris <jmorris@redhat.com> | ||
5 | * | ||
6 | * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com> | ||
7 | * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> | ||
8 | * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2, | ||
12 | * as published by the Free Software Foundation. | ||
13 | */ | ||
14 | #ifndef _LINUX_SELINUX_H | ||
15 | #define _LINUX_SELINUX_H | ||
16 | |||
17 | struct selinux_audit_rule; | ||
18 | struct audit_context; | ||
19 | struct kern_ipc_perm; | ||
20 | |||
21 | #ifdef CONFIG_SECURITY_SELINUX | ||
22 | |||
23 | /** | ||
24 | * selinux_is_enabled - is SELinux enabled? | ||
25 | */ | ||
26 | bool selinux_is_enabled(void); | ||
27 | #else | ||
28 | |||
29 | static inline bool selinux_is_enabled(void) | ||
30 | { | ||
31 | return false; | ||
32 | } | ||
33 | #endif /* CONFIG_SECURITY_SELINUX */ | ||
34 | |||
35 | #endif /* _LINUX_SELINUX_H */ | ||
diff --git a/kernel/capability.c b/kernel/capability.c index 1e1c0236f55b..1444f3954d75 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -93,9 +93,7 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy) | |||
93 | break; | 93 | break; |
94 | case _LINUX_CAPABILITY_VERSION_2: | 94 | case _LINUX_CAPABILITY_VERSION_2: |
95 | warn_deprecated_v2(); | 95 | warn_deprecated_v2(); |
96 | /* | 96 | /* fall through - v3 is otherwise equivalent to v2. */ |
97 | * fall through - v3 is otherwise equivalent to v2. | ||
98 | */ | ||
99 | case _LINUX_CAPABILITY_VERSION_3: | 97 | case _LINUX_CAPABILITY_VERSION_3: |
100 | *tocopy = _LINUX_CAPABILITY_U32S_3; | 98 | *tocopy = _LINUX_CAPABILITY_U32S_3; |
101 | break; | 99 | break; |
@@ -299,7 +297,7 @@ bool has_ns_capability(struct task_struct *t, | |||
299 | int ret; | 297 | int ret; |
300 | 298 | ||
301 | rcu_read_lock(); | 299 | rcu_read_lock(); |
302 | ret = security_capable(__task_cred(t), ns, cap); | 300 | ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE); |
303 | rcu_read_unlock(); | 301 | rcu_read_unlock(); |
304 | 302 | ||
305 | return (ret == 0); | 303 | return (ret == 0); |
@@ -340,7 +338,7 @@ bool has_ns_capability_noaudit(struct task_struct *t, | |||
340 | int ret; | 338 | int ret; |
341 | 339 | ||
342 | rcu_read_lock(); | 340 | rcu_read_lock(); |
343 | ret = security_capable_noaudit(__task_cred(t), ns, cap); | 341 | ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT); |
344 | rcu_read_unlock(); | 342 | rcu_read_unlock(); |
345 | 343 | ||
346 | return (ret == 0); | 344 | return (ret == 0); |
@@ -363,7 +361,9 @@ bool has_capability_noaudit(struct task_struct *t, int cap) | |||
363 | return has_ns_capability_noaudit(t, &init_user_ns, cap); | 361 | return has_ns_capability_noaudit(t, &init_user_ns, cap); |
364 | } | 362 | } |
365 | 363 | ||
366 | static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) | 364 | static bool ns_capable_common(struct user_namespace *ns, |
365 | int cap, | ||
366 | unsigned int opts) | ||
367 | { | 367 | { |
368 | int capable; | 368 | int capable; |
369 | 369 | ||
@@ -372,8 +372,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) | |||
372 | BUG(); | 372 | BUG(); |
373 | } | 373 | } |
374 | 374 | ||
375 | capable = audit ? security_capable(current_cred(), ns, cap) : | 375 | capable = security_capable(current_cred(), ns, cap, opts); |
376 | security_capable_noaudit(current_cred(), ns, cap); | ||
377 | if (capable == 0) { | 376 | if (capable == 0) { |
378 | current->flags |= PF_SUPERPRIV; | 377 | current->flags |= PF_SUPERPRIV; |
379 | return true; | 378 | return true; |
@@ -394,7 +393,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) | |||
394 | */ | 393 | */ |
395 | bool ns_capable(struct user_namespace *ns, int cap) | 394 | bool ns_capable(struct user_namespace *ns, int cap) |
396 | { | 395 | { |
397 | return ns_capable_common(ns, cap, true); | 396 | return ns_capable_common(ns, cap, CAP_OPT_NONE); |
398 | } | 397 | } |
399 | EXPORT_SYMBOL(ns_capable); | 398 | EXPORT_SYMBOL(ns_capable); |
400 | 399 | ||
@@ -412,11 +411,30 @@ EXPORT_SYMBOL(ns_capable); | |||
412 | */ | 411 | */ |
413 | bool ns_capable_noaudit(struct user_namespace *ns, int cap) | 412 | bool ns_capable_noaudit(struct user_namespace *ns, int cap) |
414 | { | 413 | { |
415 | return ns_capable_common(ns, cap, false); | 414 | return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT); |
416 | } | 415 | } |
417 | EXPORT_SYMBOL(ns_capable_noaudit); | 416 | EXPORT_SYMBOL(ns_capable_noaudit); |
418 | 417 | ||
419 | /** | 418 | /** |
419 | * ns_capable_setid - Determine if the current task has a superior capability | ||
420 | * in effect, while signalling that this check is being done from within a | ||
421 | * setid syscall. | ||
422 | * @ns: The usernamespace we want the capability in | ||
423 | * @cap: The capability to be tested for | ||
424 | * | ||
425 | * Return true if the current task has the given superior capability currently | ||
426 | * available for use, false if not. | ||
427 | * | ||
428 | * This sets PF_SUPERPRIV on the task if the capability is available on the | ||
429 | * assumption that it's about to be used. | ||
430 | */ | ||
431 | bool ns_capable_setid(struct user_namespace *ns, int cap) | ||
432 | { | ||
433 | return ns_capable_common(ns, cap, CAP_OPT_INSETID); | ||
434 | } | ||
435 | EXPORT_SYMBOL(ns_capable_setid); | ||
436 | |||
437 | /** | ||
420 | * capable - Determine if the current task has a superior capability in effect | 438 | * capable - Determine if the current task has a superior capability in effect |
421 | * @cap: The capability to be tested for | 439 | * @cap: The capability to be tested for |
422 | * | 440 | * |
@@ -448,10 +466,11 @@ EXPORT_SYMBOL(capable); | |||
448 | bool file_ns_capable(const struct file *file, struct user_namespace *ns, | 466 | bool file_ns_capable(const struct file *file, struct user_namespace *ns, |
449 | int cap) | 467 | int cap) |
450 | { | 468 | { |
469 | |||
451 | if (WARN_ON_ONCE(!cap_valid(cap))) | 470 | if (WARN_ON_ONCE(!cap_valid(cap))) |
452 | return false; | 471 | return false; |
453 | 472 | ||
454 | if (security_capable(file->f_cred, ns, cap) == 0) | 473 | if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE) == 0) |
455 | return true; | 474 | return true; |
456 | 475 | ||
457 | return false; | 476 | return false; |
@@ -500,10 +519,12 @@ bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns) | |||
500 | { | 519 | { |
501 | int ret = 0; /* An absent tracer adds no restrictions */ | 520 | int ret = 0; /* An absent tracer adds no restrictions */ |
502 | const struct cred *cred; | 521 | const struct cred *cred; |
522 | |||
503 | rcu_read_lock(); | 523 | rcu_read_lock(); |
504 | cred = rcu_dereference(tsk->ptracer_cred); | 524 | cred = rcu_dereference(tsk->ptracer_cred); |
505 | if (cred) | 525 | if (cred) |
506 | ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE); | 526 | ret = security_capable(cred, ns, CAP_SYS_PTRACE, |
527 | CAP_OPT_NOAUDIT); | ||
507 | rcu_read_unlock(); | 528 | rcu_read_unlock(); |
508 | return (ret == 0); | 529 | return (ret == 0); |
509 | } | 530 | } |
diff --git a/kernel/cred.c b/kernel/cred.c index 21f4a97085b4..45d77284aed0 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -760,19 +760,6 @@ bool creds_are_invalid(const struct cred *cred) | |||
760 | { | 760 | { |
761 | if (cred->magic != CRED_MAGIC) | 761 | if (cred->magic != CRED_MAGIC) |
762 | return true; | 762 | return true; |
763 | #ifdef CONFIG_SECURITY_SELINUX | ||
764 | /* | ||
765 | * cred->security == NULL if security_cred_alloc_blank() or | ||
766 | * security_prepare_creds() returned an error. | ||
767 | */ | ||
768 | if (selinux_is_enabled() && cred->security) { | ||
769 | if ((unsigned long) cred->security < PAGE_SIZE) | ||
770 | return true; | ||
771 | if ((*(u32 *)cred->security & 0xffffff00) == | ||
772 | (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) | ||
773 | return true; | ||
774 | } | ||
775 | #endif | ||
776 | return false; | 763 | return false; |
777 | } | 764 | } |
778 | EXPORT_SYMBOL(creds_are_invalid); | 765 | EXPORT_SYMBOL(creds_are_invalid); |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index a43c601ac252..54a0347ca812 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -445,8 +445,8 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) | |||
445 | * behavior of privileged children. | 445 | * behavior of privileged children. |
446 | */ | 446 | */ |
447 | if (!task_no_new_privs(current) && | 447 | if (!task_no_new_privs(current) && |
448 | security_capable_noaudit(current_cred(), current_user_ns(), | 448 | security_capable(current_cred(), current_user_ns(), |
449 | CAP_SYS_ADMIN) != 0) | 449 | CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0) |
450 | return ERR_PTR(-EACCES); | 450 | return ERR_PTR(-EACCES); |
451 | 451 | ||
452 | /* Allocate a new seccomp_filter */ | 452 | /* Allocate a new seccomp_filter */ |
diff --git a/kernel/sys.c b/kernel/sys.c index f7eb62eceb24..c5f875048aef 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -516,7 +516,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid) | |||
516 | new->uid = kruid; | 516 | new->uid = kruid; |
517 | if (!uid_eq(old->uid, kruid) && | 517 | if (!uid_eq(old->uid, kruid) && |
518 | !uid_eq(old->euid, kruid) && | 518 | !uid_eq(old->euid, kruid) && |
519 | !ns_capable(old->user_ns, CAP_SETUID)) | 519 | !ns_capable_setid(old->user_ns, CAP_SETUID)) |
520 | goto error; | 520 | goto error; |
521 | } | 521 | } |
522 | 522 | ||
@@ -525,7 +525,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid) | |||
525 | if (!uid_eq(old->uid, keuid) && | 525 | if (!uid_eq(old->uid, keuid) && |
526 | !uid_eq(old->euid, keuid) && | 526 | !uid_eq(old->euid, keuid) && |
527 | !uid_eq(old->suid, keuid) && | 527 | !uid_eq(old->suid, keuid) && |
528 | !ns_capable(old->user_ns, CAP_SETUID)) | 528 | !ns_capable_setid(old->user_ns, CAP_SETUID)) |
529 | goto error; | 529 | goto error; |
530 | } | 530 | } |
531 | 531 | ||
@@ -584,7 +584,7 @@ long __sys_setuid(uid_t uid) | |||
584 | old = current_cred(); | 584 | old = current_cred(); |
585 | 585 | ||
586 | retval = -EPERM; | 586 | retval = -EPERM; |
587 | if (ns_capable(old->user_ns, CAP_SETUID)) { | 587 | if (ns_capable_setid(old->user_ns, CAP_SETUID)) { |
588 | new->suid = new->uid = kuid; | 588 | new->suid = new->uid = kuid; |
589 | if (!uid_eq(kuid, old->uid)) { | 589 | if (!uid_eq(kuid, old->uid)) { |
590 | retval = set_user(new); | 590 | retval = set_user(new); |
@@ -646,7 +646,7 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | |||
646 | old = current_cred(); | 646 | old = current_cred(); |
647 | 647 | ||
648 | retval = -EPERM; | 648 | retval = -EPERM; |
649 | if (!ns_capable(old->user_ns, CAP_SETUID)) { | 649 | if (!ns_capable_setid(old->user_ns, CAP_SETUID)) { |
650 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && | 650 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
651 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) | 651 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) |
652 | goto error; | 652 | goto error; |
@@ -814,7 +814,7 @@ long __sys_setfsuid(uid_t uid) | |||
814 | 814 | ||
815 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || | 815 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || |
816 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || | 816 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || |
817 | ns_capable(old->user_ns, CAP_SETUID)) { | 817 | ns_capable_setid(old->user_ns, CAP_SETUID)) { |
818 | if (!uid_eq(kuid, old->fsuid)) { | 818 | if (!uid_eq(kuid, old->fsuid)) { |
819 | new->fsuid = kuid; | 819 | new->fsuid = kuid; |
820 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 820 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
diff --git a/security/Kconfig b/security/Kconfig index e4fe2f3c2c65..1d6463fb1450 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -40,8 +40,7 @@ config SECURITYFS | |||
40 | bool "Enable the securityfs filesystem" | 40 | bool "Enable the securityfs filesystem" |
41 | help | 41 | help |
42 | This will build the securityfs filesystem. It is currently used by | 42 | This will build the securityfs filesystem. It is currently used by |
43 | the TPM bios character driver and IMA, an integrity provider. It is | 43 | various security modules (AppArmor, IMA, SafeSetID, TOMOYO, TPM). |
44 | not used by SELinux or SMACK. | ||
45 | 44 | ||
46 | If you are unsure how to answer this question, answer N. | 45 | If you are unsure how to answer this question, answer N. |
47 | 46 | ||
@@ -236,45 +235,19 @@ source "security/tomoyo/Kconfig" | |||
236 | source "security/apparmor/Kconfig" | 235 | source "security/apparmor/Kconfig" |
237 | source "security/loadpin/Kconfig" | 236 | source "security/loadpin/Kconfig" |
238 | source "security/yama/Kconfig" | 237 | source "security/yama/Kconfig" |
238 | source "security/safesetid/Kconfig" | ||
239 | 239 | ||
240 | source "security/integrity/Kconfig" | 240 | source "security/integrity/Kconfig" |
241 | 241 | ||
242 | choice | 242 | config LSM |
243 | prompt "Default security module" | 243 | string "Ordered list of enabled LSMs" |
244 | default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX | 244 | default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" |
245 | default DEFAULT_SECURITY_SMACK if SECURITY_SMACK | ||
246 | default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO | ||
247 | default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR | ||
248 | default DEFAULT_SECURITY_DAC | ||
249 | |||
250 | help | 245 | help |
251 | Select the security module that will be used by default if the | 246 | A comma-separated list of LSMs, in initialization order. |
252 | kernel parameter security= is not specified. | 247 | Any LSMs left off this list will be ignored. This can be |
253 | 248 | controlled at boot with the "lsm=" parameter. | |
254 | config DEFAULT_SECURITY_SELINUX | ||
255 | bool "SELinux" if SECURITY_SELINUX=y | ||
256 | |||
257 | config DEFAULT_SECURITY_SMACK | ||
258 | bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y | ||
259 | |||
260 | config DEFAULT_SECURITY_TOMOYO | ||
261 | bool "TOMOYO" if SECURITY_TOMOYO=y | ||
262 | |||
263 | config DEFAULT_SECURITY_APPARMOR | ||
264 | bool "AppArmor" if SECURITY_APPARMOR=y | ||
265 | |||
266 | config DEFAULT_SECURITY_DAC | ||
267 | bool "Unix Discretionary Access Controls" | ||
268 | |||
269 | endchoice | ||
270 | 249 | ||
271 | config DEFAULT_SECURITY | 250 | If unsure, leave this as the default. |
272 | string | ||
273 | default "selinux" if DEFAULT_SECURITY_SELINUX | ||
274 | default "smack" if DEFAULT_SECURITY_SMACK | ||
275 | default "tomoyo" if DEFAULT_SECURITY_TOMOYO | ||
276 | default "apparmor" if DEFAULT_SECURITY_APPARMOR | ||
277 | default "" if DEFAULT_SECURITY_DAC | ||
278 | 251 | ||
279 | endmenu | 252 | endmenu |
280 | 253 | ||
diff --git a/security/Makefile b/security/Makefile index 4d2d3782ddef..c598b904938f 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo | |||
10 | subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor | 10 | subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor |
11 | subdir-$(CONFIG_SECURITY_YAMA) += yama | 11 | subdir-$(CONFIG_SECURITY_YAMA) += yama |
12 | subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin | 12 | subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin |
13 | subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid | ||
13 | 14 | ||
14 | # always enable default capabilities | 15 | # always enable default capabilities |
15 | obj-y += commoncap.o | 16 | obj-y += commoncap.o |
@@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ | |||
25 | obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ | 26 | obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ |
26 | obj-$(CONFIG_SECURITY_YAMA) += yama/ | 27 | obj-$(CONFIG_SECURITY_YAMA) += yama/ |
27 | obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ | 28 | obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ |
29 | obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ | ||
28 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 30 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
29 | 31 | ||
30 | # Object integrity file lists | 32 | # Object integrity file lists |
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index b6b68a7750ce..3de21f46c82a 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig | |||
@@ -14,22 +14,6 @@ config SECURITY_APPARMOR | |||
14 | 14 | ||
15 | If you are unsure how to answer this question, answer N. | 15 | If you are unsure how to answer this question, answer N. |
16 | 16 | ||
17 | config SECURITY_APPARMOR_BOOTPARAM_VALUE | ||
18 | int "AppArmor boot parameter default value" | ||
19 | depends on SECURITY_APPARMOR | ||
20 | range 0 1 | ||
21 | default 1 | ||
22 | help | ||
23 | This option sets the default value for the kernel parameter | ||
24 | 'apparmor', which allows AppArmor to be enabled or disabled | ||
25 | at boot. If this option is set to 0 (zero), the AppArmor | ||
26 | kernel parameter will default to 0, disabling AppArmor at | ||
27 | boot. If this option is set to 1 (one), the AppArmor | ||
28 | kernel parameter will default to 1, enabling AppArmor at | ||
29 | boot. | ||
30 | |||
31 | If you are unsure how to answer this question, answer 1. | ||
32 | |||
33 | config SECURITY_APPARMOR_HASH | 17 | config SECURITY_APPARMOR_HASH |
34 | bool "Enable introspection of sha1 hashes for loaded profiles" | 18 | bool "Enable introspection of sha1 hashes for loaded profiles" |
35 | depends on SECURITY_APPARMOR | 19 | depends on SECURITY_APPARMOR |
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 253ef6e9d445..752f73980e30 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c | |||
@@ -110,13 +110,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, | |||
110 | * profile_capable - test if profile allows use of capability @cap | 110 | * profile_capable - test if profile allows use of capability @cap |
111 | * @profile: profile being enforced (NOT NULL, NOT unconfined) | 111 | * @profile: profile being enforced (NOT NULL, NOT unconfined) |
112 | * @cap: capability to test if allowed | 112 | * @cap: capability to test if allowed |
113 | * @audit: whether an audit record should be generated | 113 | * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated |
114 | * @sa: audit data (MAY BE NULL indicating no auditing) | 114 | * @sa: audit data (MAY BE NULL indicating no auditing) |
115 | * | 115 | * |
116 | * Returns: 0 if allowed else -EPERM | 116 | * Returns: 0 if allowed else -EPERM |
117 | */ | 117 | */ |
118 | static int profile_capable(struct aa_profile *profile, int cap, int audit, | 118 | static int profile_capable(struct aa_profile *profile, int cap, |
119 | struct common_audit_data *sa) | 119 | unsigned int opts, struct common_audit_data *sa) |
120 | { | 120 | { |
121 | int error; | 121 | int error; |
122 | 122 | ||
@@ -126,7 +126,7 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit, | |||
126 | else | 126 | else |
127 | error = -EPERM; | 127 | error = -EPERM; |
128 | 128 | ||
129 | if (audit == SECURITY_CAP_NOAUDIT) { | 129 | if (opts & CAP_OPT_NOAUDIT) { |
130 | if (!COMPLAIN_MODE(profile)) | 130 | if (!COMPLAIN_MODE(profile)) |
131 | return error; | 131 | return error; |
132 | /* audit the cap request in complain mode but note that it | 132 | /* audit the cap request in complain mode but note that it |
@@ -142,13 +142,13 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit, | |||
142 | * aa_capable - test permission to use capability | 142 | * aa_capable - test permission to use capability |
143 | * @label: label being tested for capability (NOT NULL) | 143 | * @label: label being tested for capability (NOT NULL) |
144 | * @cap: capability to be tested | 144 | * @cap: capability to be tested |
145 | * @audit: whether an audit record should be generated | 145 | * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated |
146 | * | 146 | * |
147 | * Look up capability in profile capability set. | 147 | * Look up capability in profile capability set. |
148 | * | 148 | * |
149 | * Returns: 0 on success, or else an error code. | 149 | * Returns: 0 on success, or else an error code. |
150 | */ | 150 | */ |
151 | int aa_capable(struct aa_label *label, int cap, int audit) | 151 | int aa_capable(struct aa_label *label, int cap, unsigned int opts) |
152 | { | 152 | { |
153 | struct aa_profile *profile; | 153 | struct aa_profile *profile; |
154 | int error = 0; | 154 | int error = 0; |
@@ -156,7 +156,7 @@ int aa_capable(struct aa_label *label, int cap, int audit) | |||
156 | 156 | ||
157 | sa.u.cap = cap; | 157 | sa.u.cap = cap; |
158 | error = fn_for_each_confined(label, profile, | 158 | error = fn_for_each_confined(label, profile, |
159 | profile_capable(profile, cap, audit, &sa)); | 159 | profile_capable(profile, cap, opts, &sa)); |
160 | 160 | ||
161 | return error; | 161 | return error; |
162 | } | 162 | } |
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 11975ec8d566..ca2dccf5b445 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -572,7 +572,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile, | |||
572 | stack = NULL; | 572 | stack = NULL; |
573 | break; | 573 | break; |
574 | } | 574 | } |
575 | /* fall through to X_NAME */ | 575 | /* fall through - to X_NAME */ |
576 | case AA_X_NAME: | 576 | case AA_X_NAME: |
577 | if (xindex & AA_X_CHILD) | 577 | if (xindex & AA_X_CHILD) |
578 | /* released by caller */ | 578 | /* released by caller */ |
@@ -975,7 +975,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
975 | } | 975 | } |
976 | aa_put_label(cred_label(bprm->cred)); | 976 | aa_put_label(cred_label(bprm->cred)); |
977 | /* transfer reference, released when cred is freed */ | 977 | /* transfer reference, released when cred is freed */ |
978 | cred_label(bprm->cred) = new; | 978 | set_cred_label(bprm->cred, new); |
979 | 979 | ||
980 | done: | 980 | done: |
981 | aa_put_label(label); | 981 | aa_put_label(label); |
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h index e0304e2aeb7f..1b3663b6ab12 100644 --- a/security/apparmor/include/capability.h +++ b/security/apparmor/include/capability.h | |||
@@ -40,7 +40,7 @@ struct aa_caps { | |||
40 | 40 | ||
41 | extern struct aa_sfs_entry aa_sfs_entry_caps[]; | 41 | extern struct aa_sfs_entry aa_sfs_entry_caps[]; |
42 | 42 | ||
43 | int aa_capable(struct aa_label *label, int cap, int audit); | 43 | int aa_capable(struct aa_label *label, int cap, unsigned int opts); |
44 | 44 | ||
45 | static inline void aa_free_cap_rules(struct aa_caps *caps) | 45 | static inline void aa_free_cap_rules(struct aa_caps *caps) |
46 | { | 46 | { |
diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h index 265ae6641a06..b9504a05fddc 100644 --- a/security/apparmor/include/cred.h +++ b/security/apparmor/include/cred.h | |||
@@ -23,8 +23,22 @@ | |||
23 | #include "policy_ns.h" | 23 | #include "policy_ns.h" |
24 | #include "task.h" | 24 | #include "task.h" |
25 | 25 | ||
26 | #define cred_label(X) ((X)->security) | 26 | static inline struct aa_label *cred_label(const struct cred *cred) |
27 | { | ||
28 | struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; | ||
29 | |||
30 | AA_BUG(!blob); | ||
31 | return *blob; | ||
32 | } | ||
27 | 33 | ||
34 | static inline void set_cred_label(const struct cred *cred, | ||
35 | struct aa_label *label) | ||
36 | { | ||
37 | struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; | ||
38 | |||
39 | AA_BUG(!blob); | ||
40 | *blob = label; | ||
41 | } | ||
28 | 42 | ||
29 | /** | 43 | /** |
30 | * aa_cred_raw_label - obtain cred's label | 44 | * aa_cred_raw_label - obtain cred's label |
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 4c2c8ac8842f..8be09208cf7c 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h | |||
@@ -32,7 +32,10 @@ struct path; | |||
32 | AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \ | 32 | AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \ |
33 | AA_EXEC_MMAP | AA_MAY_LINK) | 33 | AA_EXEC_MMAP | AA_MAY_LINK) |
34 | 34 | ||
35 | #define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security) | 35 | static inline struct aa_file_ctx *file_ctx(struct file *file) |
36 | { | ||
37 | return file->f_security + apparmor_blob_sizes.lbs_file; | ||
38 | } | ||
36 | 39 | ||
37 | /* struct aa_file_ctx - the AppArmor context the file was opened in | 40 | /* struct aa_file_ctx - the AppArmor context the file was opened in |
38 | * @lock: lock to update the ctx | 41 | * @lock: lock to update the ctx |
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 6505e1ad9e23..bbe9b384d71d 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/lsm_hooks.h> | ||
19 | 20 | ||
20 | #include "match.h" | 21 | #include "match.h" |
21 | 22 | ||
@@ -55,6 +56,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, | |||
55 | size_t *ns_len); | 56 | size_t *ns_len); |
56 | void aa_info_message(const char *str); | 57 | void aa_info_message(const char *str); |
57 | 58 | ||
59 | /* Security blob offsets */ | ||
60 | extern struct lsm_blob_sizes apparmor_blob_sizes; | ||
61 | |||
58 | /** | 62 | /** |
59 | * aa_strneq - compare null terminated @str to a non null terminated substring | 63 | * aa_strneq - compare null terminated @str to a non null terminated substring |
60 | * @str: a null terminated string | 64 | * @str: a null terminated string |
diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index 55edaa1d83f8..311e652324e3 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h | |||
@@ -14,7 +14,10 @@ | |||
14 | #ifndef __AA_TASK_H | 14 | #ifndef __AA_TASK_H |
15 | #define __AA_TASK_H | 15 | #define __AA_TASK_H |
16 | 16 | ||
17 | #define task_ctx(X) ((X)->security) | 17 | static inline struct aa_task_ctx *task_ctx(struct task_struct *task) |
18 | { | ||
19 | return task->security + apparmor_blob_sizes.lbs_task; | ||
20 | } | ||
18 | 21 | ||
19 | /* | 22 | /* |
20 | * struct aa_task_ctx - information for current task label change | 23 | * struct aa_task_ctx - information for current task label change |
@@ -37,17 +40,6 @@ int aa_restore_previous_label(u64 cookie); | |||
37 | struct aa_label *aa_get_task_label(struct task_struct *task); | 40 | struct aa_label *aa_get_task_label(struct task_struct *task); |
38 | 41 | ||
39 | /** | 42 | /** |
40 | * aa_alloc_task_ctx - allocate a new task_ctx | ||
41 | * @flags: gfp flags for allocation | ||
42 | * | ||
43 | * Returns: allocated buffer or NULL on failure | ||
44 | */ | ||
45 | static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags) | ||
46 | { | ||
47 | return kzalloc(sizeof(struct aa_task_ctx), flags); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * aa_free_task_ctx - free a task_ctx | 43 | * aa_free_task_ctx - free a task_ctx |
52 | * @ctx: task_ctx to free (MAYBE NULL) | 44 | * @ctx: task_ctx to free (MAYBE NULL) |
53 | */ | 45 | */ |
@@ -57,8 +49,6 @@ static inline void aa_free_task_ctx(struct aa_task_ctx *ctx) | |||
57 | aa_put_label(ctx->nnp); | 49 | aa_put_label(ctx->nnp); |
58 | aa_put_label(ctx->previous); | 50 | aa_put_label(ctx->previous); |
59 | aa_put_label(ctx->onexec); | 51 | aa_put_label(ctx->onexec); |
60 | |||
61 | kzfree(ctx); | ||
62 | } | 52 | } |
63 | } | 53 | } |
64 | 54 | ||
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 527ea1557120..aacd1e95cb59 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c | |||
@@ -107,7 +107,8 @@ static int profile_tracer_perm(struct aa_profile *tracer, | |||
107 | aad(sa)->label = &tracer->label; | 107 | aad(sa)->label = &tracer->label; |
108 | aad(sa)->peer = tracee; | 108 | aad(sa)->peer = tracee; |
109 | aad(sa)->request = 0; | 109 | aad(sa)->request = 0; |
110 | aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); | 110 | aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, |
111 | CAP_OPT_NONE); | ||
111 | 112 | ||
112 | return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); | 113 | return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); |
113 | } | 114 | } |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8db1731d046a..49d664ddff44 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -60,7 +60,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers); | |||
60 | static void apparmor_cred_free(struct cred *cred) | 60 | static void apparmor_cred_free(struct cred *cred) |
61 | { | 61 | { |
62 | aa_put_label(cred_label(cred)); | 62 | aa_put_label(cred_label(cred)); |
63 | cred_label(cred) = NULL; | 63 | set_cred_label(cred, NULL); |
64 | } | 64 | } |
65 | 65 | ||
66 | /* | 66 | /* |
@@ -68,7 +68,7 @@ static void apparmor_cred_free(struct cred *cred) | |||
68 | */ | 68 | */ |
69 | static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) | 69 | static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) |
70 | { | 70 | { |
71 | cred_label(cred) = NULL; | 71 | set_cred_label(cred, NULL); |
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
@@ -78,7 +78,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) | |||
78 | static int apparmor_cred_prepare(struct cred *new, const struct cred *old, | 78 | static int apparmor_cred_prepare(struct cred *new, const struct cred *old, |
79 | gfp_t gfp) | 79 | gfp_t gfp) |
80 | { | 80 | { |
81 | cred_label(new) = aa_get_newest_label(cred_label(old)); | 81 | set_cred_label(new, aa_get_newest_label(cred_label(old))); |
82 | return 0; | 82 | return 0; |
83 | } | 83 | } |
84 | 84 | ||
@@ -87,26 +87,21 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, | |||
87 | */ | 87 | */ |
88 | static void apparmor_cred_transfer(struct cred *new, const struct cred *old) | 88 | static void apparmor_cred_transfer(struct cred *new, const struct cred *old) |
89 | { | 89 | { |
90 | cred_label(new) = aa_get_newest_label(cred_label(old)); | 90 | set_cred_label(new, aa_get_newest_label(cred_label(old))); |
91 | } | 91 | } |
92 | 92 | ||
93 | static void apparmor_task_free(struct task_struct *task) | 93 | static void apparmor_task_free(struct task_struct *task) |
94 | { | 94 | { |
95 | 95 | ||
96 | aa_free_task_ctx(task_ctx(task)); | 96 | aa_free_task_ctx(task_ctx(task)); |
97 | task_ctx(task) = NULL; | ||
98 | } | 97 | } |
99 | 98 | ||
100 | static int apparmor_task_alloc(struct task_struct *task, | 99 | static int apparmor_task_alloc(struct task_struct *task, |
101 | unsigned long clone_flags) | 100 | unsigned long clone_flags) |
102 | { | 101 | { |
103 | struct aa_task_ctx *new = aa_alloc_task_ctx(GFP_KERNEL); | 102 | struct aa_task_ctx *new = task_ctx(task); |
104 | |||
105 | if (!new) | ||
106 | return -ENOMEM; | ||
107 | 103 | ||
108 | aa_dup_task_ctx(new, task_ctx(current)); | 104 | aa_dup_task_ctx(new, task_ctx(current)); |
109 | task_ctx(task) = new; | ||
110 | 105 | ||
111 | return 0; | 106 | return 0; |
112 | } | 107 | } |
@@ -177,14 +172,14 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, | |||
177 | } | 172 | } |
178 | 173 | ||
179 | static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, | 174 | static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, |
180 | int cap, int audit) | 175 | int cap, unsigned int opts) |
181 | { | 176 | { |
182 | struct aa_label *label; | 177 | struct aa_label *label; |
183 | int error = 0; | 178 | int error = 0; |
184 | 179 | ||
185 | label = aa_get_newest_cred_label(cred); | 180 | label = aa_get_newest_cred_label(cred); |
186 | if (!unconfined(label)) | 181 | if (!unconfined(label)) |
187 | error = aa_capable(label, cap, audit); | 182 | error = aa_capable(label, cap, opts); |
188 | aa_put_label(label); | 183 | aa_put_label(label); |
189 | 184 | ||
190 | return error; | 185 | return error; |
@@ -434,21 +429,21 @@ static int apparmor_file_open(struct file *file) | |||
434 | 429 | ||
435 | static int apparmor_file_alloc_security(struct file *file) | 430 | static int apparmor_file_alloc_security(struct file *file) |
436 | { | 431 | { |
437 | int error = 0; | 432 | struct aa_file_ctx *ctx = file_ctx(file); |
438 | |||
439 | /* freed by apparmor_file_free_security */ | ||
440 | struct aa_label *label = begin_current_label_crit_section(); | 433 | struct aa_label *label = begin_current_label_crit_section(); |
441 | file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL); | ||
442 | if (!file_ctx(file)) | ||
443 | error = -ENOMEM; | ||
444 | end_current_label_crit_section(label); | ||
445 | 434 | ||
446 | return error; | 435 | spin_lock_init(&ctx->lock); |
436 | rcu_assign_pointer(ctx->label, aa_get_label(label)); | ||
437 | end_current_label_crit_section(label); | ||
438 | return 0; | ||
447 | } | 439 | } |
448 | 440 | ||
449 | static void apparmor_file_free_security(struct file *file) | 441 | static void apparmor_file_free_security(struct file *file) |
450 | { | 442 | { |
451 | aa_free_file_ctx(file_ctx(file)); | 443 | struct aa_file_ctx *ctx = file_ctx(file); |
444 | |||
445 | if (ctx) | ||
446 | aa_put_label(rcu_access_pointer(ctx->label)); | ||
452 | } | 447 | } |
453 | 448 | ||
454 | static int common_file_perm(const char *op, struct file *file, u32 mask) | 449 | static int common_file_perm(const char *op, struct file *file, u32 mask) |
@@ -1151,6 +1146,15 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
1151 | } | 1146 | } |
1152 | #endif | 1147 | #endif |
1153 | 1148 | ||
1149 | /* | ||
1150 | * The cred blob is a pointer to, not an instance of, an aa_task_ctx. | ||
1151 | */ | ||
1152 | struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { | ||
1153 | .lbs_cred = sizeof(struct aa_task_ctx *), | ||
1154 | .lbs_file = sizeof(struct aa_file_ctx), | ||
1155 | .lbs_task = sizeof(struct aa_task_ctx), | ||
1156 | }; | ||
1157 | |||
1154 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | 1158 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { |
1155 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), | 1159 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), |
1156 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), | 1160 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), |
@@ -1333,8 +1337,8 @@ bool aa_g_paranoid_load = true; | |||
1333 | module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); | 1337 | module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); |
1334 | 1338 | ||
1335 | /* Boot time disable flag */ | 1339 | /* Boot time disable flag */ |
1336 | static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; | 1340 | static int apparmor_enabled __lsm_ro_after_init = 1; |
1337 | module_param_named(enabled, apparmor_enabled, bool, S_IRUGO); | 1341 | module_param_named(enabled, apparmor_enabled, int, 0444); |
1338 | 1342 | ||
1339 | static int __init apparmor_enabled_setup(char *str) | 1343 | static int __init apparmor_enabled_setup(char *str) |
1340 | { | 1344 | { |
@@ -1479,14 +1483,8 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) | |||
1479 | static int __init set_init_ctx(void) | 1483 | static int __init set_init_ctx(void) |
1480 | { | 1484 | { |
1481 | struct cred *cred = (struct cred *)current->real_cred; | 1485 | struct cred *cred = (struct cred *)current->real_cred; |
1482 | struct aa_task_ctx *ctx; | ||
1483 | |||
1484 | ctx = aa_alloc_task_ctx(GFP_KERNEL); | ||
1485 | if (!ctx) | ||
1486 | return -ENOMEM; | ||
1487 | 1486 | ||
1488 | cred_label(cred) = aa_get_label(ns_unconfined(root_ns)); | 1487 | set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); |
1489 | task_ctx(current) = ctx; | ||
1490 | 1488 | ||
1491 | return 0; | 1489 | return 0; |
1492 | } | 1490 | } |
@@ -1665,12 +1663,6 @@ static int __init apparmor_init(void) | |||
1665 | { | 1663 | { |
1666 | int error; | 1664 | int error; |
1667 | 1665 | ||
1668 | if (!apparmor_enabled || !security_module_enable("apparmor")) { | ||
1669 | aa_info_message("AppArmor disabled by boot time parameter"); | ||
1670 | apparmor_enabled = false; | ||
1671 | return 0; | ||
1672 | } | ||
1673 | |||
1674 | aa_secids_init(); | 1666 | aa_secids_init(); |
1675 | 1667 | ||
1676 | error = aa_setup_dfa_engine(); | 1668 | error = aa_setup_dfa_engine(); |
@@ -1731,5 +1723,8 @@ alloc_out: | |||
1731 | 1723 | ||
1732 | DEFINE_LSM(apparmor) = { | 1724 | DEFINE_LSM(apparmor) = { |
1733 | .name = "apparmor", | 1725 | .name = "apparmor", |
1726 | .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, | ||
1727 | .enabled = &apparmor_enabled, | ||
1728 | .blobs = &apparmor_blob_sizes, | ||
1734 | .init = apparmor_init, | 1729 | .init = apparmor_init, |
1735 | }; | 1730 | }; |
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 95fd26d09757..552ed09cb47e 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c | |||
@@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, | |||
124 | */ | 124 | */ |
125 | 125 | ||
126 | if (label != peer && | 126 | if (label != peer && |
127 | aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0) | 127 | aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0) |
128 | error = fn_for_each(label, profile, | 128 | error = fn_for_each(label, profile, |
129 | audit_resource(profile, resource, | 129 | audit_resource(profile, resource, |
130 | new_rlim->rlim_max, peer, | 130 | new_rlim->rlim_max, peer, |
diff --git a/security/apparmor/task.c b/security/apparmor/task.c index c6b78a14da91..4551110f0496 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c | |||
@@ -81,7 +81,7 @@ int aa_replace_current_label(struct aa_label *label) | |||
81 | */ | 81 | */ |
82 | aa_get_label(label); | 82 | aa_get_label(label); |
83 | aa_put_label(cred_label(new)); | 83 | aa_put_label(cred_label(new)); |
84 | cred_label(new) = label; | 84 | set_cred_label(new, label); |
85 | 85 | ||
86 | commit_creds(new); | 86 | commit_creds(new); |
87 | return 0; | 87 | return 0; |
@@ -138,7 +138,7 @@ int aa_set_current_hat(struct aa_label *label, u64 token) | |||
138 | return -EACCES; | 138 | return -EACCES; |
139 | } | 139 | } |
140 | 140 | ||
141 | cred_label(new) = aa_get_newest_label(label); | 141 | set_cred_label(new, aa_get_newest_label(label)); |
142 | /* clear exec on switching context */ | 142 | /* clear exec on switching context */ |
143 | aa_put_label(ctx->onexec); | 143 | aa_put_label(ctx->onexec); |
144 | ctx->onexec = NULL; | 144 | ctx->onexec = NULL; |
@@ -172,7 +172,7 @@ int aa_restore_previous_label(u64 token) | |||
172 | return -ENOMEM; | 172 | return -ENOMEM; |
173 | 173 | ||
174 | aa_put_label(cred_label(new)); | 174 | aa_put_label(cred_label(new)); |
175 | cred_label(new) = aa_get_newest_label(ctx->previous); | 175 | set_cred_label(new, aa_get_newest_label(ctx->previous)); |
176 | AA_BUG(!cred_label(new)); | 176 | AA_BUG(!cred_label(new)); |
177 | /* clear exec && prev information when restoring to previous context */ | 177 | /* clear exec && prev information when restoring to previous context */ |
178 | aa_clear_task_ctx_trans(ctx); | 178 | aa_clear_task_ctx_trans(ctx); |
diff --git a/security/commoncap.c b/security/commoncap.c index 232db019f051..f1d117c3d8ae 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -57,7 +57,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname) | |||
57 | * @cred: The credentials to use | 57 | * @cred: The credentials to use |
58 | * @ns: The user namespace in which we need the capability | 58 | * @ns: The user namespace in which we need the capability |
59 | * @cap: The capability to check for | 59 | * @cap: The capability to check for |
60 | * @audit: Whether to write an audit message or not | 60 | * @opts: Bitmask of options defined in include/linux/security.h |
61 | * | 61 | * |
62 | * Determine whether the nominated task has the specified capability amongst | 62 | * Determine whether the nominated task has the specified capability amongst |
63 | * its effective set, returning 0 if it does, -ve if it does not. | 63 | * its effective set, returning 0 if it does, -ve if it does not. |
@@ -68,7 +68,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname) | |||
68 | * kernel's capable() and has_capability() returns 1 for this case. | 68 | * kernel's capable() and has_capability() returns 1 for this case. |
69 | */ | 69 | */ |
70 | int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | 70 | int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, |
71 | int cap, int audit) | 71 | int cap, unsigned int opts) |
72 | { | 72 | { |
73 | struct user_namespace *ns = targ_ns; | 73 | struct user_namespace *ns = targ_ns; |
74 | 74 | ||
@@ -222,12 +222,11 @@ int cap_capget(struct task_struct *target, kernel_cap_t *effective, | |||
222 | */ | 222 | */ |
223 | static inline int cap_inh_is_capped(void) | 223 | static inline int cap_inh_is_capped(void) |
224 | { | 224 | { |
225 | |||
226 | /* they are so limited unless the current task has the CAP_SETPCAP | 225 | /* they are so limited unless the current task has the CAP_SETPCAP |
227 | * capability | 226 | * capability |
228 | */ | 227 | */ |
229 | if (cap_capable(current_cred(), current_cred()->user_ns, | 228 | if (cap_capable(current_cred(), current_cred()->user_ns, |
230 | CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) | 229 | CAP_SETPCAP, CAP_OPT_NONE) == 0) |
231 | return 0; | 230 | return 0; |
232 | return 1; | 231 | return 1; |
233 | } | 232 | } |
@@ -1208,8 +1207,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1208 | || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | 1207 | || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
1209 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 1208 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
1210 | || (cap_capable(current_cred(), | 1209 | || (cap_capable(current_cred(), |
1211 | current_cred()->user_ns, CAP_SETPCAP, | 1210 | current_cred()->user_ns, |
1212 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ | 1211 | CAP_SETPCAP, |
1212 | CAP_OPT_NONE) != 0) /*[4]*/ | ||
1213 | /* | 1213 | /* |
1214 | * [1] no changing of bits that are locked | 1214 | * [1] no changing of bits that are locked |
1215 | * [2] no unlocking of locks | 1215 | * [2] no unlocking of locks |
@@ -1304,9 +1304,10 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) | |||
1304 | { | 1304 | { |
1305 | int cap_sys_admin = 0; | 1305 | int cap_sys_admin = 0; |
1306 | 1306 | ||
1307 | if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, | 1307 | if (cap_capable(current_cred(), &init_user_ns, |
1308 | SECURITY_CAP_NOAUDIT) == 0) | 1308 | CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0) |
1309 | cap_sys_admin = 1; | 1309 | cap_sys_admin = 1; |
1310 | |||
1310 | return cap_sys_admin; | 1311 | return cap_sys_admin; |
1311 | } | 1312 | } |
1312 | 1313 | ||
@@ -1325,7 +1326,7 @@ int cap_mmap_addr(unsigned long addr) | |||
1325 | 1326 | ||
1326 | if (addr < dac_mmap_min_addr) { | 1327 | if (addr < dac_mmap_min_addr) { |
1327 | ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, | 1328 | ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, |
1328 | SECURITY_CAP_AUDIT); | 1329 | CAP_OPT_NONE); |
1329 | /* set PF_SUPERPRIV if it turns out we allow the low mmap */ | 1330 | /* set PF_SUPERPRIV if it turns out we allow the low mmap */ |
1330 | if (ret == 0) | 1331 | if (ret == 0) |
1331 | current->flags |= PF_SUPERPRIV; | 1332 | current->flags |= PF_SUPERPRIV; |
@@ -1362,10 +1363,17 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = { | |||
1362 | LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory), | 1363 | LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory), |
1363 | }; | 1364 | }; |
1364 | 1365 | ||
1365 | void __init capability_add_hooks(void) | 1366 | static int __init capability_init(void) |
1366 | { | 1367 | { |
1367 | security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks), | 1368 | security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks), |
1368 | "capability"); | 1369 | "capability"); |
1370 | return 0; | ||
1369 | } | 1371 | } |
1370 | 1372 | ||
1373 | DEFINE_LSM(capability) = { | ||
1374 | .name = "capability", | ||
1375 | .order = LSM_ORDER_FIRST, | ||
1376 | .init = capability_init, | ||
1377 | }; | ||
1378 | |||
1371 | #endif /* CONFIG_SECURITY */ | 1379 | #endif /* CONFIG_SECURITY */ |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index a2baa85ea2f5..5fb7127bbe68 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -114,6 +114,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, | |||
114 | break; | 114 | break; |
115 | case CREDS_CHECK: | 115 | case CREDS_CHECK: |
116 | iint->ima_creds_status = status; | 116 | iint->ima_creds_status = status; |
117 | break; | ||
117 | case FILE_CHECK: | 118 | case FILE_CHECK: |
118 | case POST_SETATTR: | 119 | case POST_SETATTR: |
119 | iint->ima_file_status = status; | 120 | iint->ima_file_status = status; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 8bc8a1c8cb3f..122797023bdb 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -938,10 +938,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
938 | case Opt_uid_gt: | 938 | case Opt_uid_gt: |
939 | case Opt_euid_gt: | 939 | case Opt_euid_gt: |
940 | entry->uid_op = &uid_gt; | 940 | entry->uid_op = &uid_gt; |
941 | /* fall through */ | ||
941 | case Opt_uid_lt: | 942 | case Opt_uid_lt: |
942 | case Opt_euid_lt: | 943 | case Opt_euid_lt: |
943 | if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) | 944 | if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) |
944 | entry->uid_op = &uid_lt; | 945 | entry->uid_op = &uid_lt; |
946 | /* fall through */ | ||
945 | case Opt_uid_eq: | 947 | case Opt_uid_eq: |
946 | case Opt_euid_eq: | 948 | case Opt_euid_eq: |
947 | uid_token = (token == Opt_uid_eq) || | 949 | uid_token = (token == Opt_uid_eq) || |
@@ -970,9 +972,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
970 | break; | 972 | break; |
971 | case Opt_fowner_gt: | 973 | case Opt_fowner_gt: |
972 | entry->fowner_op = &uid_gt; | 974 | entry->fowner_op = &uid_gt; |
975 | /* fall through */ | ||
973 | case Opt_fowner_lt: | 976 | case Opt_fowner_lt: |
974 | if (token == Opt_fowner_lt) | 977 | if (token == Opt_fowner_lt) |
975 | entry->fowner_op = &uid_lt; | 978 | entry->fowner_op = &uid_lt; |
979 | /* fall through */ | ||
976 | case Opt_fowner_eq: | 980 | case Opt_fowner_eq: |
977 | ima_log_string_op(ab, "fowner", args[0].from, | 981 | ima_log_string_op(ab, "fowner", args[0].from, |
978 | entry->fowner_op); | 982 | entry->fowner_op); |
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 43752002c222..513b457ae900 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c | |||
@@ -83,6 +83,7 @@ static void ima_show_template_data_ascii(struct seq_file *m, | |||
83 | /* skip ':' and '\0' */ | 83 | /* skip ':' and '\0' */ |
84 | buf_ptr += 2; | 84 | buf_ptr += 2; |
85 | buflen -= buf_ptr - field_data->data; | 85 | buflen -= buf_ptr - field_data->data; |
86 | /* fall through */ | ||
86 | case DATA_FMT_DIGEST: | 87 | case DATA_FMT_DIGEST: |
87 | case DATA_FMT_HEX: | 88 | case DATA_FMT_HEX: |
88 | if (!buflen) | 89 | if (!buflen) |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 7bbe03593e58..3e4053a217c3 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1752,7 +1752,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1752 | return -EINVAL; | 1752 | return -EINVAL; |
1753 | return keyctl_pkey_query((key_serial_t)arg2, | 1753 | return keyctl_pkey_query((key_serial_t)arg2, |
1754 | (const char __user *)arg4, | 1754 | (const char __user *)arg4, |
1755 | (struct keyctl_pkey_query *)arg5); | 1755 | (struct keyctl_pkey_query __user *)arg5); |
1756 | 1756 | ||
1757 | case KEYCTL_PKEY_ENCRYPT: | 1757 | case KEYCTL_PKEY_ENCRYPT: |
1758 | case KEYCTL_PKEY_DECRYPT: | 1758 | case KEYCTL_PKEY_DECRYPT: |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index f81372f53dd7..e14f09e3a4b0 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -246,6 +246,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level) | |||
246 | (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8)); | 246 | (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8)); |
247 | n--; | 247 | n--; |
248 | offset = 1; | 248 | offset = 1; |
249 | /* fall through */ | ||
249 | default: | 250 | default: |
250 | offset += sizeof(chunk) - 1; | 251 | offset += sizeof(chunk) - 1; |
251 | offset += (level - 3) * sizeof(chunk); | 252 | offset += (level - 3) * sizeof(chunk); |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 0e0b9ccad2f8..9320424c4a46 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -380,6 +380,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) | |||
380 | case -EAGAIN: /* no key */ | 380 | case -EAGAIN: /* no key */ |
381 | if (ret) | 381 | if (ret) |
382 | break; | 382 | break; |
383 | /* fall through */ | ||
383 | case -ENOKEY: /* negative key */ | 384 | case -ENOKEY: /* negative key */ |
384 | ret = key_ref; | 385 | ret = key_ref; |
385 | break; | 386 | break; |
@@ -404,6 +405,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) | |||
404 | case -EAGAIN: /* no key */ | 405 | case -EAGAIN: /* no key */ |
405 | if (ret) | 406 | if (ret) |
406 | break; | 407 | break; |
408 | /* fall through */ | ||
407 | case -ENOKEY: /* negative key */ | 409 | case -ENOKEY: /* negative key */ |
408 | ret = key_ref; | 410 | ret = key_ref; |
409 | break; | 411 | break; |
@@ -424,6 +426,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) | |||
424 | case -EAGAIN: /* no key */ | 426 | case -EAGAIN: /* no key */ |
425 | if (ret) | 427 | if (ret) |
426 | break; | 428 | break; |
429 | /* fall through */ | ||
427 | case -ENOKEY: /* negative key */ | 430 | case -ENOKEY: /* negative key */ |
428 | ret = key_ref; | 431 | ret = key_ref; |
429 | break; | 432 | break; |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 7a0c6b666ff0..2f17d84d46f1 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -273,16 +273,19 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) | |||
273 | } | 273 | } |
274 | } | 274 | } |
275 | 275 | ||
276 | /* fall through */ | ||
276 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | 277 | case KEY_REQKEY_DEFL_THREAD_KEYRING: |
277 | dest_keyring = key_get(cred->thread_keyring); | 278 | dest_keyring = key_get(cred->thread_keyring); |
278 | if (dest_keyring) | 279 | if (dest_keyring) |
279 | break; | 280 | break; |
280 | 281 | ||
282 | /* fall through */ | ||
281 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | 283 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
282 | dest_keyring = key_get(cred->process_keyring); | 284 | dest_keyring = key_get(cred->process_keyring); |
283 | if (dest_keyring) | 285 | if (dest_keyring) |
284 | break; | 286 | break; |
285 | 287 | ||
288 | /* fall through */ | ||
286 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | 289 | case KEY_REQKEY_DEFL_SESSION_KEYRING: |
287 | rcu_read_lock(); | 290 | rcu_read_lock(); |
288 | dest_keyring = key_get( | 291 | dest_keyring = key_get( |
@@ -292,6 +295,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) | |||
292 | if (dest_keyring) | 295 | if (dest_keyring) |
293 | break; | 296 | break; |
294 | 297 | ||
298 | /* fall through */ | ||
295 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | 299 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: |
296 | dest_keyring = | 300 | dest_keyring = |
297 | key_get(cred->user->session_keyring); | 301 | key_get(cred->user->session_keyring); |
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 48f39631b370..055fb0a64169 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c | |||
@@ -187,13 +187,19 @@ static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { | |||
187 | LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), | 187 | LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), |
188 | }; | 188 | }; |
189 | 189 | ||
190 | void __init loadpin_add_hooks(void) | 190 | static int __init loadpin_init(void) |
191 | { | 191 | { |
192 | pr_info("ready to pin (currently %senforcing)\n", | 192 | pr_info("ready to pin (currently %senforcing)\n", |
193 | enforce ? "" : "not "); | 193 | enforce ? "" : "not "); |
194 | security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); | 194 | security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); |
195 | return 0; | ||
195 | } | 196 | } |
196 | 197 | ||
198 | DEFINE_LSM(loadpin) = { | ||
199 | .name = "loadpin", | ||
200 | .init = loadpin_init, | ||
201 | }; | ||
202 | |||
197 | /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ | 203 | /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ |
198 | module_param(enforce, int, 0); | 204 | module_param(enforce, int, 0); |
199 | MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning"); | 205 | MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning"); |
diff --git a/security/safesetid/Kconfig b/security/safesetid/Kconfig new file mode 100644 index 000000000000..4f415c4e3f93 --- /dev/null +++ b/security/safesetid/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | config SECURITY_SAFESETID | ||
2 | bool "Gate setid transitions to limit CAP_SET{U/G}ID capabilities" | ||
3 | depends on SECURITY | ||
4 | select SECURITYFS | ||
5 | default n | ||
6 | help | ||
7 | SafeSetID is an LSM module that gates the setid family of syscalls to | ||
8 | restrict UID/GID transitions from a given UID/GID to only those | ||
9 | approved by a system-wide whitelist. These restrictions also prohibit | ||
10 | the given UIDs/GIDs from obtaining auxiliary privileges associated | ||
11 | with CAP_SET{U/G}ID, such as allowing a user to set up user namespace | ||
12 | UID mappings. | ||
13 | |||
14 | If you are unsure how to answer this question, answer N. | ||
diff --git a/security/safesetid/Makefile b/security/safesetid/Makefile new file mode 100644 index 000000000000..6b0660321164 --- /dev/null +++ b/security/safesetid/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | # | ||
3 | # Makefile for the safesetid LSM. | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_SECURITY_SAFESETID) := safesetid.o | ||
7 | safesetid-y := lsm.o securityfs.o | ||
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c new file mode 100644 index 000000000000..cecd38e2ac80 --- /dev/null +++ b/security/safesetid/lsm.c | |||
@@ -0,0 +1,277 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * SafeSetID Linux Security Module | ||
4 | * | ||
5 | * Author: Micah Morton <mortonm@chromium.org> | ||
6 | * | ||
7 | * Copyright (C) 2018 The Chromium OS Authors. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #define pr_fmt(fmt) "SafeSetID: " fmt | ||
16 | |||
17 | #include <linux/hashtable.h> | ||
18 | #include <linux/lsm_hooks.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/ptrace.h> | ||
21 | #include <linux/sched/task_stack.h> | ||
22 | #include <linux/security.h> | ||
23 | |||
24 | /* Flag indicating whether initialization completed */ | ||
25 | int safesetid_initialized; | ||
26 | |||
27 | #define NUM_BITS 8 /* 128 buckets in hash table */ | ||
28 | |||
29 | static DEFINE_HASHTABLE(safesetid_whitelist_hashtable, NUM_BITS); | ||
30 | |||
31 | /* | ||
32 | * Hash table entry to store safesetid policy signifying that 'parent' user | ||
33 | * can setid to 'child' user. | ||
34 | */ | ||
35 | struct entry { | ||
36 | struct hlist_node next; | ||
37 | struct hlist_node dlist; /* for deletion cleanup */ | ||
38 | uint64_t parent_kuid; | ||
39 | uint64_t child_kuid; | ||
40 | }; | ||
41 | |||
42 | static DEFINE_SPINLOCK(safesetid_whitelist_hashtable_spinlock); | ||
43 | |||
44 | static bool check_setuid_policy_hashtable_key(kuid_t parent) | ||
45 | { | ||
46 | struct entry *entry; | ||
47 | |||
48 | rcu_read_lock(); | ||
49 | hash_for_each_possible_rcu(safesetid_whitelist_hashtable, | ||
50 | entry, next, __kuid_val(parent)) { | ||
51 | if (entry->parent_kuid == __kuid_val(parent)) { | ||
52 | rcu_read_unlock(); | ||
53 | return true; | ||
54 | } | ||
55 | } | ||
56 | rcu_read_unlock(); | ||
57 | |||
58 | return false; | ||
59 | } | ||
60 | |||
61 | static bool check_setuid_policy_hashtable_key_value(kuid_t parent, | ||
62 | kuid_t child) | ||
63 | { | ||
64 | struct entry *entry; | ||
65 | |||
66 | rcu_read_lock(); | ||
67 | hash_for_each_possible_rcu(safesetid_whitelist_hashtable, | ||
68 | entry, next, __kuid_val(parent)) { | ||
69 | if (entry->parent_kuid == __kuid_val(parent) && | ||
70 | entry->child_kuid == __kuid_val(child)) { | ||
71 | rcu_read_unlock(); | ||
72 | return true; | ||
73 | } | ||
74 | } | ||
75 | rcu_read_unlock(); | ||
76 | |||
77 | return false; | ||
78 | } | ||
79 | |||
80 | static int safesetid_security_capable(const struct cred *cred, | ||
81 | struct user_namespace *ns, | ||
82 | int cap, | ||
83 | unsigned int opts) | ||
84 | { | ||
85 | if (cap == CAP_SETUID && | ||
86 | check_setuid_policy_hashtable_key(cred->uid)) { | ||
87 | if (!(opts & CAP_OPT_INSETID)) { | ||
88 | /* | ||
89 | * Deny if we're not in a set*uid() syscall to avoid | ||
90 | * giving powers gated by CAP_SETUID that are related | ||
91 | * to functionality other than calling set*uid() (e.g. | ||
92 | * allowing user to set up userns uid mappings). | ||
93 | */ | ||
94 | pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions", | ||
95 | __kuid_val(cred->uid)); | ||
96 | return -1; | ||
97 | } | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int check_uid_transition(kuid_t parent, kuid_t child) | ||
103 | { | ||
104 | if (check_setuid_policy_hashtable_key_value(parent, child)) | ||
105 | return 0; | ||
106 | pr_warn("UID transition (%d -> %d) blocked", | ||
107 | __kuid_val(parent), | ||
108 | __kuid_val(child)); | ||
109 | /* | ||
110 | * Kill this process to avoid potential security vulnerabilities | ||
111 | * that could arise from a missing whitelist entry preventing a | ||
112 | * privileged process from dropping to a lesser-privileged one. | ||
113 | */ | ||
114 | force_sig(SIGKILL, current); | ||
115 | return -EACCES; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Check whether there is either an exception for user under old cred struct to | ||
120 | * set*uid to user under new cred struct, or the UID transition is allowed (by | ||
121 | * Linux set*uid rules) even without CAP_SETUID. | ||
122 | */ | ||
123 | static int safesetid_task_fix_setuid(struct cred *new, | ||
124 | const struct cred *old, | ||
125 | int flags) | ||
126 | { | ||
127 | |||
128 | /* Do nothing if there are no setuid restrictions for this UID. */ | ||
129 | if (!check_setuid_policy_hashtable_key(old->uid)) | ||
130 | return 0; | ||
131 | |||
132 | switch (flags) { | ||
133 | case LSM_SETID_RE: | ||
134 | /* | ||
135 | * Users for which setuid restrictions exist can only set the | ||
136 | * real UID to the real UID or the effective UID, unless an | ||
137 | * explicit whitelist policy allows the transition. | ||
138 | */ | ||
139 | if (!uid_eq(old->uid, new->uid) && | ||
140 | !uid_eq(old->euid, new->uid)) { | ||
141 | return check_uid_transition(old->uid, new->uid); | ||
142 | } | ||
143 | /* | ||
144 | * Users for which setuid restrictions exist can only set the | ||
145 | * effective UID to the real UID, the effective UID, or the | ||
146 | * saved set-UID, unless an explicit whitelist policy allows | ||
147 | * the transition. | ||
148 | */ | ||
149 | if (!uid_eq(old->uid, new->euid) && | ||
150 | !uid_eq(old->euid, new->euid) && | ||
151 | !uid_eq(old->suid, new->euid)) { | ||
152 | return check_uid_transition(old->euid, new->euid); | ||
153 | } | ||
154 | break; | ||
155 | case LSM_SETID_ID: | ||
156 | /* | ||
157 | * Users for which setuid restrictions exist cannot change the | ||
158 | * real UID or saved set-UID unless an explicit whitelist | ||
159 | * policy allows the transition. | ||
160 | */ | ||
161 | if (!uid_eq(old->uid, new->uid)) | ||
162 | return check_uid_transition(old->uid, new->uid); | ||
163 | if (!uid_eq(old->suid, new->suid)) | ||
164 | return check_uid_transition(old->suid, new->suid); | ||
165 | break; | ||
166 | case LSM_SETID_RES: | ||
167 | /* | ||
168 | * Users for which setuid restrictions exist cannot change the | ||
169 | * real UID, effective UID, or saved set-UID to anything but | ||
170 | * one of: the current real UID, the current effective UID or | ||
171 | * the current saved set-user-ID unless an explicit whitelist | ||
172 | * policy allows the transition. | ||
173 | */ | ||
174 | if (!uid_eq(new->uid, old->uid) && | ||
175 | !uid_eq(new->uid, old->euid) && | ||
176 | !uid_eq(new->uid, old->suid)) { | ||
177 | return check_uid_transition(old->uid, new->uid); | ||
178 | } | ||
179 | if (!uid_eq(new->euid, old->uid) && | ||
180 | !uid_eq(new->euid, old->euid) && | ||
181 | !uid_eq(new->euid, old->suid)) { | ||
182 | return check_uid_transition(old->euid, new->euid); | ||
183 | } | ||
184 | if (!uid_eq(new->suid, old->uid) && | ||
185 | !uid_eq(new->suid, old->euid) && | ||
186 | !uid_eq(new->suid, old->suid)) { | ||
187 | return check_uid_transition(old->suid, new->suid); | ||
188 | } | ||
189 | break; | ||
190 | case LSM_SETID_FS: | ||
191 | /* | ||
192 | * Users for which setuid restrictions exist cannot change the | ||
193 | * filesystem UID to anything but one of: the current real UID, | ||
194 | * the current effective UID or the current saved set-UID | ||
195 | * unless an explicit whitelist policy allows the transition. | ||
196 | */ | ||
197 | if (!uid_eq(new->fsuid, old->uid) && | ||
198 | !uid_eq(new->fsuid, old->euid) && | ||
199 | !uid_eq(new->fsuid, old->suid) && | ||
200 | !uid_eq(new->fsuid, old->fsuid)) { | ||
201 | return check_uid_transition(old->fsuid, new->fsuid); | ||
202 | } | ||
203 | break; | ||
204 | default: | ||
205 | pr_warn("Unknown setid state %d\n", flags); | ||
206 | force_sig(SIGKILL, current); | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child) | ||
213 | { | ||
214 | struct entry *new; | ||
215 | |||
216 | /* Return if entry already exists */ | ||
217 | if (check_setuid_policy_hashtable_key_value(parent, child)) | ||
218 | return 0; | ||
219 | |||
220 | new = kzalloc(sizeof(struct entry), GFP_KERNEL); | ||
221 | if (!new) | ||
222 | return -ENOMEM; | ||
223 | new->parent_kuid = __kuid_val(parent); | ||
224 | new->child_kuid = __kuid_val(child); | ||
225 | spin_lock(&safesetid_whitelist_hashtable_spinlock); | ||
226 | hash_add_rcu(safesetid_whitelist_hashtable, | ||
227 | &new->next, | ||
228 | __kuid_val(parent)); | ||
229 | spin_unlock(&safesetid_whitelist_hashtable_spinlock); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | void flush_safesetid_whitelist_entries(void) | ||
234 | { | ||
235 | struct entry *entry; | ||
236 | struct hlist_node *hlist_node; | ||
237 | unsigned int bkt_loop_cursor; | ||
238 | HLIST_HEAD(free_list); | ||
239 | |||
240 | /* | ||
241 | * Could probably use hash_for_each_rcu here instead, but this should | ||
242 | * be fine as well. | ||
243 | */ | ||
244 | spin_lock(&safesetid_whitelist_hashtable_spinlock); | ||
245 | hash_for_each_safe(safesetid_whitelist_hashtable, bkt_loop_cursor, | ||
246 | hlist_node, entry, next) { | ||
247 | hash_del_rcu(&entry->next); | ||
248 | hlist_add_head(&entry->dlist, &free_list); | ||
249 | } | ||
250 | spin_unlock(&safesetid_whitelist_hashtable_spinlock); | ||
251 | synchronize_rcu(); | ||
252 | hlist_for_each_entry_safe(entry, hlist_node, &free_list, dlist) { | ||
253 | hlist_del(&entry->dlist); | ||
254 | kfree(entry); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static struct security_hook_list safesetid_security_hooks[] = { | ||
259 | LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid), | ||
260 | LSM_HOOK_INIT(capable, safesetid_security_capable) | ||
261 | }; | ||
262 | |||
263 | static int __init safesetid_security_init(void) | ||
264 | { | ||
265 | security_add_hooks(safesetid_security_hooks, | ||
266 | ARRAY_SIZE(safesetid_security_hooks), "safesetid"); | ||
267 | |||
268 | /* Report that SafeSetID successfully initialized */ | ||
269 | safesetid_initialized = 1; | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | DEFINE_LSM(safesetid_security_init) = { | ||
275 | .init = safesetid_security_init, | ||
276 | .name = "safesetid", | ||
277 | }; | ||
diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h new file mode 100644 index 000000000000..c1ea3c265fcf --- /dev/null +++ b/security/safesetid/lsm.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * SafeSetID Linux Security Module | ||
4 | * | ||
5 | * Author: Micah Morton <mortonm@chromium.org> | ||
6 | * | ||
7 | * Copyright (C) 2018 The Chromium OS Authors. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | #ifndef _SAFESETID_H | ||
15 | #define _SAFESETID_H | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | |||
19 | /* Flag indicating whether initialization completed */ | ||
20 | extern int safesetid_initialized; | ||
21 | |||
22 | /* Function type. */ | ||
23 | enum safesetid_whitelist_file_write_type { | ||
24 | SAFESETID_WHITELIST_ADD, /* Add whitelist policy. */ | ||
25 | SAFESETID_WHITELIST_FLUSH, /* Flush whitelist policies. */ | ||
26 | }; | ||
27 | |||
28 | /* Add entry to safesetid whitelist to allow 'parent' to setid to 'child'. */ | ||
29 | int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child); | ||
30 | |||
31 | void flush_safesetid_whitelist_entries(void); | ||
32 | |||
33 | #endif /* _SAFESETID_H */ | ||
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c new file mode 100644 index 000000000000..2c6c829be044 --- /dev/null +++ b/security/safesetid/securityfs.c | |||
@@ -0,0 +1,193 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * SafeSetID Linux Security Module | ||
4 | * | ||
5 | * Author: Micah Morton <mortonm@chromium.org> | ||
6 | * | ||
7 | * Copyright (C) 2018 The Chromium OS Authors. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | #include <linux/security.h> | ||
15 | #include <linux/cred.h> | ||
16 | |||
17 | #include "lsm.h" | ||
18 | |||
19 | static struct dentry *safesetid_policy_dir; | ||
20 | |||
21 | struct safesetid_file_entry { | ||
22 | const char *name; | ||
23 | enum safesetid_whitelist_file_write_type type; | ||
24 | struct dentry *dentry; | ||
25 | }; | ||
26 | |||
27 | static struct safesetid_file_entry safesetid_files[] = { | ||
28 | {.name = "add_whitelist_policy", | ||
29 | .type = SAFESETID_WHITELIST_ADD}, | ||
30 | {.name = "flush_whitelist_policies", | ||
31 | .type = SAFESETID_WHITELIST_FLUSH}, | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * In the case the input buffer contains one or more invalid UIDs, the kuid_t | ||
36 | * variables pointed to by 'parent' and 'child' will get updated but this | ||
37 | * function will return an error. | ||
38 | */ | ||
39 | static int parse_safesetid_whitelist_policy(const char __user *buf, | ||
40 | size_t len, | ||
41 | kuid_t *parent, | ||
42 | kuid_t *child) | ||
43 | { | ||
44 | char *kern_buf; | ||
45 | char *parent_buf; | ||
46 | char *child_buf; | ||
47 | const char separator[] = ":"; | ||
48 | int ret; | ||
49 | size_t first_substring_length; | ||
50 | long parsed_parent; | ||
51 | long parsed_child; | ||
52 | |||
53 | /* Duplicate string from user memory and NULL-terminate */ | ||
54 | kern_buf = memdup_user_nul(buf, len); | ||
55 | if (IS_ERR(kern_buf)) | ||
56 | return PTR_ERR(kern_buf); | ||
57 | |||
58 | /* | ||
59 | * Format of |buf| string should be <UID>:<UID>. | ||
60 | * Find location of ":" in kern_buf (copied from |buf|). | ||
61 | */ | ||
62 | first_substring_length = strcspn(kern_buf, separator); | ||
63 | if (first_substring_length == 0 || first_substring_length == len) { | ||
64 | ret = -EINVAL; | ||
65 | goto free_kern; | ||
66 | } | ||
67 | |||
68 | parent_buf = kmemdup_nul(kern_buf, first_substring_length, GFP_KERNEL); | ||
69 | if (!parent_buf) { | ||
70 | ret = -ENOMEM; | ||
71 | goto free_kern; | ||
72 | } | ||
73 | |||
74 | ret = kstrtol(parent_buf, 0, &parsed_parent); | ||
75 | if (ret) | ||
76 | goto free_both; | ||
77 | |||
78 | child_buf = kern_buf + first_substring_length + 1; | ||
79 | ret = kstrtol(child_buf, 0, &parsed_child); | ||
80 | if (ret) | ||
81 | goto free_both; | ||
82 | |||
83 | *parent = make_kuid(current_user_ns(), parsed_parent); | ||
84 | if (!uid_valid(*parent)) { | ||
85 | ret = -EINVAL; | ||
86 | goto free_both; | ||
87 | } | ||
88 | |||
89 | *child = make_kuid(current_user_ns(), parsed_child); | ||
90 | if (!uid_valid(*child)) { | ||
91 | ret = -EINVAL; | ||
92 | goto free_both; | ||
93 | } | ||
94 | |||
95 | free_both: | ||
96 | kfree(parent_buf); | ||
97 | free_kern: | ||
98 | kfree(kern_buf); | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static ssize_t safesetid_file_write(struct file *file, | ||
103 | const char __user *buf, | ||
104 | size_t len, | ||
105 | loff_t *ppos) | ||
106 | { | ||
107 | struct safesetid_file_entry *file_entry = | ||
108 | file->f_inode->i_private; | ||
109 | kuid_t parent; | ||
110 | kuid_t child; | ||
111 | int ret; | ||
112 | |||
113 | if (!ns_capable(current_user_ns(), CAP_MAC_ADMIN)) | ||
114 | return -EPERM; | ||
115 | |||
116 | if (*ppos != 0) | ||
117 | return -EINVAL; | ||
118 | |||
119 | switch (file_entry->type) { | ||
120 | case SAFESETID_WHITELIST_FLUSH: | ||
121 | flush_safesetid_whitelist_entries(); | ||
122 | break; | ||
123 | case SAFESETID_WHITELIST_ADD: | ||
124 | ret = parse_safesetid_whitelist_policy(buf, len, &parent, | ||
125 | &child); | ||
126 | if (ret) | ||
127 | return ret; | ||
128 | |||
129 | ret = add_safesetid_whitelist_entry(parent, child); | ||
130 | if (ret) | ||
131 | return ret; | ||
132 | break; | ||
133 | default: | ||
134 | pr_warn("Unknown securityfs file %d\n", file_entry->type); | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | /* Return len on success so caller won't keep trying to write */ | ||
139 | return len; | ||
140 | } | ||
141 | |||
142 | static const struct file_operations safesetid_file_fops = { | ||
143 | .write = safesetid_file_write, | ||
144 | }; | ||
145 | |||
146 | static void safesetid_shutdown_securityfs(void) | ||
147 | { | ||
148 | int i; | ||
149 | |||
150 | for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) { | ||
151 | struct safesetid_file_entry *entry = | ||
152 | &safesetid_files[i]; | ||
153 | securityfs_remove(entry->dentry); | ||
154 | entry->dentry = NULL; | ||
155 | } | ||
156 | |||
157 | securityfs_remove(safesetid_policy_dir); | ||
158 | safesetid_policy_dir = NULL; | ||
159 | } | ||
160 | |||
161 | static int __init safesetid_init_securityfs(void) | ||
162 | { | ||
163 | int i; | ||
164 | int ret; | ||
165 | |||
166 | if (!safesetid_initialized) | ||
167 | return 0; | ||
168 | |||
169 | safesetid_policy_dir = securityfs_create_dir("safesetid", NULL); | ||
170 | if (IS_ERR(safesetid_policy_dir)) { | ||
171 | ret = PTR_ERR(safesetid_policy_dir); | ||
172 | goto error; | ||
173 | } | ||
174 | |||
175 | for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) { | ||
176 | struct safesetid_file_entry *entry = | ||
177 | &safesetid_files[i]; | ||
178 | entry->dentry = securityfs_create_file( | ||
179 | entry->name, 0200, safesetid_policy_dir, | ||
180 | entry, &safesetid_file_fops); | ||
181 | if (IS_ERR(entry->dentry)) { | ||
182 | ret = PTR_ERR(entry->dentry); | ||
183 | goto error; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | |||
189 | error: | ||
190 | safesetid_shutdown_securityfs(); | ||
191 | return ret; | ||
192 | } | ||
193 | fs_initcall(safesetid_init_securityfs); | ||
diff --git a/security/security.c b/security/security.c index 55bc49027ba9..ed9b8cbf21cf 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -30,20 +30,32 @@ | |||
30 | #include <linux/personality.h> | 30 | #include <linux/personality.h> |
31 | #include <linux/backing-dev.h> | 31 | #include <linux/backing-dev.h> |
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/msg.h> | ||
33 | #include <net/flow.h> | 34 | #include <net/flow.h> |
34 | 35 | ||
35 | #define MAX_LSM_EVM_XATTR 2 | 36 | #define MAX_LSM_EVM_XATTR 2 |
36 | 37 | ||
37 | /* Maximum number of letters for an LSM name string */ | 38 | /* How many LSMs were built into the kernel? */ |
38 | #define SECURITY_NAME_MAX 10 | 39 | #define LSM_COUNT (__end_lsm_info - __start_lsm_info) |
39 | 40 | ||
40 | struct security_hook_heads security_hook_heads __lsm_ro_after_init; | 41 | struct security_hook_heads security_hook_heads __lsm_ro_after_init; |
41 | static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); | 42 | static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); |
42 | 43 | ||
44 | static struct kmem_cache *lsm_file_cache; | ||
45 | static struct kmem_cache *lsm_inode_cache; | ||
46 | |||
43 | char *lsm_names; | 47 | char *lsm_names; |
48 | static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; | ||
49 | |||
44 | /* Boot-time LSM user choice */ | 50 | /* Boot-time LSM user choice */ |
45 | static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = | 51 | static __initdata const char *chosen_lsm_order; |
46 | CONFIG_DEFAULT_SECURITY; | 52 | static __initdata const char *chosen_major_lsm; |
53 | |||
54 | static __initconst const char * const builtin_lsm_order = CONFIG_LSM; | ||
55 | |||
56 | /* Ordered list of LSMs to initialize. */ | ||
57 | static __initdata struct lsm_info **ordered_lsms; | ||
58 | static __initdata struct lsm_info *exclusive; | ||
47 | 59 | ||
48 | static __initdata bool debug; | 60 | static __initdata bool debug; |
49 | #define init_debug(...) \ | 61 | #define init_debug(...) \ |
@@ -52,18 +64,269 @@ static __initdata bool debug; | |||
52 | pr_info(__VA_ARGS__); \ | 64 | pr_info(__VA_ARGS__); \ |
53 | } while (0) | 65 | } while (0) |
54 | 66 | ||
55 | static void __init major_lsm_init(void) | 67 | static bool __init is_enabled(struct lsm_info *lsm) |
56 | { | 68 | { |
57 | struct lsm_info *lsm; | 69 | if (!lsm->enabled) |
58 | int ret; | 70 | return false; |
71 | |||
72 | return *lsm->enabled; | ||
73 | } | ||
74 | |||
75 | /* Mark an LSM's enabled flag. */ | ||
76 | static int lsm_enabled_true __initdata = 1; | ||
77 | static int lsm_enabled_false __initdata = 0; | ||
78 | static void __init set_enabled(struct lsm_info *lsm, bool enabled) | ||
79 | { | ||
80 | /* | ||
81 | * When an LSM hasn't configured an enable variable, we can use | ||
82 | * a hard-coded location for storing the default enabled state. | ||
83 | */ | ||
84 | if (!lsm->enabled) { | ||
85 | if (enabled) | ||
86 | lsm->enabled = &lsm_enabled_true; | ||
87 | else | ||
88 | lsm->enabled = &lsm_enabled_false; | ||
89 | } else if (lsm->enabled == &lsm_enabled_true) { | ||
90 | if (!enabled) | ||
91 | lsm->enabled = &lsm_enabled_false; | ||
92 | } else if (lsm->enabled == &lsm_enabled_false) { | ||
93 | if (enabled) | ||
94 | lsm->enabled = &lsm_enabled_true; | ||
95 | } else { | ||
96 | *lsm->enabled = enabled; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* Is an LSM already listed in the ordered LSMs list? */ | ||
101 | static bool __init exists_ordered_lsm(struct lsm_info *lsm) | ||
102 | { | ||
103 | struct lsm_info **check; | ||
104 | |||
105 | for (check = ordered_lsms; *check; check++) | ||
106 | if (*check == lsm) | ||
107 | return true; | ||
108 | |||
109 | return false; | ||
110 | } | ||
111 | |||
112 | /* Append an LSM to the list of ordered LSMs to initialize. */ | ||
113 | static int last_lsm __initdata; | ||
114 | static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from) | ||
115 | { | ||
116 | /* Ignore duplicate selections. */ | ||
117 | if (exists_ordered_lsm(lsm)) | ||
118 | return; | ||
119 | |||
120 | if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from)) | ||
121 | return; | ||
122 | |||
123 | /* Enable this LSM, if it is not already set. */ | ||
124 | if (!lsm->enabled) | ||
125 | lsm->enabled = &lsm_enabled_true; | ||
126 | ordered_lsms[last_lsm++] = lsm; | ||
127 | |||
128 | init_debug("%s ordering: %s (%sabled)\n", from, lsm->name, | ||
129 | is_enabled(lsm) ? "en" : "dis"); | ||
130 | } | ||
131 | |||
132 | /* Is an LSM allowed to be initialized? */ | ||
133 | static bool __init lsm_allowed(struct lsm_info *lsm) | ||
134 | { | ||
135 | /* Skip if the LSM is disabled. */ | ||
136 | if (!is_enabled(lsm)) | ||
137 | return false; | ||
138 | |||
139 | /* Not allowed if another exclusive LSM already initialized. */ | ||
140 | if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) { | ||
141 | init_debug("exclusive disabled: %s\n", lsm->name); | ||
142 | return false; | ||
143 | } | ||
144 | |||
145 | return true; | ||
146 | } | ||
147 | |||
148 | static void __init lsm_set_blob_size(int *need, int *lbs) | ||
149 | { | ||
150 | int offset; | ||
151 | |||
152 | if (*need > 0) { | ||
153 | offset = *lbs; | ||
154 | *lbs += *need; | ||
155 | *need = offset; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) | ||
160 | { | ||
161 | if (!needed) | ||
162 | return; | ||
163 | |||
164 | lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred); | ||
165 | lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file); | ||
166 | /* | ||
167 | * The inode blob gets an rcu_head in addition to | ||
168 | * what the modules might need. | ||
169 | */ | ||
170 | if (needed->lbs_inode && blob_sizes.lbs_inode == 0) | ||
171 | blob_sizes.lbs_inode = sizeof(struct rcu_head); | ||
172 | lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode); | ||
173 | lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc); | ||
174 | lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg); | ||
175 | lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task); | ||
176 | } | ||
177 | |||
178 | /* Prepare LSM for initialization. */ | ||
179 | static void __init prepare_lsm(struct lsm_info *lsm) | ||
180 | { | ||
181 | int enabled = lsm_allowed(lsm); | ||
182 | |||
183 | /* Record enablement (to handle any following exclusive LSMs). */ | ||
184 | set_enabled(lsm, enabled); | ||
185 | |||
186 | /* If enabled, do pre-initialization work. */ | ||
187 | if (enabled) { | ||
188 | if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) { | ||
189 | exclusive = lsm; | ||
190 | init_debug("exclusive chosen: %s\n", lsm->name); | ||
191 | } | ||
192 | |||
193 | lsm_set_blob_sizes(lsm->blobs); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* Initialize a given LSM, if it is enabled. */ | ||
198 | static void __init initialize_lsm(struct lsm_info *lsm) | ||
199 | { | ||
200 | if (is_enabled(lsm)) { | ||
201 | int ret; | ||
59 | 202 | ||
60 | for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { | ||
61 | init_debug("initializing %s\n", lsm->name); | 203 | init_debug("initializing %s\n", lsm->name); |
62 | ret = lsm->init(); | 204 | ret = lsm->init(); |
63 | WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret); | 205 | WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret); |
64 | } | 206 | } |
65 | } | 207 | } |
66 | 208 | ||
209 | /* Populate ordered LSMs list from comma-separated LSM name list. */ | ||
210 | static void __init ordered_lsm_parse(const char *order, const char *origin) | ||
211 | { | ||
212 | struct lsm_info *lsm; | ||
213 | char *sep, *name, *next; | ||
214 | |||
215 | /* LSM_ORDER_FIRST is always first. */ | ||
216 | for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { | ||
217 | if (lsm->order == LSM_ORDER_FIRST) | ||
218 | append_ordered_lsm(lsm, "first"); | ||
219 | } | ||
220 | |||
221 | /* Process "security=", if given. */ | ||
222 | if (chosen_major_lsm) { | ||
223 | struct lsm_info *major; | ||
224 | |||
225 | /* | ||
226 | * To match the original "security=" behavior, this | ||
227 | * explicitly does NOT fallback to another Legacy Major | ||
228 | * if the selected one was separately disabled: disable | ||
229 | * all non-matching Legacy Major LSMs. | ||
230 | */ | ||
231 | for (major = __start_lsm_info; major < __end_lsm_info; | ||
232 | major++) { | ||
233 | if ((major->flags & LSM_FLAG_LEGACY_MAJOR) && | ||
234 | strcmp(major->name, chosen_major_lsm) != 0) { | ||
235 | set_enabled(major, false); | ||
236 | init_debug("security=%s disabled: %s\n", | ||
237 | chosen_major_lsm, major->name); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | sep = kstrdup(order, GFP_KERNEL); | ||
243 | next = sep; | ||
244 | /* Walk the list, looking for matching LSMs. */ | ||
245 | while ((name = strsep(&next, ",")) != NULL) { | ||
246 | bool found = false; | ||
247 | |||
248 | for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { | ||
249 | if (lsm->order == LSM_ORDER_MUTABLE && | ||
250 | strcmp(lsm->name, name) == 0) { | ||
251 | append_ordered_lsm(lsm, origin); | ||
252 | found = true; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if (!found) | ||
257 | init_debug("%s ignored: %s\n", origin, name); | ||
258 | } | ||
259 | |||
260 | /* Process "security=", if given. */ | ||
261 | if (chosen_major_lsm) { | ||
262 | for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { | ||
263 | if (exists_ordered_lsm(lsm)) | ||
264 | continue; | ||
265 | if (strcmp(lsm->name, chosen_major_lsm) == 0) | ||
266 | append_ordered_lsm(lsm, "security="); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | /* Disable all LSMs not in the ordered list. */ | ||
271 | for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { | ||
272 | if (exists_ordered_lsm(lsm)) | ||
273 | continue; | ||
274 | set_enabled(lsm, false); | ||
275 | init_debug("%s disabled: %s\n", origin, lsm->name); | ||
276 | } | ||
277 | |||
278 | kfree(sep); | ||
279 | } | ||
280 | |||
281 | static void __init lsm_early_cred(struct cred *cred); | ||
282 | static void __init lsm_early_task(struct task_struct *task); | ||
283 | |||
284 | static void __init ordered_lsm_init(void) | ||
285 | { | ||
286 | struct lsm_info **lsm; | ||
287 | |||
288 | ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms), | ||
289 | GFP_KERNEL); | ||
290 | |||
291 | if (chosen_lsm_order) { | ||
292 | if (chosen_major_lsm) { | ||
293 | pr_info("security= is ignored because it is superseded by lsm=\n"); | ||
294 | chosen_major_lsm = NULL; | ||
295 | } | ||
296 | ordered_lsm_parse(chosen_lsm_order, "cmdline"); | ||
297 | } else | ||
298 | ordered_lsm_parse(builtin_lsm_order, "builtin"); | ||
299 | |||
300 | for (lsm = ordered_lsms; *lsm; lsm++) | ||
301 | prepare_lsm(*lsm); | ||
302 | |||
303 | init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); | ||
304 | init_debug("file blob size = %d\n", blob_sizes.lbs_file); | ||
305 | init_debug("inode blob size = %d\n", blob_sizes.lbs_inode); | ||
306 | init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc); | ||
307 | init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg); | ||
308 | init_debug("task blob size = %d\n", blob_sizes.lbs_task); | ||
309 | |||
310 | /* | ||
311 | * Create any kmem_caches needed for blobs | ||
312 | */ | ||
313 | if (blob_sizes.lbs_file) | ||
314 | lsm_file_cache = kmem_cache_create("lsm_file_cache", | ||
315 | blob_sizes.lbs_file, 0, | ||
316 | SLAB_PANIC, NULL); | ||
317 | if (blob_sizes.lbs_inode) | ||
318 | lsm_inode_cache = kmem_cache_create("lsm_inode_cache", | ||
319 | blob_sizes.lbs_inode, 0, | ||
320 | SLAB_PANIC, NULL); | ||
321 | |||
322 | lsm_early_cred((struct cred *) current->cred); | ||
323 | lsm_early_task(current); | ||
324 | for (lsm = ordered_lsms; *lsm; lsm++) | ||
325 | initialize_lsm(*lsm); | ||
326 | |||
327 | kfree(ordered_lsms); | ||
328 | } | ||
329 | |||
67 | /** | 330 | /** |
68 | * security_init - initializes the security framework | 331 | * security_init - initializes the security framework |
69 | * | 332 | * |
@@ -80,28 +343,27 @@ int __init security_init(void) | |||
80 | i++) | 343 | i++) |
81 | INIT_HLIST_HEAD(&list[i]); | 344 | INIT_HLIST_HEAD(&list[i]); |
82 | 345 | ||
83 | /* | 346 | /* Load LSMs in specified order. */ |
84 | * Load minor LSMs, with the capability module always first. | 347 | ordered_lsm_init(); |
85 | */ | ||
86 | capability_add_hooks(); | ||
87 | yama_add_hooks(); | ||
88 | loadpin_add_hooks(); | ||
89 | |||
90 | /* | ||
91 | * Load all the remaining security modules. | ||
92 | */ | ||
93 | major_lsm_init(); | ||
94 | 348 | ||
95 | return 0; | 349 | return 0; |
96 | } | 350 | } |
97 | 351 | ||
98 | /* Save user chosen LSM */ | 352 | /* Save user chosen LSM */ |
99 | static int __init choose_lsm(char *str) | 353 | static int __init choose_major_lsm(char *str) |
354 | { | ||
355 | chosen_major_lsm = str; | ||
356 | return 1; | ||
357 | } | ||
358 | __setup("security=", choose_major_lsm); | ||
359 | |||
360 | /* Explicitly choose LSM initialization order. */ | ||
361 | static int __init choose_lsm_order(char *str) | ||
100 | { | 362 | { |
101 | strncpy(chosen_lsm, str, SECURITY_NAME_MAX); | 363 | chosen_lsm_order = str; |
102 | return 1; | 364 | return 1; |
103 | } | 365 | } |
104 | __setup("security=", choose_lsm); | 366 | __setup("lsm=", choose_lsm_order); |
105 | 367 | ||
106 | /* Enable LSM order debugging. */ | 368 | /* Enable LSM order debugging. */ |
107 | static int __init enable_debug(char *str) | 369 | static int __init enable_debug(char *str) |
@@ -148,29 +410,6 @@ static int lsm_append(char *new, char **result) | |||
148 | } | 410 | } |
149 | 411 | ||
150 | /** | 412 | /** |
151 | * security_module_enable - Load given security module on boot ? | ||
152 | * @module: the name of the module | ||
153 | * | ||
154 | * Each LSM must pass this method before registering its own operations | ||
155 | * to avoid security registration races. This method may also be used | ||
156 | * to check if your LSM is currently loaded during kernel initialization. | ||
157 | * | ||
158 | * Returns: | ||
159 | * | ||
160 | * true if: | ||
161 | * | ||
162 | * - The passed LSM is the one chosen by user at boot time, | ||
163 | * - or the passed LSM is configured as the default and the user did not | ||
164 | * choose an alternate LSM at boot time. | ||
165 | * | ||
166 | * Otherwise, return false. | ||
167 | */ | ||
168 | int __init security_module_enable(const char *module) | ||
169 | { | ||
170 | return !strcmp(module, chosen_lsm); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * security_add_hooks - Add a modules hooks to the hook lists. | 413 | * security_add_hooks - Add a modules hooks to the hook lists. |
175 | * @hooks: the hooks to add | 414 | * @hooks: the hooks to add |
176 | * @count: the number of hooks to add | 415 | * @count: the number of hooks to add |
@@ -209,6 +448,161 @@ int unregister_lsm_notifier(struct notifier_block *nb) | |||
209 | } | 448 | } |
210 | EXPORT_SYMBOL(unregister_lsm_notifier); | 449 | EXPORT_SYMBOL(unregister_lsm_notifier); |
211 | 450 | ||
451 | /** | ||
452 | * lsm_cred_alloc - allocate a composite cred blob | ||
453 | * @cred: the cred that needs a blob | ||
454 | * @gfp: allocation type | ||
455 | * | ||
456 | * Allocate the cred blob for all the modules | ||
457 | * | ||
458 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
459 | */ | ||
460 | static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) | ||
461 | { | ||
462 | if (blob_sizes.lbs_cred == 0) { | ||
463 | cred->security = NULL; | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | cred->security = kzalloc(blob_sizes.lbs_cred, gfp); | ||
468 | if (cred->security == NULL) | ||
469 | return -ENOMEM; | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * lsm_early_cred - during initialization allocate a composite cred blob | ||
475 | * @cred: the cred that needs a blob | ||
476 | * | ||
477 | * Allocate the cred blob for all the modules | ||
478 | */ | ||
479 | static void __init lsm_early_cred(struct cred *cred) | ||
480 | { | ||
481 | int rc = lsm_cred_alloc(cred, GFP_KERNEL); | ||
482 | |||
483 | if (rc) | ||
484 | panic("%s: Early cred alloc failed.\n", __func__); | ||
485 | } | ||
486 | |||
487 | /** | ||
488 | * lsm_file_alloc - allocate a composite file blob | ||
489 | * @file: the file that needs a blob | ||
490 | * | ||
491 | * Allocate the file blob for all the modules | ||
492 | * | ||
493 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
494 | */ | ||
495 | static int lsm_file_alloc(struct file *file) | ||
496 | { | ||
497 | if (!lsm_file_cache) { | ||
498 | file->f_security = NULL; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL); | ||
503 | if (file->f_security == NULL) | ||
504 | return -ENOMEM; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * lsm_inode_alloc - allocate a composite inode blob | ||
510 | * @inode: the inode that needs a blob | ||
511 | * | ||
512 | * Allocate the inode blob for all the modules | ||
513 | * | ||
514 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
515 | */ | ||
516 | int lsm_inode_alloc(struct inode *inode) | ||
517 | { | ||
518 | if (!lsm_inode_cache) { | ||
519 | inode->i_security = NULL; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | inode->i_security = kmem_cache_zalloc(lsm_inode_cache, GFP_NOFS); | ||
524 | if (inode->i_security == NULL) | ||
525 | return -ENOMEM; | ||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * lsm_task_alloc - allocate a composite task blob | ||
531 | * @task: the task that needs a blob | ||
532 | * | ||
533 | * Allocate the task blob for all the modules | ||
534 | * | ||
535 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
536 | */ | ||
537 | static int lsm_task_alloc(struct task_struct *task) | ||
538 | { | ||
539 | if (blob_sizes.lbs_task == 0) { | ||
540 | task->security = NULL; | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL); | ||
545 | if (task->security == NULL) | ||
546 | return -ENOMEM; | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | /** | ||
551 | * lsm_ipc_alloc - allocate a composite ipc blob | ||
552 | * @kip: the ipc that needs a blob | ||
553 | * | ||
554 | * Allocate the ipc blob for all the modules | ||
555 | * | ||
556 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
557 | */ | ||
558 | static int lsm_ipc_alloc(struct kern_ipc_perm *kip) | ||
559 | { | ||
560 | if (blob_sizes.lbs_ipc == 0) { | ||
561 | kip->security = NULL; | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL); | ||
566 | if (kip->security == NULL) | ||
567 | return -ENOMEM; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * lsm_msg_msg_alloc - allocate a composite msg_msg blob | ||
573 | * @mp: the msg_msg that needs a blob | ||
574 | * | ||
575 | * Allocate the ipc blob for all the modules | ||
576 | * | ||
577 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
578 | */ | ||
579 | static int lsm_msg_msg_alloc(struct msg_msg *mp) | ||
580 | { | ||
581 | if (blob_sizes.lbs_msg_msg == 0) { | ||
582 | mp->security = NULL; | ||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL); | ||
587 | if (mp->security == NULL) | ||
588 | return -ENOMEM; | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /** | ||
593 | * lsm_early_task - during initialization allocate a composite task blob | ||
594 | * @task: the task that needs a blob | ||
595 | * | ||
596 | * Allocate the task blob for all the modules | ||
597 | */ | ||
598 | static void __init lsm_early_task(struct task_struct *task) | ||
599 | { | ||
600 | int rc = lsm_task_alloc(task); | ||
601 | |||
602 | if (rc) | ||
603 | panic("%s: Early task alloc failed.\n", __func__); | ||
604 | } | ||
605 | |||
212 | /* | 606 | /* |
213 | * Hook list operation macros. | 607 | * Hook list operation macros. |
214 | * | 608 | * |
@@ -294,16 +688,12 @@ int security_capset(struct cred *new, const struct cred *old, | |||
294 | effective, inheritable, permitted); | 688 | effective, inheritable, permitted); |
295 | } | 689 | } |
296 | 690 | ||
297 | int security_capable(const struct cred *cred, struct user_namespace *ns, | 691 | int security_capable(const struct cred *cred, |
298 | int cap) | 692 | struct user_namespace *ns, |
693 | int cap, | ||
694 | unsigned int opts) | ||
299 | { | 695 | { |
300 | return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT); | 696 | return call_int_hook(capable, 0, cred, ns, cap, opts); |
301 | } | ||
302 | |||
303 | int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, | ||
304 | int cap) | ||
305 | { | ||
306 | return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT); | ||
307 | } | 697 | } |
308 | 698 | ||
309 | int security_quotactl(int cmds, int type, int id, struct super_block *sb) | 699 | int security_quotactl(int cmds, int type, int id, struct super_block *sb) |
@@ -468,14 +858,40 @@ EXPORT_SYMBOL(security_add_mnt_opt); | |||
468 | 858 | ||
469 | int security_inode_alloc(struct inode *inode) | 859 | int security_inode_alloc(struct inode *inode) |
470 | { | 860 | { |
471 | inode->i_security = NULL; | 861 | int rc = lsm_inode_alloc(inode); |
472 | return call_int_hook(inode_alloc_security, 0, inode); | 862 | |
863 | if (unlikely(rc)) | ||
864 | return rc; | ||
865 | rc = call_int_hook(inode_alloc_security, 0, inode); | ||
866 | if (unlikely(rc)) | ||
867 | security_inode_free(inode); | ||
868 | return rc; | ||
869 | } | ||
870 | |||
871 | static void inode_free_by_rcu(struct rcu_head *head) | ||
872 | { | ||
873 | /* | ||
874 | * The rcu head is at the start of the inode blob | ||
875 | */ | ||
876 | kmem_cache_free(lsm_inode_cache, head); | ||
473 | } | 877 | } |
474 | 878 | ||
475 | void security_inode_free(struct inode *inode) | 879 | void security_inode_free(struct inode *inode) |
476 | { | 880 | { |
477 | integrity_inode_free(inode); | 881 | integrity_inode_free(inode); |
478 | call_void_hook(inode_free_security, inode); | 882 | call_void_hook(inode_free_security, inode); |
883 | /* | ||
884 | * The inode may still be referenced in a path walk and | ||
885 | * a call to security_inode_permission() can be made | ||
886 | * after inode_free_security() is called. Ideally, the VFS | ||
887 | * wouldn't do this, but fixing that is a much harder | ||
888 | * job. For now, simply free the i_security via RCU, and | ||
889 | * leave the current inode->i_security pointer intact. | ||
890 | * The inode will be freed after the RCU grace period too. | ||
891 | */ | ||
892 | if (inode->i_security) | ||
893 | call_rcu((struct rcu_head *)inode->i_security, | ||
894 | inode_free_by_rcu); | ||
479 | } | 895 | } |
480 | 896 | ||
481 | int security_dentry_init_security(struct dentry *dentry, int mode, | 897 | int security_dentry_init_security(struct dentry *dentry, int mode, |
@@ -905,12 +1321,27 @@ int security_file_permission(struct file *file, int mask) | |||
905 | 1321 | ||
906 | int security_file_alloc(struct file *file) | 1322 | int security_file_alloc(struct file *file) |
907 | { | 1323 | { |
908 | return call_int_hook(file_alloc_security, 0, file); | 1324 | int rc = lsm_file_alloc(file); |
1325 | |||
1326 | if (rc) | ||
1327 | return rc; | ||
1328 | rc = call_int_hook(file_alloc_security, 0, file); | ||
1329 | if (unlikely(rc)) | ||
1330 | security_file_free(file); | ||
1331 | return rc; | ||
909 | } | 1332 | } |
910 | 1333 | ||
911 | void security_file_free(struct file *file) | 1334 | void security_file_free(struct file *file) |
912 | { | 1335 | { |
1336 | void *blob; | ||
1337 | |||
913 | call_void_hook(file_free_security, file); | 1338 | call_void_hook(file_free_security, file); |
1339 | |||
1340 | blob = file->f_security; | ||
1341 | if (blob) { | ||
1342 | file->f_security = NULL; | ||
1343 | kmem_cache_free(lsm_file_cache, blob); | ||
1344 | } | ||
914 | } | 1345 | } |
915 | 1346 | ||
916 | int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1347 | int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
@@ -1012,17 +1443,35 @@ int security_file_open(struct file *file) | |||
1012 | 1443 | ||
1013 | int security_task_alloc(struct task_struct *task, unsigned long clone_flags) | 1444 | int security_task_alloc(struct task_struct *task, unsigned long clone_flags) |
1014 | { | 1445 | { |
1015 | return call_int_hook(task_alloc, 0, task, clone_flags); | 1446 | int rc = lsm_task_alloc(task); |
1447 | |||
1448 | if (rc) | ||
1449 | return rc; | ||
1450 | rc = call_int_hook(task_alloc, 0, task, clone_flags); | ||
1451 | if (unlikely(rc)) | ||
1452 | security_task_free(task); | ||
1453 | return rc; | ||
1016 | } | 1454 | } |
1017 | 1455 | ||
1018 | void security_task_free(struct task_struct *task) | 1456 | void security_task_free(struct task_struct *task) |
1019 | { | 1457 | { |
1020 | call_void_hook(task_free, task); | 1458 | call_void_hook(task_free, task); |
1459 | |||
1460 | kfree(task->security); | ||
1461 | task->security = NULL; | ||
1021 | } | 1462 | } |
1022 | 1463 | ||
1023 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | 1464 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) |
1024 | { | 1465 | { |
1025 | return call_int_hook(cred_alloc_blank, 0, cred, gfp); | 1466 | int rc = lsm_cred_alloc(cred, gfp); |
1467 | |||
1468 | if (rc) | ||
1469 | return rc; | ||
1470 | |||
1471 | rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); | ||
1472 | if (unlikely(rc)) | ||
1473 | security_cred_free(cred); | ||
1474 | return rc; | ||
1026 | } | 1475 | } |
1027 | 1476 | ||
1028 | void security_cred_free(struct cred *cred) | 1477 | void security_cred_free(struct cred *cred) |
@@ -1035,11 +1484,22 @@ void security_cred_free(struct cred *cred) | |||
1035 | return; | 1484 | return; |
1036 | 1485 | ||
1037 | call_void_hook(cred_free, cred); | 1486 | call_void_hook(cred_free, cred); |
1487 | |||
1488 | kfree(cred->security); | ||
1489 | cred->security = NULL; | ||
1038 | } | 1490 | } |
1039 | 1491 | ||
1040 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) | 1492 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) |
1041 | { | 1493 | { |
1042 | return call_int_hook(cred_prepare, 0, new, old, gfp); | 1494 | int rc = lsm_cred_alloc(new, gfp); |
1495 | |||
1496 | if (rc) | ||
1497 | return rc; | ||
1498 | |||
1499 | rc = call_int_hook(cred_prepare, 0, new, old, gfp); | ||
1500 | if (unlikely(rc)) | ||
1501 | security_cred_free(new); | ||
1502 | return rc; | ||
1043 | } | 1503 | } |
1044 | 1504 | ||
1045 | void security_transfer_creds(struct cred *new, const struct cred *old) | 1505 | void security_transfer_creds(struct cred *new, const struct cred *old) |
@@ -1220,22 +1680,40 @@ void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) | |||
1220 | 1680 | ||
1221 | int security_msg_msg_alloc(struct msg_msg *msg) | 1681 | int security_msg_msg_alloc(struct msg_msg *msg) |
1222 | { | 1682 | { |
1223 | return call_int_hook(msg_msg_alloc_security, 0, msg); | 1683 | int rc = lsm_msg_msg_alloc(msg); |
1684 | |||
1685 | if (unlikely(rc)) | ||
1686 | return rc; | ||
1687 | rc = call_int_hook(msg_msg_alloc_security, 0, msg); | ||
1688 | if (unlikely(rc)) | ||
1689 | security_msg_msg_free(msg); | ||
1690 | return rc; | ||
1224 | } | 1691 | } |
1225 | 1692 | ||
1226 | void security_msg_msg_free(struct msg_msg *msg) | 1693 | void security_msg_msg_free(struct msg_msg *msg) |
1227 | { | 1694 | { |
1228 | call_void_hook(msg_msg_free_security, msg); | 1695 | call_void_hook(msg_msg_free_security, msg); |
1696 | kfree(msg->security); | ||
1697 | msg->security = NULL; | ||
1229 | } | 1698 | } |
1230 | 1699 | ||
1231 | int security_msg_queue_alloc(struct kern_ipc_perm *msq) | 1700 | int security_msg_queue_alloc(struct kern_ipc_perm *msq) |
1232 | { | 1701 | { |
1233 | return call_int_hook(msg_queue_alloc_security, 0, msq); | 1702 | int rc = lsm_ipc_alloc(msq); |
1703 | |||
1704 | if (unlikely(rc)) | ||
1705 | return rc; | ||
1706 | rc = call_int_hook(msg_queue_alloc_security, 0, msq); | ||
1707 | if (unlikely(rc)) | ||
1708 | security_msg_queue_free(msq); | ||
1709 | return rc; | ||
1234 | } | 1710 | } |
1235 | 1711 | ||
1236 | void security_msg_queue_free(struct kern_ipc_perm *msq) | 1712 | void security_msg_queue_free(struct kern_ipc_perm *msq) |
1237 | { | 1713 | { |
1238 | call_void_hook(msg_queue_free_security, msq); | 1714 | call_void_hook(msg_queue_free_security, msq); |
1715 | kfree(msq->security); | ||
1716 | msq->security = NULL; | ||
1239 | } | 1717 | } |
1240 | 1718 | ||
1241 | int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) | 1719 | int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) |
@@ -1262,12 +1740,21 @@ int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, | |||
1262 | 1740 | ||
1263 | int security_shm_alloc(struct kern_ipc_perm *shp) | 1741 | int security_shm_alloc(struct kern_ipc_perm *shp) |
1264 | { | 1742 | { |
1265 | return call_int_hook(shm_alloc_security, 0, shp); | 1743 | int rc = lsm_ipc_alloc(shp); |
1744 | |||
1745 | if (unlikely(rc)) | ||
1746 | return rc; | ||
1747 | rc = call_int_hook(shm_alloc_security, 0, shp); | ||
1748 | if (unlikely(rc)) | ||
1749 | security_shm_free(shp); | ||
1750 | return rc; | ||
1266 | } | 1751 | } |
1267 | 1752 | ||
1268 | void security_shm_free(struct kern_ipc_perm *shp) | 1753 | void security_shm_free(struct kern_ipc_perm *shp) |
1269 | { | 1754 | { |
1270 | call_void_hook(shm_free_security, shp); | 1755 | call_void_hook(shm_free_security, shp); |
1756 | kfree(shp->security); | ||
1757 | shp->security = NULL; | ||
1271 | } | 1758 | } |
1272 | 1759 | ||
1273 | int security_shm_associate(struct kern_ipc_perm *shp, int shmflg) | 1760 | int security_shm_associate(struct kern_ipc_perm *shp, int shmflg) |
@@ -1287,12 +1774,21 @@ int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmf | |||
1287 | 1774 | ||
1288 | int security_sem_alloc(struct kern_ipc_perm *sma) | 1775 | int security_sem_alloc(struct kern_ipc_perm *sma) |
1289 | { | 1776 | { |
1290 | return call_int_hook(sem_alloc_security, 0, sma); | 1777 | int rc = lsm_ipc_alloc(sma); |
1778 | |||
1779 | if (unlikely(rc)) | ||
1780 | return rc; | ||
1781 | rc = call_int_hook(sem_alloc_security, 0, sma); | ||
1782 | if (unlikely(rc)) | ||
1783 | security_sem_free(sma); | ||
1784 | return rc; | ||
1291 | } | 1785 | } |
1292 | 1786 | ||
1293 | void security_sem_free(struct kern_ipc_perm *sma) | 1787 | void security_sem_free(struct kern_ipc_perm *sma) |
1294 | { | 1788 | { |
1295 | call_void_hook(sem_free_security, sma); | 1789 | call_void_hook(sem_free_security, sma); |
1790 | kfree(sma->security); | ||
1791 | sma->security = NULL; | ||
1296 | } | 1792 | } |
1297 | 1793 | ||
1298 | int security_sem_associate(struct kern_ipc_perm *sma, int semflg) | 1794 | int security_sem_associate(struct kern_ipc_perm *sma, int semflg) |
@@ -1319,14 +1815,30 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode) | |||
1319 | } | 1815 | } |
1320 | EXPORT_SYMBOL(security_d_instantiate); | 1816 | EXPORT_SYMBOL(security_d_instantiate); |
1321 | 1817 | ||
1322 | int security_getprocattr(struct task_struct *p, char *name, char **value) | 1818 | int security_getprocattr(struct task_struct *p, const char *lsm, char *name, |
1819 | char **value) | ||
1323 | { | 1820 | { |
1324 | return call_int_hook(getprocattr, -EINVAL, p, name, value); | 1821 | struct security_hook_list *hp; |
1822 | |||
1823 | hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) { | ||
1824 | if (lsm != NULL && strcmp(lsm, hp->lsm)) | ||
1825 | continue; | ||
1826 | return hp->hook.getprocattr(p, name, value); | ||
1827 | } | ||
1828 | return -EINVAL; | ||
1325 | } | 1829 | } |
1326 | 1830 | ||
1327 | int security_setprocattr(const char *name, void *value, size_t size) | 1831 | int security_setprocattr(const char *lsm, const char *name, void *value, |
1832 | size_t size) | ||
1328 | { | 1833 | { |
1329 | return call_int_hook(setprocattr, -EINVAL, name, value, size); | 1834 | struct security_hook_list *hp; |
1835 | |||
1836 | hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) { | ||
1837 | if (lsm != NULL && strcmp(lsm, hp->lsm)) | ||
1838 | continue; | ||
1839 | return hp->hook.setprocattr(name, value, size); | ||
1840 | } | ||
1841 | return -EINVAL; | ||
1330 | } | 1842 | } |
1331 | 1843 | ||
1332 | int security_netlink_send(struct sock *sk, struct sk_buff *skb) | 1844 | int security_netlink_send(struct sock *sk, struct sk_buff *skb) |
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 8af7a690eb40..55f032f1fc2d 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig | |||
@@ -22,21 +22,6 @@ config SECURITY_SELINUX_BOOTPARAM | |||
22 | 22 | ||
23 | If you are unsure how to answer this question, answer N. | 23 | If you are unsure how to answer this question, answer N. |
24 | 24 | ||
25 | config SECURITY_SELINUX_BOOTPARAM_VALUE | ||
26 | int "NSA SELinux boot parameter default value" | ||
27 | depends on SECURITY_SELINUX_BOOTPARAM | ||
28 | range 0 1 | ||
29 | default 1 | ||
30 | help | ||
31 | This option sets the default value for the kernel parameter | ||
32 | 'selinux', which allows SELinux to be disabled at boot. If this | ||
33 | option is set to 0 (zero), the SELinux kernel parameter will | ||
34 | default to 0, disabling SELinux at bootup. If this option is | ||
35 | set to 1 (one), the SELinux kernel parameter will default to 1, | ||
36 | enabling SELinux at bootup. | ||
37 | |||
38 | If you are unsure how to answer this question, answer 1. | ||
39 | |||
40 | config SECURITY_SELINUX_DISABLE | 25 | config SECURITY_SELINUX_DISABLE |
41 | bool "NSA SELinux runtime disable" | 26 | bool "NSA SELinux runtime disable" |
42 | depends on SECURITY_SELINUX | 27 | depends on SECURITY_SELINUX |
diff --git a/security/selinux/Makefile b/security/selinux/Makefile index c7161f8792b2..ccf950409384 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile | |||
@@ -6,7 +6,7 @@ | |||
6 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o | 6 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o |
7 | 7 | ||
8 | selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ | 8 | selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ |
9 | netnode.o netport.o ibpkey.o exports.o \ | 9 | netnode.o netport.o ibpkey.o \ |
10 | ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ | 10 | ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ |
11 | ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o | 11 | ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o |
12 | 12 | ||
diff --git a/security/selinux/exports.c b/security/selinux/exports.c deleted file mode 100644 index e75dd94e2d2b..000000000000 --- a/security/selinux/exports.c +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * SELinux services exported to the rest of the kernel. | ||
3 | * | ||
4 | * Author: James Morris <jmorris@redhat.com> | ||
5 | * | ||
6 | * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com> | ||
7 | * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> | ||
8 | * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2, | ||
12 | * as published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/selinux.h> | ||
16 | |||
17 | #include "security.h" | ||
18 | |||
19 | bool selinux_is_enabled(void) | ||
20 | { | ||
21 | return selinux_enabled; | ||
22 | } | ||
23 | EXPORT_SYMBOL_GPL(selinux_is_enabled); | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f0e36c3492ba..5d92167dbe05 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -79,7 +79,6 @@ | |||
79 | #include <linux/personality.h> | 79 | #include <linux/personality.h> |
80 | #include <linux/audit.h> | 80 | #include <linux/audit.h> |
81 | #include <linux/string.h> | 81 | #include <linux/string.h> |
82 | #include <linux/selinux.h> | ||
83 | #include <linux/mutex.h> | 82 | #include <linux/mutex.h> |
84 | #include <linux/posix-timers.h> | 83 | #include <linux/posix-timers.h> |
85 | #include <linux/syslog.h> | 84 | #include <linux/syslog.h> |
@@ -121,9 +120,8 @@ __setup("enforcing=", enforcing_setup); | |||
121 | #define selinux_enforcing_boot 1 | 120 | #define selinux_enforcing_boot 1 |
122 | #endif | 121 | #endif |
123 | 122 | ||
123 | int selinux_enabled __lsm_ro_after_init = 1; | ||
124 | #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM | 124 | #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM |
125 | int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; | ||
126 | |||
127 | static int __init selinux_enabled_setup(char *str) | 125 | static int __init selinux_enabled_setup(char *str) |
128 | { | 126 | { |
129 | unsigned long enabled; | 127 | unsigned long enabled; |
@@ -132,8 +130,6 @@ static int __init selinux_enabled_setup(char *str) | |||
132 | return 1; | 130 | return 1; |
133 | } | 131 | } |
134 | __setup("selinux=", selinux_enabled_setup); | 132 | __setup("selinux=", selinux_enabled_setup); |
135 | #else | ||
136 | int selinux_enabled = 1; | ||
137 | #endif | 133 | #endif |
138 | 134 | ||
139 | static unsigned int selinux_checkreqprot_boot = | 135 | static unsigned int selinux_checkreqprot_boot = |
@@ -149,9 +145,6 @@ static int __init checkreqprot_setup(char *str) | |||
149 | } | 145 | } |
150 | __setup("checkreqprot=", checkreqprot_setup); | 146 | __setup("checkreqprot=", checkreqprot_setup); |
151 | 147 | ||
152 | static struct kmem_cache *sel_inode_cache; | ||
153 | static struct kmem_cache *file_security_cache; | ||
154 | |||
155 | /** | 148 | /** |
156 | * selinux_secmark_enabled - Check to see if SECMARK is currently enabled | 149 | * selinux_secmark_enabled - Check to see if SECMARK is currently enabled |
157 | * | 150 | * |
@@ -214,12 +207,8 @@ static void cred_init_security(void) | |||
214 | struct cred *cred = (struct cred *) current->real_cred; | 207 | struct cred *cred = (struct cred *) current->real_cred; |
215 | struct task_security_struct *tsec; | 208 | struct task_security_struct *tsec; |
216 | 209 | ||
217 | tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); | 210 | tsec = selinux_cred(cred); |
218 | if (!tsec) | ||
219 | panic("SELinux: Failed to initialize initial task.\n"); | ||
220 | |||
221 | tsec->osid = tsec->sid = SECINITSID_KERNEL; | 211 | tsec->osid = tsec->sid = SECINITSID_KERNEL; |
222 | cred->security = tsec; | ||
223 | } | 212 | } |
224 | 213 | ||
225 | /* | 214 | /* |
@@ -229,7 +218,7 @@ static inline u32 cred_sid(const struct cred *cred) | |||
229 | { | 218 | { |
230 | const struct task_security_struct *tsec; | 219 | const struct task_security_struct *tsec; |
231 | 220 | ||
232 | tsec = cred->security; | 221 | tsec = selinux_cred(cred); |
233 | return tsec->sid; | 222 | return tsec->sid; |
234 | } | 223 | } |
235 | 224 | ||
@@ -250,13 +239,9 @@ static inline u32 task_sid(const struct task_struct *task) | |||
250 | 239 | ||
251 | static int inode_alloc_security(struct inode *inode) | 240 | static int inode_alloc_security(struct inode *inode) |
252 | { | 241 | { |
253 | struct inode_security_struct *isec; | 242 | struct inode_security_struct *isec = selinux_inode(inode); |
254 | u32 sid = current_sid(); | 243 | u32 sid = current_sid(); |
255 | 244 | ||
256 | isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS); | ||
257 | if (!isec) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | spin_lock_init(&isec->lock); | 245 | spin_lock_init(&isec->lock); |
261 | INIT_LIST_HEAD(&isec->list); | 246 | INIT_LIST_HEAD(&isec->list); |
262 | isec->inode = inode; | 247 | isec->inode = inode; |
@@ -264,7 +249,6 @@ static int inode_alloc_security(struct inode *inode) | |||
264 | isec->sclass = SECCLASS_FILE; | 249 | isec->sclass = SECCLASS_FILE; |
265 | isec->task_sid = sid; | 250 | isec->task_sid = sid; |
266 | isec->initialized = LABEL_INVALID; | 251 | isec->initialized = LABEL_INVALID; |
267 | inode->i_security = isec; | ||
268 | 252 | ||
269 | return 0; | 253 | return 0; |
270 | } | 254 | } |
@@ -281,7 +265,7 @@ static int __inode_security_revalidate(struct inode *inode, | |||
281 | struct dentry *dentry, | 265 | struct dentry *dentry, |
282 | bool may_sleep) | 266 | bool may_sleep) |
283 | { | 267 | { |
284 | struct inode_security_struct *isec = inode->i_security; | 268 | struct inode_security_struct *isec = selinux_inode(inode); |
285 | 269 | ||
286 | might_sleep_if(may_sleep); | 270 | might_sleep_if(may_sleep); |
287 | 271 | ||
@@ -302,7 +286,7 @@ static int __inode_security_revalidate(struct inode *inode, | |||
302 | 286 | ||
303 | static struct inode_security_struct *inode_security_novalidate(struct inode *inode) | 287 | static struct inode_security_struct *inode_security_novalidate(struct inode *inode) |
304 | { | 288 | { |
305 | return inode->i_security; | 289 | return selinux_inode(inode); |
306 | } | 290 | } |
307 | 291 | ||
308 | static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu) | 292 | static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu) |
@@ -312,7 +296,7 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo | |||
312 | error = __inode_security_revalidate(inode, NULL, !rcu); | 296 | error = __inode_security_revalidate(inode, NULL, !rcu); |
313 | if (error) | 297 | if (error) |
314 | return ERR_PTR(error); | 298 | return ERR_PTR(error); |
315 | return inode->i_security; | 299 | return selinux_inode(inode); |
316 | } | 300 | } |
317 | 301 | ||
318 | /* | 302 | /* |
@@ -321,14 +305,14 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo | |||
321 | static struct inode_security_struct *inode_security(struct inode *inode) | 305 | static struct inode_security_struct *inode_security(struct inode *inode) |
322 | { | 306 | { |
323 | __inode_security_revalidate(inode, NULL, true); | 307 | __inode_security_revalidate(inode, NULL, true); |
324 | return inode->i_security; | 308 | return selinux_inode(inode); |
325 | } | 309 | } |
326 | 310 | ||
327 | static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry) | 311 | static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry) |
328 | { | 312 | { |
329 | struct inode *inode = d_backing_inode(dentry); | 313 | struct inode *inode = d_backing_inode(dentry); |
330 | 314 | ||
331 | return inode->i_security; | 315 | return selinux_inode(inode); |
332 | } | 316 | } |
333 | 317 | ||
334 | /* | 318 | /* |
@@ -339,22 +323,17 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr | |||
339 | struct inode *inode = d_backing_inode(dentry); | 323 | struct inode *inode = d_backing_inode(dentry); |
340 | 324 | ||
341 | __inode_security_revalidate(inode, dentry, true); | 325 | __inode_security_revalidate(inode, dentry, true); |
342 | return inode->i_security; | 326 | return selinux_inode(inode); |
343 | } | ||
344 | |||
345 | static void inode_free_rcu(struct rcu_head *head) | ||
346 | { | ||
347 | struct inode_security_struct *isec; | ||
348 | |||
349 | isec = container_of(head, struct inode_security_struct, rcu); | ||
350 | kmem_cache_free(sel_inode_cache, isec); | ||
351 | } | 327 | } |
352 | 328 | ||
353 | static void inode_free_security(struct inode *inode) | 329 | static void inode_free_security(struct inode *inode) |
354 | { | 330 | { |
355 | struct inode_security_struct *isec = inode->i_security; | 331 | struct inode_security_struct *isec = selinux_inode(inode); |
356 | struct superblock_security_struct *sbsec = inode->i_sb->s_security; | 332 | struct superblock_security_struct *sbsec; |
357 | 333 | ||
334 | if (!isec) | ||
335 | return; | ||
336 | sbsec = inode->i_sb->s_security; | ||
358 | /* | 337 | /* |
359 | * As not all inode security structures are in a list, we check for | 338 | * As not all inode security structures are in a list, we check for |
360 | * empty list outside of the lock to make sure that we won't waste | 339 | * empty list outside of the lock to make sure that we won't waste |
@@ -370,42 +349,19 @@ static void inode_free_security(struct inode *inode) | |||
370 | list_del_init(&isec->list); | 349 | list_del_init(&isec->list); |
371 | spin_unlock(&sbsec->isec_lock); | 350 | spin_unlock(&sbsec->isec_lock); |
372 | } | 351 | } |
373 | |||
374 | /* | ||
375 | * The inode may still be referenced in a path walk and | ||
376 | * a call to selinux_inode_permission() can be made | ||
377 | * after inode_free_security() is called. Ideally, the VFS | ||
378 | * wouldn't do this, but fixing that is a much harder | ||
379 | * job. For now, simply free the i_security via RCU, and | ||
380 | * leave the current inode->i_security pointer intact. | ||
381 | * The inode will be freed after the RCU grace period too. | ||
382 | */ | ||
383 | call_rcu(&isec->rcu, inode_free_rcu); | ||
384 | } | 352 | } |
385 | 353 | ||
386 | static int file_alloc_security(struct file *file) | 354 | static int file_alloc_security(struct file *file) |
387 | { | 355 | { |
388 | struct file_security_struct *fsec; | 356 | struct file_security_struct *fsec = selinux_file(file); |
389 | u32 sid = current_sid(); | 357 | u32 sid = current_sid(); |
390 | 358 | ||
391 | fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL); | ||
392 | if (!fsec) | ||
393 | return -ENOMEM; | ||
394 | |||
395 | fsec->sid = sid; | 359 | fsec->sid = sid; |
396 | fsec->fown_sid = sid; | 360 | fsec->fown_sid = sid; |
397 | file->f_security = fsec; | ||
398 | 361 | ||
399 | return 0; | 362 | return 0; |
400 | } | 363 | } |
401 | 364 | ||
402 | static void file_free_security(struct file *file) | ||
403 | { | ||
404 | struct file_security_struct *fsec = file->f_security; | ||
405 | file->f_security = NULL; | ||
406 | kmem_cache_free(file_security_cache, fsec); | ||
407 | } | ||
408 | |||
409 | static int superblock_alloc_security(struct super_block *sb) | 365 | static int superblock_alloc_security(struct super_block *sb) |
410 | { | 366 | { |
411 | struct superblock_security_struct *sbsec; | 367 | struct superblock_security_struct *sbsec; |
@@ -501,7 +457,7 @@ static int may_context_mount_sb_relabel(u32 sid, | |||
501 | struct superblock_security_struct *sbsec, | 457 | struct superblock_security_struct *sbsec, |
502 | const struct cred *cred) | 458 | const struct cred *cred) |
503 | { | 459 | { |
504 | const struct task_security_struct *tsec = cred->security; | 460 | const struct task_security_struct *tsec = selinux_cred(cred); |
505 | int rc; | 461 | int rc; |
506 | 462 | ||
507 | rc = avc_has_perm(&selinux_state, | 463 | rc = avc_has_perm(&selinux_state, |
@@ -520,7 +476,7 @@ static int may_context_mount_inode_relabel(u32 sid, | |||
520 | struct superblock_security_struct *sbsec, | 476 | struct superblock_security_struct *sbsec, |
521 | const struct cred *cred) | 477 | const struct cred *cred) |
522 | { | 478 | { |
523 | const struct task_security_struct *tsec = cred->security; | 479 | const struct task_security_struct *tsec = selinux_cred(cred); |
524 | int rc; | 480 | int rc; |
525 | rc = avc_has_perm(&selinux_state, | 481 | rc = avc_has_perm(&selinux_state, |
526 | tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | 482 | tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, |
@@ -1374,7 +1330,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry, | |||
1374 | static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) | 1330 | static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) |
1375 | { | 1331 | { |
1376 | struct superblock_security_struct *sbsec = NULL; | 1332 | struct superblock_security_struct *sbsec = NULL; |
1377 | struct inode_security_struct *isec = inode->i_security; | 1333 | struct inode_security_struct *isec = selinux_inode(inode); |
1378 | u32 task_sid, sid = 0; | 1334 | u32 task_sid, sid = 0; |
1379 | u16 sclass; | 1335 | u16 sclass; |
1380 | struct dentry *dentry; | 1336 | struct dentry *dentry; |
@@ -1621,7 +1577,7 @@ static inline u32 signal_to_av(int sig) | |||
1621 | 1577 | ||
1622 | /* Check whether a task is allowed to use a capability. */ | 1578 | /* Check whether a task is allowed to use a capability. */ |
1623 | static int cred_has_capability(const struct cred *cred, | 1579 | static int cred_has_capability(const struct cred *cred, |
1624 | int cap, int audit, bool initns) | 1580 | int cap, unsigned int opts, bool initns) |
1625 | { | 1581 | { |
1626 | struct common_audit_data ad; | 1582 | struct common_audit_data ad; |
1627 | struct av_decision avd; | 1583 | struct av_decision avd; |
@@ -1648,7 +1604,7 @@ static int cred_has_capability(const struct cred *cred, | |||
1648 | 1604 | ||
1649 | rc = avc_has_perm_noaudit(&selinux_state, | 1605 | rc = avc_has_perm_noaudit(&selinux_state, |
1650 | sid, sid, sclass, av, 0, &avd); | 1606 | sid, sid, sclass, av, 0, &avd); |
1651 | if (audit == SECURITY_CAP_AUDIT) { | 1607 | if (!(opts & CAP_OPT_NOAUDIT)) { |
1652 | int rc2 = avc_audit(&selinux_state, | 1608 | int rc2 = avc_audit(&selinux_state, |
1653 | sid, sid, sclass, av, &avd, rc, &ad, 0); | 1609 | sid, sid, sclass, av, &avd, rc, &ad, 0); |
1654 | if (rc2) | 1610 | if (rc2) |
@@ -1674,7 +1630,7 @@ static int inode_has_perm(const struct cred *cred, | |||
1674 | return 0; | 1630 | return 0; |
1675 | 1631 | ||
1676 | sid = cred_sid(cred); | 1632 | sid = cred_sid(cred); |
1677 | isec = inode->i_security; | 1633 | isec = selinux_inode(inode); |
1678 | 1634 | ||
1679 | return avc_has_perm(&selinux_state, | 1635 | return avc_has_perm(&selinux_state, |
1680 | sid, isec->sid, isec->sclass, perms, adp); | 1636 | sid, isec->sid, isec->sclass, perms, adp); |
@@ -1740,7 +1696,7 @@ static int file_has_perm(const struct cred *cred, | |||
1740 | struct file *file, | 1696 | struct file *file, |
1741 | u32 av) | 1697 | u32 av) |
1742 | { | 1698 | { |
1743 | struct file_security_struct *fsec = file->f_security; | 1699 | struct file_security_struct *fsec = selinux_file(file); |
1744 | struct inode *inode = file_inode(file); | 1700 | struct inode *inode = file_inode(file); |
1745 | struct common_audit_data ad; | 1701 | struct common_audit_data ad; |
1746 | u32 sid = cred_sid(cred); | 1702 | u32 sid = cred_sid(cred); |
@@ -1806,7 +1762,7 @@ static int may_create(struct inode *dir, | |||
1806 | struct dentry *dentry, | 1762 | struct dentry *dentry, |
1807 | u16 tclass) | 1763 | u16 tclass) |
1808 | { | 1764 | { |
1809 | const struct task_security_struct *tsec = current_security(); | 1765 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
1810 | struct inode_security_struct *dsec; | 1766 | struct inode_security_struct *dsec; |
1811 | struct superblock_security_struct *sbsec; | 1767 | struct superblock_security_struct *sbsec; |
1812 | u32 sid, newsid; | 1768 | u32 sid, newsid; |
@@ -1828,7 +1784,7 @@ static int may_create(struct inode *dir, | |||
1828 | if (rc) | 1784 | if (rc) |
1829 | return rc; | 1785 | return rc; |
1830 | 1786 | ||
1831 | rc = selinux_determine_inode_label(current_security(), dir, | 1787 | rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir, |
1832 | &dentry->d_name, tclass, &newsid); | 1788 | &dentry->d_name, tclass, &newsid); |
1833 | if (rc) | 1789 | if (rc) |
1834 | return rc; | 1790 | return rc; |
@@ -2084,7 +2040,7 @@ static int selinux_binder_transfer_file(struct task_struct *from, | |||
2084 | struct file *file) | 2040 | struct file *file) |
2085 | { | 2041 | { |
2086 | u32 sid = task_sid(to); | 2042 | u32 sid = task_sid(to); |
2087 | struct file_security_struct *fsec = file->f_security; | 2043 | struct file_security_struct *fsec = selinux_file(file); |
2088 | struct dentry *dentry = file->f_path.dentry; | 2044 | struct dentry *dentry = file->f_path.dentry; |
2089 | struct inode_security_struct *isec; | 2045 | struct inode_security_struct *isec; |
2090 | struct common_audit_data ad; | 2046 | struct common_audit_data ad; |
@@ -2168,9 +2124,9 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
2168 | */ | 2124 | */ |
2169 | 2125 | ||
2170 | static int selinux_capable(const struct cred *cred, struct user_namespace *ns, | 2126 | static int selinux_capable(const struct cred *cred, struct user_namespace *ns, |
2171 | int cap, int audit) | 2127 | int cap, unsigned int opts) |
2172 | { | 2128 | { |
2173 | return cred_has_capability(cred, cap, audit, ns == &init_user_ns); | 2129 | return cred_has_capability(cred, cap, opts, ns == &init_user_ns); |
2174 | } | 2130 | } |
2175 | 2131 | ||
2176 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) | 2132 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) |
@@ -2244,7 +2200,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
2244 | int rc, cap_sys_admin = 0; | 2200 | int rc, cap_sys_admin = 0; |
2245 | 2201 | ||
2246 | rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, | 2202 | rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, |
2247 | SECURITY_CAP_NOAUDIT, true); | 2203 | CAP_OPT_NOAUDIT, true); |
2248 | if (rc == 0) | 2204 | if (rc == 0) |
2249 | cap_sys_admin = 1; | 2205 | cap_sys_admin = 1; |
2250 | 2206 | ||
@@ -2335,8 +2291,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2335 | if (bprm->called_set_creds) | 2291 | if (bprm->called_set_creds) |
2336 | return 0; | 2292 | return 0; |
2337 | 2293 | ||
2338 | old_tsec = current_security(); | 2294 | old_tsec = selinux_cred(current_cred()); |
2339 | new_tsec = bprm->cred->security; | 2295 | new_tsec = selinux_cred(bprm->cred); |
2340 | isec = inode_security(inode); | 2296 | isec = inode_security(inode); |
2341 | 2297 | ||
2342 | /* Default to the current task SID. */ | 2298 | /* Default to the current task SID. */ |
@@ -2500,7 +2456,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) | |||
2500 | struct rlimit *rlim, *initrlim; | 2456 | struct rlimit *rlim, *initrlim; |
2501 | int rc, i; | 2457 | int rc, i; |
2502 | 2458 | ||
2503 | new_tsec = bprm->cred->security; | 2459 | new_tsec = selinux_cred(bprm->cred); |
2504 | if (new_tsec->sid == new_tsec->osid) | 2460 | if (new_tsec->sid == new_tsec->osid) |
2505 | return; | 2461 | return; |
2506 | 2462 | ||
@@ -2543,7 +2499,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) | |||
2543 | */ | 2499 | */ |
2544 | static void selinux_bprm_committed_creds(struct linux_binprm *bprm) | 2500 | static void selinux_bprm_committed_creds(struct linux_binprm *bprm) |
2545 | { | 2501 | { |
2546 | const struct task_security_struct *tsec = current_security(); | 2502 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
2547 | struct itimerval itimer; | 2503 | struct itimerval itimer; |
2548 | u32 osid, sid; | 2504 | u32 osid, sid; |
2549 | int rc, i; | 2505 | int rc, i; |
@@ -2780,7 +2736,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, | |||
2780 | u32 newsid; | 2736 | u32 newsid; |
2781 | int rc; | 2737 | int rc; |
2782 | 2738 | ||
2783 | rc = selinux_determine_inode_label(current_security(), | 2739 | rc = selinux_determine_inode_label(selinux_cred(current_cred()), |
2784 | d_inode(dentry->d_parent), name, | 2740 | d_inode(dentry->d_parent), name, |
2785 | inode_mode_to_security_class(mode), | 2741 | inode_mode_to_security_class(mode), |
2786 | &newsid); | 2742 | &newsid); |
@@ -2800,14 +2756,14 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode, | |||
2800 | int rc; | 2756 | int rc; |
2801 | struct task_security_struct *tsec; | 2757 | struct task_security_struct *tsec; |
2802 | 2758 | ||
2803 | rc = selinux_determine_inode_label(old->security, | 2759 | rc = selinux_determine_inode_label(selinux_cred(old), |
2804 | d_inode(dentry->d_parent), name, | 2760 | d_inode(dentry->d_parent), name, |
2805 | inode_mode_to_security_class(mode), | 2761 | inode_mode_to_security_class(mode), |
2806 | &newsid); | 2762 | &newsid); |
2807 | if (rc) | 2763 | if (rc) |
2808 | return rc; | 2764 | return rc; |
2809 | 2765 | ||
2810 | tsec = new->security; | 2766 | tsec = selinux_cred(new); |
2811 | tsec->create_sid = newsid; | 2767 | tsec->create_sid = newsid; |
2812 | return 0; | 2768 | return 0; |
2813 | } | 2769 | } |
@@ -2817,7 +2773,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2817 | const char **name, | 2773 | const char **name, |
2818 | void **value, size_t *len) | 2774 | void **value, size_t *len) |
2819 | { | 2775 | { |
2820 | const struct task_security_struct *tsec = current_security(); | 2776 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
2821 | struct superblock_security_struct *sbsec; | 2777 | struct superblock_security_struct *sbsec; |
2822 | u32 newsid, clen; | 2778 | u32 newsid, clen; |
2823 | int rc; | 2779 | int rc; |
@@ -2827,7 +2783,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2827 | 2783 | ||
2828 | newsid = tsec->create_sid; | 2784 | newsid = tsec->create_sid; |
2829 | 2785 | ||
2830 | rc = selinux_determine_inode_label(current_security(), | 2786 | rc = selinux_determine_inode_label(selinux_cred(current_cred()), |
2831 | dir, qstr, | 2787 | dir, qstr, |
2832 | inode_mode_to_security_class(inode->i_mode), | 2788 | inode_mode_to_security_class(inode->i_mode), |
2833 | &newsid); | 2789 | &newsid); |
@@ -2836,7 +2792,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2836 | 2792 | ||
2837 | /* Possibly defer initialization to selinux_complete_init. */ | 2793 | /* Possibly defer initialization to selinux_complete_init. */ |
2838 | if (sbsec->flags & SE_SBINITIALIZED) { | 2794 | if (sbsec->flags & SE_SBINITIALIZED) { |
2839 | struct inode_security_struct *isec = inode->i_security; | 2795 | struct inode_security_struct *isec = selinux_inode(inode); |
2840 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 2796 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
2841 | isec->sid = newsid; | 2797 | isec->sid = newsid; |
2842 | isec->initialized = LABEL_INITIALIZED; | 2798 | isec->initialized = LABEL_INITIALIZED; |
@@ -2936,7 +2892,7 @@ static noinline int audit_inode_permission(struct inode *inode, | |||
2936 | unsigned flags) | 2892 | unsigned flags) |
2937 | { | 2893 | { |
2938 | struct common_audit_data ad; | 2894 | struct common_audit_data ad; |
2939 | struct inode_security_struct *isec = inode->i_security; | 2895 | struct inode_security_struct *isec = selinux_inode(inode); |
2940 | int rc; | 2896 | int rc; |
2941 | 2897 | ||
2942 | ad.type = LSM_AUDIT_DATA_INODE; | 2898 | ad.type = LSM_AUDIT_DATA_INODE; |
@@ -3031,11 +2987,11 @@ static int selinux_inode_getattr(const struct path *path) | |||
3031 | static bool has_cap_mac_admin(bool audit) | 2987 | static bool has_cap_mac_admin(bool audit) |
3032 | { | 2988 | { |
3033 | const struct cred *cred = current_cred(); | 2989 | const struct cred *cred = current_cred(); |
3034 | int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT; | 2990 | unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT; |
3035 | 2991 | ||
3036 | if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit)) | 2992 | if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts)) |
3037 | return false; | 2993 | return false; |
3038 | if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true)) | 2994 | if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true)) |
3039 | return false; | 2995 | return false; |
3040 | return true; | 2996 | return true; |
3041 | } | 2997 | } |
@@ -3289,7 +3245,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new) | |||
3289 | return -ENOMEM; | 3245 | return -ENOMEM; |
3290 | } | 3246 | } |
3291 | 3247 | ||
3292 | tsec = new_creds->security; | 3248 | tsec = selinux_cred(new_creds); |
3293 | /* Get label from overlay inode and set it in create_sid */ | 3249 | /* Get label from overlay inode and set it in create_sid */ |
3294 | selinux_inode_getsecid(d_inode(src), &sid); | 3250 | selinux_inode_getsecid(d_inode(src), &sid); |
3295 | tsec->create_sid = sid; | 3251 | tsec->create_sid = sid; |
@@ -3330,7 +3286,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
3330 | static int selinux_file_permission(struct file *file, int mask) | 3286 | static int selinux_file_permission(struct file *file, int mask) |
3331 | { | 3287 | { |
3332 | struct inode *inode = file_inode(file); | 3288 | struct inode *inode = file_inode(file); |
3333 | struct file_security_struct *fsec = file->f_security; | 3289 | struct file_security_struct *fsec = selinux_file(file); |
3334 | struct inode_security_struct *isec; | 3290 | struct inode_security_struct *isec; |
3335 | u32 sid = current_sid(); | 3291 | u32 sid = current_sid(); |
3336 | 3292 | ||
@@ -3352,11 +3308,6 @@ static int selinux_file_alloc_security(struct file *file) | |||
3352 | return file_alloc_security(file); | 3308 | return file_alloc_security(file); |
3353 | } | 3309 | } |
3354 | 3310 | ||
3355 | static void selinux_file_free_security(struct file *file) | ||
3356 | { | ||
3357 | file_free_security(file); | ||
3358 | } | ||
3359 | |||
3360 | /* | 3311 | /* |
3361 | * Check whether a task has the ioctl permission and cmd | 3312 | * Check whether a task has the ioctl permission and cmd |
3362 | * operation to an inode. | 3313 | * operation to an inode. |
@@ -3365,7 +3316,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, | |||
3365 | u32 requested, u16 cmd) | 3316 | u32 requested, u16 cmd) |
3366 | { | 3317 | { |
3367 | struct common_audit_data ad; | 3318 | struct common_audit_data ad; |
3368 | struct file_security_struct *fsec = file->f_security; | 3319 | struct file_security_struct *fsec = selinux_file(file); |
3369 | struct inode *inode = file_inode(file); | 3320 | struct inode *inode = file_inode(file); |
3370 | struct inode_security_struct *isec; | 3321 | struct inode_security_struct *isec; |
3371 | struct lsm_ioctlop_audit ioctl; | 3322 | struct lsm_ioctlop_audit ioctl; |
@@ -3435,7 +3386,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
3435 | case KDSKBENT: | 3386 | case KDSKBENT: |
3436 | case KDSKBSENT: | 3387 | case KDSKBSENT: |
3437 | error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, | 3388 | error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, |
3438 | SECURITY_CAP_AUDIT, true); | 3389 | CAP_OPT_NONE, true); |
3439 | break; | 3390 | break; |
3440 | 3391 | ||
3441 | /* default case assumes that the command will go | 3392 | /* default case assumes that the command will go |
@@ -3617,7 +3568,7 @@ static void selinux_file_set_fowner(struct file *file) | |||
3617 | { | 3568 | { |
3618 | struct file_security_struct *fsec; | 3569 | struct file_security_struct *fsec; |
3619 | 3570 | ||
3620 | fsec = file->f_security; | 3571 | fsec = selinux_file(file); |
3621 | fsec->fown_sid = current_sid(); | 3572 | fsec->fown_sid = current_sid(); |
3622 | } | 3573 | } |
3623 | 3574 | ||
@@ -3632,7 +3583,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, | |||
3632 | /* struct fown_struct is never outside the context of a struct file */ | 3583 | /* struct fown_struct is never outside the context of a struct file */ |
3633 | file = container_of(fown, struct file, f_owner); | 3584 | file = container_of(fown, struct file, f_owner); |
3634 | 3585 | ||
3635 | fsec = file->f_security; | 3586 | fsec = selinux_file(file); |
3636 | 3587 | ||
3637 | if (!signum) | 3588 | if (!signum) |
3638 | perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ | 3589 | perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ |
@@ -3656,7 +3607,7 @@ static int selinux_file_open(struct file *file) | |||
3656 | struct file_security_struct *fsec; | 3607 | struct file_security_struct *fsec; |
3657 | struct inode_security_struct *isec; | 3608 | struct inode_security_struct *isec; |
3658 | 3609 | ||
3659 | fsec = file->f_security; | 3610 | fsec = selinux_file(file); |
3660 | isec = inode_security(file_inode(file)); | 3611 | isec = inode_security(file_inode(file)); |
3661 | /* | 3612 | /* |
3662 | * Save inode label and policy sequence number | 3613 | * Save inode label and policy sequence number |
@@ -3690,52 +3641,15 @@ static int selinux_task_alloc(struct task_struct *task, | |||
3690 | } | 3641 | } |
3691 | 3642 | ||
3692 | /* | 3643 | /* |
3693 | * allocate the SELinux part of blank credentials | ||
3694 | */ | ||
3695 | static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
3696 | { | ||
3697 | struct task_security_struct *tsec; | ||
3698 | |||
3699 | tsec = kzalloc(sizeof(struct task_security_struct), gfp); | ||
3700 | if (!tsec) | ||
3701 | return -ENOMEM; | ||
3702 | |||
3703 | cred->security = tsec; | ||
3704 | return 0; | ||
3705 | } | ||
3706 | |||
3707 | /* | ||
3708 | * detach and free the LSM part of a set of credentials | ||
3709 | */ | ||
3710 | static void selinux_cred_free(struct cred *cred) | ||
3711 | { | ||
3712 | struct task_security_struct *tsec = cred->security; | ||
3713 | |||
3714 | /* | ||
3715 | * cred->security == NULL if security_cred_alloc_blank() or | ||
3716 | * security_prepare_creds() returned an error. | ||
3717 | */ | ||
3718 | BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE); | ||
3719 | cred->security = (void *) 0x7UL; | ||
3720 | kfree(tsec); | ||
3721 | } | ||
3722 | |||
3723 | /* | ||
3724 | * prepare a new set of credentials for modification | 3644 | * prepare a new set of credentials for modification |
3725 | */ | 3645 | */ |
3726 | static int selinux_cred_prepare(struct cred *new, const struct cred *old, | 3646 | static int selinux_cred_prepare(struct cred *new, const struct cred *old, |
3727 | gfp_t gfp) | 3647 | gfp_t gfp) |
3728 | { | 3648 | { |
3729 | const struct task_security_struct *old_tsec; | 3649 | const struct task_security_struct *old_tsec = selinux_cred(old); |
3730 | struct task_security_struct *tsec; | 3650 | struct task_security_struct *tsec = selinux_cred(new); |
3731 | |||
3732 | old_tsec = old->security; | ||
3733 | 3651 | ||
3734 | tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); | 3652 | *tsec = *old_tsec; |
3735 | if (!tsec) | ||
3736 | return -ENOMEM; | ||
3737 | |||
3738 | new->security = tsec; | ||
3739 | return 0; | 3653 | return 0; |
3740 | } | 3654 | } |
3741 | 3655 | ||
@@ -3744,8 +3658,8 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, | |||
3744 | */ | 3658 | */ |
3745 | static void selinux_cred_transfer(struct cred *new, const struct cred *old) | 3659 | static void selinux_cred_transfer(struct cred *new, const struct cred *old) |
3746 | { | 3660 | { |
3747 | const struct task_security_struct *old_tsec = old->security; | 3661 | const struct task_security_struct *old_tsec = selinux_cred(old); |
3748 | struct task_security_struct *tsec = new->security; | 3662 | struct task_security_struct *tsec = selinux_cred(new); |
3749 | 3663 | ||
3750 | *tsec = *old_tsec; | 3664 | *tsec = *old_tsec; |
3751 | } | 3665 | } |
@@ -3761,7 +3675,7 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid) | |||
3761 | */ | 3675 | */ |
3762 | static int selinux_kernel_act_as(struct cred *new, u32 secid) | 3676 | static int selinux_kernel_act_as(struct cred *new, u32 secid) |
3763 | { | 3677 | { |
3764 | struct task_security_struct *tsec = new->security; | 3678 | struct task_security_struct *tsec = selinux_cred(new); |
3765 | u32 sid = current_sid(); | 3679 | u32 sid = current_sid(); |
3766 | int ret; | 3680 | int ret; |
3767 | 3681 | ||
@@ -3786,7 +3700,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid) | |||
3786 | static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | 3700 | static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) |
3787 | { | 3701 | { |
3788 | struct inode_security_struct *isec = inode_security(inode); | 3702 | struct inode_security_struct *isec = inode_security(inode); |
3789 | struct task_security_struct *tsec = new->security; | 3703 | struct task_security_struct *tsec = selinux_cred(new); |
3790 | u32 sid = current_sid(); | 3704 | u32 sid = current_sid(); |
3791 | int ret; | 3705 | int ret; |
3792 | 3706 | ||
@@ -3832,7 +3746,7 @@ static int selinux_kernel_module_from_file(struct file *file) | |||
3832 | ad.type = LSM_AUDIT_DATA_FILE; | 3746 | ad.type = LSM_AUDIT_DATA_FILE; |
3833 | ad.u.file = file; | 3747 | ad.u.file = file; |
3834 | 3748 | ||
3835 | fsec = file->f_security; | 3749 | fsec = selinux_file(file); |
3836 | if (sid != fsec->sid) { | 3750 | if (sid != fsec->sid) { |
3837 | rc = avc_has_perm(&selinux_state, | 3751 | rc = avc_has_perm(&selinux_state, |
3838 | sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); | 3752 | sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); |
@@ -3998,7 +3912,7 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info, | |||
3998 | static void selinux_task_to_inode(struct task_struct *p, | 3912 | static void selinux_task_to_inode(struct task_struct *p, |
3999 | struct inode *inode) | 3913 | struct inode *inode) |
4000 | { | 3914 | { |
4001 | struct inode_security_struct *isec = inode->i_security; | 3915 | struct inode_security_struct *isec = selinux_inode(inode); |
4002 | u32 sid = task_sid(p); | 3916 | u32 sid = task_sid(p); |
4003 | 3917 | ||
4004 | spin_lock(&isec->lock); | 3918 | spin_lock(&isec->lock); |
@@ -4335,7 +4249,7 @@ static int sock_has_perm(struct sock *sk, u32 perms) | |||
4335 | static int selinux_socket_create(int family, int type, | 4249 | static int selinux_socket_create(int family, int type, |
4336 | int protocol, int kern) | 4250 | int protocol, int kern) |
4337 | { | 4251 | { |
4338 | const struct task_security_struct *tsec = current_security(); | 4252 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
4339 | u32 newsid; | 4253 | u32 newsid; |
4340 | u16 secclass; | 4254 | u16 secclass; |
4341 | int rc; | 4255 | int rc; |
@@ -4355,7 +4269,7 @@ static int selinux_socket_create(int family, int type, | |||
4355 | static int selinux_socket_post_create(struct socket *sock, int family, | 4269 | static int selinux_socket_post_create(struct socket *sock, int family, |
4356 | int type, int protocol, int kern) | 4270 | int type, int protocol, int kern) |
4357 | { | 4271 | { |
4358 | const struct task_security_struct *tsec = current_security(); | 4272 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
4359 | struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock)); | 4273 | struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock)); |
4360 | struct sk_security_struct *sksec; | 4274 | struct sk_security_struct *sksec; |
4361 | u16 sclass = socket_type_to_security_class(family, type, protocol); | 4275 | u16 sclass = socket_type_to_security_class(family, type, protocol); |
@@ -5236,7 +5150,7 @@ static int selinux_secmark_relabel_packet(u32 sid) | |||
5236 | const struct task_security_struct *__tsec; | 5150 | const struct task_security_struct *__tsec; |
5237 | u32 tsid; | 5151 | u32 tsid; |
5238 | 5152 | ||
5239 | __tsec = current_security(); | 5153 | __tsec = selinux_cred(current_cred()); |
5240 | tsid = __tsec->sid; | 5154 | tsid = __tsec->sid; |
5241 | 5155 | ||
5242 | return avc_has_perm(&selinux_state, | 5156 | return avc_has_perm(&selinux_state, |
@@ -5711,51 +5625,22 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) | |||
5711 | return selinux_nlmsg_perm(sk, skb); | 5625 | return selinux_nlmsg_perm(sk, skb); |
5712 | } | 5626 | } |
5713 | 5627 | ||
5714 | static int ipc_alloc_security(struct kern_ipc_perm *perm, | 5628 | static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass) |
5715 | u16 sclass) | ||
5716 | { | 5629 | { |
5717 | struct ipc_security_struct *isec; | ||
5718 | |||
5719 | isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); | ||
5720 | if (!isec) | ||
5721 | return -ENOMEM; | ||
5722 | |||
5723 | isec->sclass = sclass; | 5630 | isec->sclass = sclass; |
5724 | isec->sid = current_sid(); | 5631 | isec->sid = current_sid(); |
5725 | perm->security = isec; | ||
5726 | |||
5727 | return 0; | ||
5728 | } | ||
5729 | |||
5730 | static void ipc_free_security(struct kern_ipc_perm *perm) | ||
5731 | { | ||
5732 | struct ipc_security_struct *isec = perm->security; | ||
5733 | perm->security = NULL; | ||
5734 | kfree(isec); | ||
5735 | } | 5632 | } |
5736 | 5633 | ||
5737 | static int msg_msg_alloc_security(struct msg_msg *msg) | 5634 | static int msg_msg_alloc_security(struct msg_msg *msg) |
5738 | { | 5635 | { |
5739 | struct msg_security_struct *msec; | 5636 | struct msg_security_struct *msec; |
5740 | 5637 | ||
5741 | msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL); | 5638 | msec = selinux_msg_msg(msg); |
5742 | if (!msec) | ||
5743 | return -ENOMEM; | ||
5744 | |||
5745 | msec->sid = SECINITSID_UNLABELED; | 5639 | msec->sid = SECINITSID_UNLABELED; |
5746 | msg->security = msec; | ||
5747 | 5640 | ||
5748 | return 0; | 5641 | return 0; |
5749 | } | 5642 | } |
5750 | 5643 | ||
5751 | static void msg_msg_free_security(struct msg_msg *msg) | ||
5752 | { | ||
5753 | struct msg_security_struct *msec = msg->security; | ||
5754 | |||
5755 | msg->security = NULL; | ||
5756 | kfree(msec); | ||
5757 | } | ||
5758 | |||
5759 | static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, | 5644 | static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, |
5760 | u32 perms) | 5645 | u32 perms) |
5761 | { | 5646 | { |
@@ -5763,7 +5648,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, | |||
5763 | struct common_audit_data ad; | 5648 | struct common_audit_data ad; |
5764 | u32 sid = current_sid(); | 5649 | u32 sid = current_sid(); |
5765 | 5650 | ||
5766 | isec = ipc_perms->security; | 5651 | isec = selinux_ipc(ipc_perms); |
5767 | 5652 | ||
5768 | ad.type = LSM_AUDIT_DATA_IPC; | 5653 | ad.type = LSM_AUDIT_DATA_IPC; |
5769 | ad.u.ipc_id = ipc_perms->key; | 5654 | ad.u.ipc_id = ipc_perms->key; |
@@ -5777,11 +5662,6 @@ static int selinux_msg_msg_alloc_security(struct msg_msg *msg) | |||
5777 | return msg_msg_alloc_security(msg); | 5662 | return msg_msg_alloc_security(msg); |
5778 | } | 5663 | } |
5779 | 5664 | ||
5780 | static void selinux_msg_msg_free_security(struct msg_msg *msg) | ||
5781 | { | ||
5782 | msg_msg_free_security(msg); | ||
5783 | } | ||
5784 | |||
5785 | /* message queue security operations */ | 5665 | /* message queue security operations */ |
5786 | static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) | 5666 | static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) |
5787 | { | 5667 | { |
@@ -5790,11 +5670,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) | |||
5790 | u32 sid = current_sid(); | 5670 | u32 sid = current_sid(); |
5791 | int rc; | 5671 | int rc; |
5792 | 5672 | ||
5793 | rc = ipc_alloc_security(msq, SECCLASS_MSGQ); | 5673 | isec = selinux_ipc(msq); |
5794 | if (rc) | 5674 | ipc_init_security(isec, SECCLASS_MSGQ); |
5795 | return rc; | ||
5796 | |||
5797 | isec = msq->security; | ||
5798 | 5675 | ||
5799 | ad.type = LSM_AUDIT_DATA_IPC; | 5676 | ad.type = LSM_AUDIT_DATA_IPC; |
5800 | ad.u.ipc_id = msq->key; | 5677 | ad.u.ipc_id = msq->key; |
@@ -5802,16 +5679,7 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) | |||
5802 | rc = avc_has_perm(&selinux_state, | 5679 | rc = avc_has_perm(&selinux_state, |
5803 | sid, isec->sid, SECCLASS_MSGQ, | 5680 | sid, isec->sid, SECCLASS_MSGQ, |
5804 | MSGQ__CREATE, &ad); | 5681 | MSGQ__CREATE, &ad); |
5805 | if (rc) { | 5682 | return rc; |
5806 | ipc_free_security(msq); | ||
5807 | return rc; | ||
5808 | } | ||
5809 | return 0; | ||
5810 | } | ||
5811 | |||
5812 | static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq) | ||
5813 | { | ||
5814 | ipc_free_security(msq); | ||
5815 | } | 5683 | } |
5816 | 5684 | ||
5817 | static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) | 5685 | static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) |
@@ -5820,7 +5688,7 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) | |||
5820 | struct common_audit_data ad; | 5688 | struct common_audit_data ad; |
5821 | u32 sid = current_sid(); | 5689 | u32 sid = current_sid(); |
5822 | 5690 | ||
5823 | isec = msq->security; | 5691 | isec = selinux_ipc(msq); |
5824 | 5692 | ||
5825 | ad.type = LSM_AUDIT_DATA_IPC; | 5693 | ad.type = LSM_AUDIT_DATA_IPC; |
5826 | ad.u.ipc_id = msq->key; | 5694 | ad.u.ipc_id = msq->key; |
@@ -5869,8 +5737,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m | |||
5869 | u32 sid = current_sid(); | 5737 | u32 sid = current_sid(); |
5870 | int rc; | 5738 | int rc; |
5871 | 5739 | ||
5872 | isec = msq->security; | 5740 | isec = selinux_ipc(msq); |
5873 | msec = msg->security; | 5741 | msec = selinux_msg_msg(msg); |
5874 | 5742 | ||
5875 | /* | 5743 | /* |
5876 | * First time through, need to assign label to the message | 5744 | * First time through, need to assign label to the message |
@@ -5917,8 +5785,8 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m | |||
5917 | u32 sid = task_sid(target); | 5785 | u32 sid = task_sid(target); |
5918 | int rc; | 5786 | int rc; |
5919 | 5787 | ||
5920 | isec = msq->security; | 5788 | isec = selinux_ipc(msq); |
5921 | msec = msg->security; | 5789 | msec = selinux_msg_msg(msg); |
5922 | 5790 | ||
5923 | ad.type = LSM_AUDIT_DATA_IPC; | 5791 | ad.type = LSM_AUDIT_DATA_IPC; |
5924 | ad.u.ipc_id = msq->key; | 5792 | ad.u.ipc_id = msq->key; |
@@ -5941,11 +5809,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp) | |||
5941 | u32 sid = current_sid(); | 5809 | u32 sid = current_sid(); |
5942 | int rc; | 5810 | int rc; |
5943 | 5811 | ||
5944 | rc = ipc_alloc_security(shp, SECCLASS_SHM); | 5812 | isec = selinux_ipc(shp); |
5945 | if (rc) | 5813 | ipc_init_security(isec, SECCLASS_SHM); |
5946 | return rc; | ||
5947 | |||
5948 | isec = shp->security; | ||
5949 | 5814 | ||
5950 | ad.type = LSM_AUDIT_DATA_IPC; | 5815 | ad.type = LSM_AUDIT_DATA_IPC; |
5951 | ad.u.ipc_id = shp->key; | 5816 | ad.u.ipc_id = shp->key; |
@@ -5953,16 +5818,7 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp) | |||
5953 | rc = avc_has_perm(&selinux_state, | 5818 | rc = avc_has_perm(&selinux_state, |
5954 | sid, isec->sid, SECCLASS_SHM, | 5819 | sid, isec->sid, SECCLASS_SHM, |
5955 | SHM__CREATE, &ad); | 5820 | SHM__CREATE, &ad); |
5956 | if (rc) { | 5821 | return rc; |
5957 | ipc_free_security(shp); | ||
5958 | return rc; | ||
5959 | } | ||
5960 | return 0; | ||
5961 | } | ||
5962 | |||
5963 | static void selinux_shm_free_security(struct kern_ipc_perm *shp) | ||
5964 | { | ||
5965 | ipc_free_security(shp); | ||
5966 | } | 5822 | } |
5967 | 5823 | ||
5968 | static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) | 5824 | static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) |
@@ -5971,7 +5827,7 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) | |||
5971 | struct common_audit_data ad; | 5827 | struct common_audit_data ad; |
5972 | u32 sid = current_sid(); | 5828 | u32 sid = current_sid(); |
5973 | 5829 | ||
5974 | isec = shp->security; | 5830 | isec = selinux_ipc(shp); |
5975 | 5831 | ||
5976 | ad.type = LSM_AUDIT_DATA_IPC; | 5832 | ad.type = LSM_AUDIT_DATA_IPC; |
5977 | ad.u.ipc_id = shp->key; | 5833 | ad.u.ipc_id = shp->key; |
@@ -6038,11 +5894,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma) | |||
6038 | u32 sid = current_sid(); | 5894 | u32 sid = current_sid(); |
6039 | int rc; | 5895 | int rc; |
6040 | 5896 | ||
6041 | rc = ipc_alloc_security(sma, SECCLASS_SEM); | 5897 | isec = selinux_ipc(sma); |
6042 | if (rc) | 5898 | ipc_init_security(isec, SECCLASS_SEM); |
6043 | return rc; | ||
6044 | |||
6045 | isec = sma->security; | ||
6046 | 5899 | ||
6047 | ad.type = LSM_AUDIT_DATA_IPC; | 5900 | ad.type = LSM_AUDIT_DATA_IPC; |
6048 | ad.u.ipc_id = sma->key; | 5901 | ad.u.ipc_id = sma->key; |
@@ -6050,16 +5903,7 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma) | |||
6050 | rc = avc_has_perm(&selinux_state, | 5903 | rc = avc_has_perm(&selinux_state, |
6051 | sid, isec->sid, SECCLASS_SEM, | 5904 | sid, isec->sid, SECCLASS_SEM, |
6052 | SEM__CREATE, &ad); | 5905 | SEM__CREATE, &ad); |
6053 | if (rc) { | 5906 | return rc; |
6054 | ipc_free_security(sma); | ||
6055 | return rc; | ||
6056 | } | ||
6057 | return 0; | ||
6058 | } | ||
6059 | |||
6060 | static void selinux_sem_free_security(struct kern_ipc_perm *sma) | ||
6061 | { | ||
6062 | ipc_free_security(sma); | ||
6063 | } | 5907 | } |
6064 | 5908 | ||
6065 | static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) | 5909 | static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) |
@@ -6068,7 +5912,7 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) | |||
6068 | struct common_audit_data ad; | 5912 | struct common_audit_data ad; |
6069 | u32 sid = current_sid(); | 5913 | u32 sid = current_sid(); |
6070 | 5914 | ||
6071 | isec = sma->security; | 5915 | isec = selinux_ipc(sma); |
6072 | 5916 | ||
6073 | ad.type = LSM_AUDIT_DATA_IPC; | 5917 | ad.type = LSM_AUDIT_DATA_IPC; |
6074 | ad.u.ipc_id = sma->key; | 5918 | ad.u.ipc_id = sma->key; |
@@ -6154,7 +5998,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) | |||
6154 | 5998 | ||
6155 | static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) | 5999 | static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) |
6156 | { | 6000 | { |
6157 | struct ipc_security_struct *isec = ipcp->security; | 6001 | struct ipc_security_struct *isec = selinux_ipc(ipcp); |
6158 | *secid = isec->sid; | 6002 | *secid = isec->sid; |
6159 | } | 6003 | } |
6160 | 6004 | ||
@@ -6173,7 +6017,7 @@ static int selinux_getprocattr(struct task_struct *p, | |||
6173 | unsigned len; | 6017 | unsigned len; |
6174 | 6018 | ||
6175 | rcu_read_lock(); | 6019 | rcu_read_lock(); |
6176 | __tsec = __task_cred(p)->security; | 6020 | __tsec = selinux_cred(__task_cred(p)); |
6177 | 6021 | ||
6178 | if (current != p) { | 6022 | if (current != p) { |
6179 | error = avc_has_perm(&selinux_state, | 6023 | error = avc_has_perm(&selinux_state, |
@@ -6296,7 +6140,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) | |||
6296 | operation. See selinux_bprm_set_creds for the execve | 6140 | operation. See selinux_bprm_set_creds for the execve |
6297 | checks and may_create for the file creation checks. The | 6141 | checks and may_create for the file creation checks. The |
6298 | operation will then fail if the context is not permitted. */ | 6142 | operation will then fail if the context is not permitted. */ |
6299 | tsec = new->security; | 6143 | tsec = selinux_cred(new); |
6300 | if (!strcmp(name, "exec")) { | 6144 | if (!strcmp(name, "exec")) { |
6301 | tsec->exec_sid = sid; | 6145 | tsec->exec_sid = sid; |
6302 | } else if (!strcmp(name, "fscreate")) { | 6146 | } else if (!strcmp(name, "fscreate")) { |
@@ -6380,7 +6224,7 @@ static void selinux_release_secctx(char *secdata, u32 seclen) | |||
6380 | 6224 | ||
6381 | static void selinux_inode_invalidate_secctx(struct inode *inode) | 6225 | static void selinux_inode_invalidate_secctx(struct inode *inode) |
6382 | { | 6226 | { |
6383 | struct inode_security_struct *isec = inode->i_security; | 6227 | struct inode_security_struct *isec = selinux_inode(inode); |
6384 | 6228 | ||
6385 | spin_lock(&isec->lock); | 6229 | spin_lock(&isec->lock); |
6386 | isec->initialized = LABEL_INVALID; | 6230 | isec->initialized = LABEL_INVALID; |
@@ -6425,7 +6269,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred, | |||
6425 | if (!ksec) | 6269 | if (!ksec) |
6426 | return -ENOMEM; | 6270 | return -ENOMEM; |
6427 | 6271 | ||
6428 | tsec = cred->security; | 6272 | tsec = selinux_cred(cred); |
6429 | if (tsec->keycreate_sid) | 6273 | if (tsec->keycreate_sid) |
6430 | ksec->sid = tsec->keycreate_sid; | 6274 | ksec->sid = tsec->keycreate_sid; |
6431 | else | 6275 | else |
@@ -6688,6 +6532,14 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) | |||
6688 | } | 6532 | } |
6689 | #endif | 6533 | #endif |
6690 | 6534 | ||
6535 | struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { | ||
6536 | .lbs_cred = sizeof(struct task_security_struct), | ||
6537 | .lbs_file = sizeof(struct file_security_struct), | ||
6538 | .lbs_inode = sizeof(struct inode_security_struct), | ||
6539 | .lbs_ipc = sizeof(struct ipc_security_struct), | ||
6540 | .lbs_msg_msg = sizeof(struct msg_security_struct), | ||
6541 | }; | ||
6542 | |||
6691 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | 6543 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { |
6692 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), | 6544 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), |
6693 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), | 6545 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), |
@@ -6757,7 +6609,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6757 | 6609 | ||
6758 | LSM_HOOK_INIT(file_permission, selinux_file_permission), | 6610 | LSM_HOOK_INIT(file_permission, selinux_file_permission), |
6759 | LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), | 6611 | LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), |
6760 | LSM_HOOK_INIT(file_free_security, selinux_file_free_security), | ||
6761 | LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), | 6612 | LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), |
6762 | LSM_HOOK_INIT(mmap_file, selinux_mmap_file), | 6613 | LSM_HOOK_INIT(mmap_file, selinux_mmap_file), |
6763 | LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr), | 6614 | LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr), |
@@ -6771,8 +6622,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6771 | LSM_HOOK_INIT(file_open, selinux_file_open), | 6622 | LSM_HOOK_INIT(file_open, selinux_file_open), |
6772 | 6623 | ||
6773 | LSM_HOOK_INIT(task_alloc, selinux_task_alloc), | 6624 | LSM_HOOK_INIT(task_alloc, selinux_task_alloc), |
6774 | LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank), | ||
6775 | LSM_HOOK_INIT(cred_free, selinux_cred_free), | ||
6776 | LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), | 6625 | LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), |
6777 | LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), | 6626 | LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), |
6778 | LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), | 6627 | LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), |
@@ -6800,24 +6649,20 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6800 | LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid), | 6649 | LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid), |
6801 | 6650 | ||
6802 | LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security), | 6651 | LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security), |
6803 | LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security), | ||
6804 | 6652 | ||
6805 | LSM_HOOK_INIT(msg_queue_alloc_security, | 6653 | LSM_HOOK_INIT(msg_queue_alloc_security, |
6806 | selinux_msg_queue_alloc_security), | 6654 | selinux_msg_queue_alloc_security), |
6807 | LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security), | ||
6808 | LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate), | 6655 | LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate), |
6809 | LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl), | 6656 | LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl), |
6810 | LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd), | 6657 | LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd), |
6811 | LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv), | 6658 | LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv), |
6812 | 6659 | ||
6813 | LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security), | 6660 | LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security), |
6814 | LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security), | ||
6815 | LSM_HOOK_INIT(shm_associate, selinux_shm_associate), | 6661 | LSM_HOOK_INIT(shm_associate, selinux_shm_associate), |
6816 | LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl), | 6662 | LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl), |
6817 | LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat), | 6663 | LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat), |
6818 | 6664 | ||
6819 | LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security), | 6665 | LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security), |
6820 | LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security), | ||
6821 | LSM_HOOK_INIT(sem_associate, selinux_sem_associate), | 6666 | LSM_HOOK_INIT(sem_associate, selinux_sem_associate), |
6822 | LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl), | 6667 | LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl), |
6823 | LSM_HOOK_INIT(sem_semop, selinux_sem_semop), | 6668 | LSM_HOOK_INIT(sem_semop, selinux_sem_semop), |
@@ -6928,16 +6773,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6928 | 6773 | ||
6929 | static __init int selinux_init(void) | 6774 | static __init int selinux_init(void) |
6930 | { | 6775 | { |
6931 | if (!security_module_enable("selinux")) { | ||
6932 | selinux_enabled = 0; | ||
6933 | return 0; | ||
6934 | } | ||
6935 | |||
6936 | if (!selinux_enabled) { | ||
6937 | pr_info("SELinux: Disabled at boot.\n"); | ||
6938 | return 0; | ||
6939 | } | ||
6940 | |||
6941 | pr_info("SELinux: Initializing.\n"); | 6776 | pr_info("SELinux: Initializing.\n"); |
6942 | 6777 | ||
6943 | memset(&selinux_state, 0, sizeof(selinux_state)); | 6778 | memset(&selinux_state, 0, sizeof(selinux_state)); |
@@ -6951,12 +6786,6 @@ static __init int selinux_init(void) | |||
6951 | 6786 | ||
6952 | default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); | 6787 | default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); |
6953 | 6788 | ||
6954 | sel_inode_cache = kmem_cache_create("selinux_inode_security", | ||
6955 | sizeof(struct inode_security_struct), | ||
6956 | 0, SLAB_PANIC, NULL); | ||
6957 | file_security_cache = kmem_cache_create("selinux_file_security", | ||
6958 | sizeof(struct file_security_struct), | ||
6959 | 0, SLAB_PANIC, NULL); | ||
6960 | avc_init(); | 6789 | avc_init(); |
6961 | 6790 | ||
6962 | avtab_cache_init(); | 6791 | avtab_cache_init(); |
@@ -6999,6 +6828,9 @@ void selinux_complete_init(void) | |||
6999 | all processes and objects when they are created. */ | 6828 | all processes and objects when they are created. */ |
7000 | DEFINE_LSM(selinux) = { | 6829 | DEFINE_LSM(selinux) = { |
7001 | .name = "selinux", | 6830 | .name = "selinux", |
6831 | .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, | ||
6832 | .enabled = &selinux_enabled, | ||
6833 | .blobs = &selinux_blob_sizes, | ||
7002 | .init = selinux_init, | 6834 | .init = selinux_init, |
7003 | }; | 6835 | }; |
7004 | 6836 | ||
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 1bdf973433cc..36e1d44c0209 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h | |||
@@ -1,9 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * SELinux support for the Audit LSM hooks | 2 | * SELinux support for the Audit LSM hooks |
3 | * | 3 | * |
4 | * Most of below header was moved from include/linux/selinux.h which | ||
5 | * is released under below copyrights: | ||
6 | * | ||
7 | * Author: James Morris <jmorris@redhat.com> | 4 | * Author: James Morris <jmorris@redhat.com> |
8 | * | 5 | * |
9 | * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com> | 6 | * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com> |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index cc5e26b0161b..231262d8eac9 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <linux/binfmts.h> | 25 | #include <linux/binfmts.h> |
26 | #include <linux/in.h> | 26 | #include <linux/in.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/lsm_hooks.h> | ||
29 | #include <linux/msg.h> | ||
28 | #include <net/net_namespace.h> | 30 | #include <net/net_namespace.h> |
29 | #include "flask.h" | 31 | #include "flask.h" |
30 | #include "avc.h" | 32 | #include "avc.h" |
@@ -56,10 +58,7 @@ enum label_initialized { | |||
56 | 58 | ||
57 | struct inode_security_struct { | 59 | struct inode_security_struct { |
58 | struct inode *inode; /* back pointer to inode object */ | 60 | struct inode *inode; /* back pointer to inode object */ |
59 | union { | 61 | struct list_head list; /* list of inode_security_struct */ |
60 | struct list_head list; /* list of inode_security_struct */ | ||
61 | struct rcu_head rcu; /* for freeing the inode_security_struct */ | ||
62 | }; | ||
63 | u32 task_sid; /* SID of creating task */ | 62 | u32 task_sid; /* SID of creating task */ |
64 | u32 sid; /* SID of this object */ | 63 | u32 sid; /* SID of this object */ |
65 | u16 sclass; /* security class of this object */ | 64 | u16 sclass; /* security class of this object */ |
@@ -158,4 +157,35 @@ struct bpf_security_struct { | |||
158 | u32 sid; /*SID of bpf obj creater*/ | 157 | u32 sid; /*SID of bpf obj creater*/ |
159 | }; | 158 | }; |
160 | 159 | ||
160 | extern struct lsm_blob_sizes selinux_blob_sizes; | ||
161 | static inline struct task_security_struct *selinux_cred(const struct cred *cred) | ||
162 | { | ||
163 | return cred->security + selinux_blob_sizes.lbs_cred; | ||
164 | } | ||
165 | |||
166 | static inline struct file_security_struct *selinux_file(const struct file *file) | ||
167 | { | ||
168 | return file->f_security + selinux_blob_sizes.lbs_file; | ||
169 | } | ||
170 | |||
171 | static inline struct inode_security_struct *selinux_inode( | ||
172 | const struct inode *inode) | ||
173 | { | ||
174 | if (unlikely(!inode->i_security)) | ||
175 | return NULL; | ||
176 | return inode->i_security + selinux_blob_sizes.lbs_inode; | ||
177 | } | ||
178 | |||
179 | static inline struct msg_security_struct *selinux_msg_msg( | ||
180 | const struct msg_msg *msg_msg) | ||
181 | { | ||
182 | return msg_msg->security + selinux_blob_sizes.lbs_msg_msg; | ||
183 | } | ||
184 | |||
185 | static inline struct ipc_security_struct *selinux_ipc( | ||
186 | const struct kern_ipc_perm *ipc) | ||
187 | { | ||
188 | return ipc->security + selinux_blob_sizes.lbs_ipc; | ||
189 | } | ||
190 | |||
161 | #endif /* _SELINUX_OBJSEC_H_ */ | 191 | #endif /* _SELINUX_OBJSEC_H_ */ |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index f3a5a138a096..145ee62f205a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -1378,7 +1378,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi) | |||
1378 | goto out; | 1378 | goto out; |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | isec = (struct inode_security_struct *)inode->i_security; | 1381 | isec = selinux_inode(inode); |
1382 | ret = security_genfs_sid(fsi->state, "selinuxfs", page, | 1382 | ret = security_genfs_sid(fsi->state, "selinuxfs", page, |
1383 | SECCLASS_FILE, &sid); | 1383 | SECCLASS_FILE, &sid); |
1384 | if (ret) { | 1384 | if (ret) { |
@@ -1953,7 +1953,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1953 | } | 1953 | } |
1954 | 1954 | ||
1955 | inode->i_ino = ++fsi->last_ino; | 1955 | inode->i_ino = ++fsi->last_ino; |
1956 | isec = (struct inode_security_struct *)inode->i_security; | 1956 | isec = selinux_inode(inode); |
1957 | isec->sid = SECINITSID_DEVNULL; | 1957 | isec->sid = SECINITSID_DEVNULL; |
1958 | isec->sclass = SECCLASS_CHR_FILE; | 1958 | isec->sclass = SECCLASS_CHR_FILE; |
1959 | isec->initialized = LABEL_INITIALIZED; | 1959 | isec->initialized = LABEL_INITIALIZED; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index dd44126c8d14..d6e7b4856d93 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -49,7 +49,6 @@ | |||
49 | #include <linux/sched.h> | 49 | #include <linux/sched.h> |
50 | #include <linux/audit.h> | 50 | #include <linux/audit.h> |
51 | #include <linux/mutex.h> | 51 | #include <linux/mutex.h> |
52 | #include <linux/selinux.h> | ||
53 | #include <linux/flex_array.h> | 52 | #include <linux/flex_array.h> |
54 | #include <linux/vmalloc.h> | 53 | #include <linux/vmalloc.h> |
55 | #include <net/netlabel.h> | 54 | #include <net/netlabel.h> |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index bd7d18bdb147..7c57cb7e4146 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -79,7 +79,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, | |||
79 | gfp_t gfp) | 79 | gfp_t gfp) |
80 | { | 80 | { |
81 | int rc; | 81 | int rc; |
82 | const struct task_security_struct *tsec = current_security(); | 82 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
83 | struct xfrm_sec_ctx *ctx = NULL; | 83 | struct xfrm_sec_ctx *ctx = NULL; |
84 | u32 str_len; | 84 | u32 str_len; |
85 | 85 | ||
@@ -138,7 +138,7 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx) | |||
138 | */ | 138 | */ |
139 | static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) | 139 | static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) |
140 | { | 140 | { |
141 | const struct task_security_struct *tsec = current_security(); | 141 | const struct task_security_struct *tsec = selinux_cred(current_cred()); |
142 | 142 | ||
143 | if (!ctx) | 143 | if (!ctx) |
144 | return 0; | 144 | return 0; |
diff --git a/security/smack/smack.h b/security/smack/smack.h index f7db791fb566..9c7c95a5c497 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/rculist.h> | 25 | #include <linux/rculist.h> |
26 | #include <linux/lsm_audit.h> | 26 | #include <linux/lsm_audit.h> |
27 | #include <linux/msg.h> | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * Use IPv6 port labeling if IPv6 is enabled and secmarks | 30 | * Use IPv6 port labeling if IPv6 is enabled and secmarks |
@@ -336,6 +337,7 @@ extern struct smack_known *smack_syslog_label; | |||
336 | extern struct smack_known *smack_unconfined; | 337 | extern struct smack_known *smack_unconfined; |
337 | #endif | 338 | #endif |
338 | extern int smack_ptrace_rule; | 339 | extern int smack_ptrace_rule; |
340 | extern struct lsm_blob_sizes smack_blob_sizes; | ||
339 | 341 | ||
340 | extern struct smack_known smack_known_floor; | 342 | extern struct smack_known smack_known_floor; |
341 | extern struct smack_known smack_known_hat; | 343 | extern struct smack_known smack_known_hat; |
@@ -356,12 +358,38 @@ extern struct list_head smack_onlycap_list; | |||
356 | #define SMACK_HASH_SLOTS 16 | 358 | #define SMACK_HASH_SLOTS 16 |
357 | extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; | 359 | extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; |
358 | 360 | ||
361 | static inline struct task_smack *smack_cred(const struct cred *cred) | ||
362 | { | ||
363 | return cred->security + smack_blob_sizes.lbs_cred; | ||
364 | } | ||
365 | |||
366 | static inline struct smack_known **smack_file(const struct file *file) | ||
367 | { | ||
368 | return (struct smack_known **)(file->f_security + | ||
369 | smack_blob_sizes.lbs_file); | ||
370 | } | ||
371 | |||
372 | static inline struct inode_smack *smack_inode(const struct inode *inode) | ||
373 | { | ||
374 | return inode->i_security + smack_blob_sizes.lbs_inode; | ||
375 | } | ||
376 | |||
377 | static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg) | ||
378 | { | ||
379 | return msg->security + smack_blob_sizes.lbs_msg_msg; | ||
380 | } | ||
381 | |||
382 | static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc) | ||
383 | { | ||
384 | return ipc->security + smack_blob_sizes.lbs_ipc; | ||
385 | } | ||
386 | |||
359 | /* | 387 | /* |
360 | * Is the directory transmuting? | 388 | * Is the directory transmuting? |
361 | */ | 389 | */ |
362 | static inline int smk_inode_transmutable(const struct inode *isp) | 390 | static inline int smk_inode_transmutable(const struct inode *isp) |
363 | { | 391 | { |
364 | struct inode_smack *sip = isp->i_security; | 392 | struct inode_smack *sip = smack_inode(isp); |
365 | return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0; | 393 | return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0; |
366 | } | 394 | } |
367 | 395 | ||
@@ -370,7 +398,7 @@ static inline int smk_inode_transmutable(const struct inode *isp) | |||
370 | */ | 398 | */ |
371 | static inline struct smack_known *smk_of_inode(const struct inode *isp) | 399 | static inline struct smack_known *smk_of_inode(const struct inode *isp) |
372 | { | 400 | { |
373 | struct inode_smack *sip = isp->i_security; | 401 | struct inode_smack *sip = smack_inode(isp); |
374 | return sip->smk_inode; | 402 | return sip->smk_inode; |
375 | } | 403 | } |
376 | 404 | ||
@@ -382,13 +410,19 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp) | |||
382 | return tsp->smk_task; | 410 | return tsp->smk_task; |
383 | } | 411 | } |
384 | 412 | ||
385 | static inline struct smack_known *smk_of_task_struct(const struct task_struct *t) | 413 | static inline struct smack_known *smk_of_task_struct( |
414 | const struct task_struct *t) | ||
386 | { | 415 | { |
387 | struct smack_known *skp; | 416 | struct smack_known *skp; |
417 | const struct cred *cred; | ||
388 | 418 | ||
389 | rcu_read_lock(); | 419 | rcu_read_lock(); |
390 | skp = smk_of_task(__task_cred(t)->security); | 420 | |
421 | cred = __task_cred(t); | ||
422 | skp = smk_of_task(smack_cred(cred)); | ||
423 | |||
391 | rcu_read_unlock(); | 424 | rcu_read_unlock(); |
425 | |||
392 | return skp; | 426 | return skp; |
393 | } | 427 | } |
394 | 428 | ||
@@ -405,7 +439,7 @@ static inline struct smack_known *smk_of_forked(const struct task_smack *tsp) | |||
405 | */ | 439 | */ |
406 | static inline struct smack_known *smk_of_current(void) | 440 | static inline struct smack_known *smk_of_current(void) |
407 | { | 441 | { |
408 | return smk_of_task(current_security()); | 442 | return smk_of_task(smack_cred(current_cred())); |
409 | } | 443 | } |
410 | 444 | ||
411 | /* | 445 | /* |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 9a4c0ad46518..fe2ce3a65822 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -275,7 +275,7 @@ out_audit: | |||
275 | int smk_curacc(struct smack_known *obj_known, | 275 | int smk_curacc(struct smack_known *obj_known, |
276 | u32 mode, struct smk_audit_info *a) | 276 | u32 mode, struct smk_audit_info *a) |
277 | { | 277 | { |
278 | struct task_smack *tsp = current_security(); | 278 | struct task_smack *tsp = smack_cred(current_cred()); |
279 | 279 | ||
280 | return smk_tskacc(tsp, obj_known, mode, a); | 280 | return smk_tskacc(tsp, obj_known, mode, a); |
281 | } | 281 | } |
@@ -635,12 +635,12 @@ DEFINE_MUTEX(smack_onlycap_lock); | |||
635 | */ | 635 | */ |
636 | bool smack_privileged_cred(int cap, const struct cred *cred) | 636 | bool smack_privileged_cred(int cap, const struct cred *cred) |
637 | { | 637 | { |
638 | struct task_smack *tsp = cred->security; | 638 | struct task_smack *tsp = smack_cred(cred); |
639 | struct smack_known *skp = tsp->smk_task; | 639 | struct smack_known *skp = tsp->smk_task; |
640 | struct smack_known_list_elem *sklep; | 640 | struct smack_known_list_elem *sklep; |
641 | int rc; | 641 | int rc; |
642 | 642 | ||
643 | rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT); | 643 | rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE); |
644 | if (rc) | 644 | if (rc) |
645 | return false; | 645 | return false; |
646 | 646 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 430d4f35e55c..2309c696c6c8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -139,7 +139,7 @@ static int smk_bu_note(char *note, struct smack_known *sskp, | |||
139 | static int smk_bu_current(char *note, struct smack_known *oskp, | 139 | static int smk_bu_current(char *note, struct smack_known *oskp, |
140 | int mode, int rc) | 140 | int mode, int rc) |
141 | { | 141 | { |
142 | struct task_smack *tsp = current_security(); | 142 | struct task_smack *tsp = smack_cred(current_cred()); |
143 | char acc[SMK_NUM_ACCESS_TYPE + 1]; | 143 | char acc[SMK_NUM_ACCESS_TYPE + 1]; |
144 | 144 | ||
145 | if (rc <= 0) | 145 | if (rc <= 0) |
@@ -160,7 +160,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp, | |||
160 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 160 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
161 | static int smk_bu_task(struct task_struct *otp, int mode, int rc) | 161 | static int smk_bu_task(struct task_struct *otp, int mode, int rc) |
162 | { | 162 | { |
163 | struct task_smack *tsp = current_security(); | 163 | struct task_smack *tsp = smack_cred(current_cred()); |
164 | struct smack_known *smk_task = smk_of_task_struct(otp); | 164 | struct smack_known *smk_task = smk_of_task_struct(otp); |
165 | char acc[SMK_NUM_ACCESS_TYPE + 1]; | 165 | char acc[SMK_NUM_ACCESS_TYPE + 1]; |
166 | 166 | ||
@@ -182,8 +182,8 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc) | |||
182 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 182 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
183 | static int smk_bu_inode(struct inode *inode, int mode, int rc) | 183 | static int smk_bu_inode(struct inode *inode, int mode, int rc) |
184 | { | 184 | { |
185 | struct task_smack *tsp = current_security(); | 185 | struct task_smack *tsp = smack_cred(current_cred()); |
186 | struct inode_smack *isp = inode->i_security; | 186 | struct inode_smack *isp = smack_inode(inode); |
187 | char acc[SMK_NUM_ACCESS_TYPE + 1]; | 187 | char acc[SMK_NUM_ACCESS_TYPE + 1]; |
188 | 188 | ||
189 | if (isp->smk_flags & SMK_INODE_IMPURE) | 189 | if (isp->smk_flags & SMK_INODE_IMPURE) |
@@ -212,10 +212,10 @@ static int smk_bu_inode(struct inode *inode, int mode, int rc) | |||
212 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 212 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
213 | static int smk_bu_file(struct file *file, int mode, int rc) | 213 | static int smk_bu_file(struct file *file, int mode, int rc) |
214 | { | 214 | { |
215 | struct task_smack *tsp = current_security(); | 215 | struct task_smack *tsp = smack_cred(current_cred()); |
216 | struct smack_known *sskp = tsp->smk_task; | 216 | struct smack_known *sskp = tsp->smk_task; |
217 | struct inode *inode = file_inode(file); | 217 | struct inode *inode = file_inode(file); |
218 | struct inode_smack *isp = inode->i_security; | 218 | struct inode_smack *isp = smack_inode(inode); |
219 | char acc[SMK_NUM_ACCESS_TYPE + 1]; | 219 | char acc[SMK_NUM_ACCESS_TYPE + 1]; |
220 | 220 | ||
221 | if (isp->smk_flags & SMK_INODE_IMPURE) | 221 | if (isp->smk_flags & SMK_INODE_IMPURE) |
@@ -242,10 +242,10 @@ static int smk_bu_file(struct file *file, int mode, int rc) | |||
242 | static int smk_bu_credfile(const struct cred *cred, struct file *file, | 242 | static int smk_bu_credfile(const struct cred *cred, struct file *file, |
243 | int mode, int rc) | 243 | int mode, int rc) |
244 | { | 244 | { |
245 | struct task_smack *tsp = cred->security; | 245 | struct task_smack *tsp = smack_cred(cred); |
246 | struct smack_known *sskp = tsp->smk_task; | 246 | struct smack_known *sskp = tsp->smk_task; |
247 | struct inode *inode = file_inode(file); | 247 | struct inode *inode = file_inode(file); |
248 | struct inode_smack *isp = inode->i_security; | 248 | struct inode_smack *isp = smack_inode(inode); |
249 | char acc[SMK_NUM_ACCESS_TYPE + 1]; | 249 | char acc[SMK_NUM_ACCESS_TYPE + 1]; |
250 | 250 | ||
251 | if (isp->smk_flags & SMK_INODE_IMPURE) | 251 | if (isp->smk_flags & SMK_INODE_IMPURE) |
@@ -305,50 +305,35 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, | |||
305 | } | 305 | } |
306 | 306 | ||
307 | /** | 307 | /** |
308 | * new_inode_smack - allocate an inode security blob | 308 | * init_inode_smack - initialize an inode security blob |
309 | * @isp: the blob to initialize | ||
309 | * @skp: a pointer to the Smack label entry to use in the blob | 310 | * @skp: a pointer to the Smack label entry to use in the blob |
310 | * | 311 | * |
311 | * Returns the new blob or NULL if there's no memory available | ||
312 | */ | 312 | */ |
313 | static struct inode_smack *new_inode_smack(struct smack_known *skp) | 313 | static void init_inode_smack(struct inode *inode, struct smack_known *skp) |
314 | { | 314 | { |
315 | struct inode_smack *isp; | 315 | struct inode_smack *isp = smack_inode(inode); |
316 | |||
317 | isp = kmem_cache_zalloc(smack_inode_cache, GFP_NOFS); | ||
318 | if (isp == NULL) | ||
319 | return NULL; | ||
320 | 316 | ||
321 | isp->smk_inode = skp; | 317 | isp->smk_inode = skp; |
322 | isp->smk_flags = 0; | 318 | isp->smk_flags = 0; |
323 | mutex_init(&isp->smk_lock); | 319 | mutex_init(&isp->smk_lock); |
324 | |||
325 | return isp; | ||
326 | } | 320 | } |
327 | 321 | ||
328 | /** | 322 | /** |
329 | * new_task_smack - allocate a task security blob | 323 | * init_task_smack - initialize a task security blob |
324 | * @tsp: blob to initialize | ||
330 | * @task: a pointer to the Smack label for the running task | 325 | * @task: a pointer to the Smack label for the running task |
331 | * @forked: a pointer to the Smack label for the forked task | 326 | * @forked: a pointer to the Smack label for the forked task |
332 | * @gfp: type of the memory for the allocation | ||
333 | * | 327 | * |
334 | * Returns the new blob or NULL if there's no memory available | ||
335 | */ | 328 | */ |
336 | static struct task_smack *new_task_smack(struct smack_known *task, | 329 | static void init_task_smack(struct task_smack *tsp, struct smack_known *task, |
337 | struct smack_known *forked, gfp_t gfp) | 330 | struct smack_known *forked) |
338 | { | 331 | { |
339 | struct task_smack *tsp; | ||
340 | |||
341 | tsp = kzalloc(sizeof(struct task_smack), gfp); | ||
342 | if (tsp == NULL) | ||
343 | return NULL; | ||
344 | |||
345 | tsp->smk_task = task; | 332 | tsp->smk_task = task; |
346 | tsp->smk_forked = forked; | 333 | tsp->smk_forked = forked; |
347 | INIT_LIST_HEAD(&tsp->smk_rules); | 334 | INIT_LIST_HEAD(&tsp->smk_rules); |
348 | INIT_LIST_HEAD(&tsp->smk_relabel); | 335 | INIT_LIST_HEAD(&tsp->smk_relabel); |
349 | mutex_init(&tsp->smk_rules_lock); | 336 | mutex_init(&tsp->smk_rules_lock); |
350 | |||
351 | return tsp; | ||
352 | } | 337 | } |
353 | 338 | ||
354 | /** | 339 | /** |
@@ -448,7 +433,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, | |||
448 | 433 | ||
449 | rcu_read_lock(); | 434 | rcu_read_lock(); |
450 | tracercred = __task_cred(tracer); | 435 | tracercred = __task_cred(tracer); |
451 | tsp = tracercred->security; | 436 | tsp = smack_cred(tracercred); |
452 | tracer_known = smk_of_task(tsp); | 437 | tracer_known = smk_of_task(tsp); |
453 | 438 | ||
454 | if ((mode & PTRACE_MODE_ATTACH) && | 439 | if ((mode & PTRACE_MODE_ATTACH) && |
@@ -515,7 +500,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
515 | int rc; | 500 | int rc; |
516 | struct smack_known *skp; | 501 | struct smack_known *skp; |
517 | 502 | ||
518 | skp = smk_of_task(current_security()); | 503 | skp = smk_of_task(smack_cred(current_cred())); |
519 | 504 | ||
520 | rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); | 505 | rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); |
521 | return rc; | 506 | return rc; |
@@ -718,6 +703,13 @@ static int smack_set_mnt_opts(struct super_block *sb, | |||
718 | if (sp->smk_flags & SMK_SB_INITIALIZED) | 703 | if (sp->smk_flags & SMK_SB_INITIALIZED) |
719 | return 0; | 704 | return 0; |
720 | 705 | ||
706 | if (inode->i_security == NULL) { | ||
707 | int rc = lsm_inode_alloc(inode); | ||
708 | |||
709 | if (rc) | ||
710 | return rc; | ||
711 | } | ||
712 | |||
721 | if (!smack_privileged(CAP_MAC_ADMIN)) { | 713 | if (!smack_privileged(CAP_MAC_ADMIN)) { |
722 | /* | 714 | /* |
723 | * Unprivileged mounts don't get to specify Smack values. | 715 | * Unprivileged mounts don't get to specify Smack values. |
@@ -782,17 +774,12 @@ static int smack_set_mnt_opts(struct super_block *sb, | |||
782 | /* | 774 | /* |
783 | * Initialize the root inode. | 775 | * Initialize the root inode. |
784 | */ | 776 | */ |
785 | isp = inode->i_security; | 777 | init_inode_smack(inode, sp->smk_root); |
786 | if (isp == NULL) { | ||
787 | isp = new_inode_smack(sp->smk_root); | ||
788 | if (isp == NULL) | ||
789 | return -ENOMEM; | ||
790 | inode->i_security = isp; | ||
791 | } else | ||
792 | isp->smk_inode = sp->smk_root; | ||
793 | 778 | ||
794 | if (transmute) | 779 | if (transmute) { |
780 | isp = smack_inode(inode); | ||
795 | isp->smk_flags |= SMK_INODE_TRANSMUTE; | 781 | isp->smk_flags |= SMK_INODE_TRANSMUTE; |
782 | } | ||
796 | 783 | ||
797 | return 0; | 784 | return 0; |
798 | } | 785 | } |
@@ -831,7 +818,7 @@ static int smack_sb_statfs(struct dentry *dentry) | |||
831 | static int smack_bprm_set_creds(struct linux_binprm *bprm) | 818 | static int smack_bprm_set_creds(struct linux_binprm *bprm) |
832 | { | 819 | { |
833 | struct inode *inode = file_inode(bprm->file); | 820 | struct inode *inode = file_inode(bprm->file); |
834 | struct task_smack *bsp = bprm->cred->security; | 821 | struct task_smack *bsp = smack_cred(bprm->cred); |
835 | struct inode_smack *isp; | 822 | struct inode_smack *isp; |
836 | struct superblock_smack *sbsp; | 823 | struct superblock_smack *sbsp; |
837 | int rc; | 824 | int rc; |
@@ -839,7 +826,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) | |||
839 | if (bprm->called_set_creds) | 826 | if (bprm->called_set_creds) |
840 | return 0; | 827 | return 0; |
841 | 828 | ||
842 | isp = inode->i_security; | 829 | isp = smack_inode(inode); |
843 | if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) | 830 | if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) |
844 | return 0; | 831 | return 0; |
845 | 832 | ||
@@ -890,49 +877,11 @@ static int smack_inode_alloc_security(struct inode *inode) | |||
890 | { | 877 | { |
891 | struct smack_known *skp = smk_of_current(); | 878 | struct smack_known *skp = smk_of_current(); |
892 | 879 | ||
893 | inode->i_security = new_inode_smack(skp); | 880 | init_inode_smack(inode, skp); |
894 | if (inode->i_security == NULL) | ||
895 | return -ENOMEM; | ||
896 | return 0; | 881 | return 0; |
897 | } | 882 | } |
898 | 883 | ||
899 | /** | 884 | /** |
900 | * smack_inode_free_rcu - Free inode_smack blob from cache | ||
901 | * @head: the rcu_head for getting inode_smack pointer | ||
902 | * | ||
903 | * Call back function called from call_rcu() to free | ||
904 | * the i_security blob pointer in inode | ||
905 | */ | ||
906 | static void smack_inode_free_rcu(struct rcu_head *head) | ||
907 | { | ||
908 | struct inode_smack *issp; | ||
909 | |||
910 | issp = container_of(head, struct inode_smack, smk_rcu); | ||
911 | kmem_cache_free(smack_inode_cache, issp); | ||
912 | } | ||
913 | |||
914 | /** | ||
915 | * smack_inode_free_security - free an inode blob using call_rcu() | ||
916 | * @inode: the inode with a blob | ||
917 | * | ||
918 | * Clears the blob pointer in inode using RCU | ||
919 | */ | ||
920 | static void smack_inode_free_security(struct inode *inode) | ||
921 | { | ||
922 | struct inode_smack *issp = inode->i_security; | ||
923 | |||
924 | /* | ||
925 | * The inode may still be referenced in a path walk and | ||
926 | * a call to smack_inode_permission() can be made | ||
927 | * after smack_inode_free_security() is called. | ||
928 | * To avoid race condition free the i_security via RCU | ||
929 | * and leave the current inode->i_security pointer intact. | ||
930 | * The inode will be freed after the RCU grace period too. | ||
931 | */ | ||
932 | call_rcu(&issp->smk_rcu, smack_inode_free_rcu); | ||
933 | } | ||
934 | |||
935 | /** | ||
936 | * smack_inode_init_security - copy out the smack from an inode | 885 | * smack_inode_init_security - copy out the smack from an inode |
937 | * @inode: the newly created inode | 886 | * @inode: the newly created inode |
938 | * @dir: containing directory object | 887 | * @dir: containing directory object |
@@ -947,7 +896,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
947 | const struct qstr *qstr, const char **name, | 896 | const struct qstr *qstr, const char **name, |
948 | void **value, size_t *len) | 897 | void **value, size_t *len) |
949 | { | 898 | { |
950 | struct inode_smack *issp = inode->i_security; | 899 | struct inode_smack *issp = smack_inode(inode); |
951 | struct smack_known *skp = smk_of_current(); | 900 | struct smack_known *skp = smk_of_current(); |
952 | struct smack_known *isp = smk_of_inode(inode); | 901 | struct smack_known *isp = smk_of_inode(inode); |
953 | struct smack_known *dsp = smk_of_inode(dir); | 902 | struct smack_known *dsp = smk_of_inode(dir); |
@@ -1285,7 +1234,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
1285 | const void *value, size_t size, int flags) | 1234 | const void *value, size_t size, int flags) |
1286 | { | 1235 | { |
1287 | struct smack_known *skp; | 1236 | struct smack_known *skp; |
1288 | struct inode_smack *isp = d_backing_inode(dentry)->i_security; | 1237 | struct inode_smack *isp = smack_inode(d_backing_inode(dentry)); |
1289 | 1238 | ||
1290 | if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 1239 | if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { |
1291 | isp->smk_flags |= SMK_INODE_TRANSMUTE; | 1240 | isp->smk_flags |= SMK_INODE_TRANSMUTE; |
@@ -1366,7 +1315,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
1366 | if (rc != 0) | 1315 | if (rc != 0) |
1367 | return rc; | 1316 | return rc; |
1368 | 1317 | ||
1369 | isp = d_backing_inode(dentry)->i_security; | 1318 | isp = smack_inode(d_backing_inode(dentry)); |
1370 | /* | 1319 | /* |
1371 | * Don't do anything special for these. | 1320 | * Don't do anything special for these. |
1372 | * XATTR_NAME_SMACKIPIN | 1321 | * XATTR_NAME_SMACKIPIN |
@@ -1498,25 +1447,13 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid) | |||
1498 | */ | 1447 | */ |
1499 | static int smack_file_alloc_security(struct file *file) | 1448 | static int smack_file_alloc_security(struct file *file) |
1500 | { | 1449 | { |
1501 | struct smack_known *skp = smk_of_current(); | 1450 | struct smack_known **blob = smack_file(file); |
1502 | 1451 | ||
1503 | file->f_security = skp; | 1452 | *blob = smk_of_current(); |
1504 | return 0; | 1453 | return 0; |
1505 | } | 1454 | } |
1506 | 1455 | ||
1507 | /** | 1456 | /** |
1508 | * smack_file_free_security - clear a file security blob | ||
1509 | * @file: the object | ||
1510 | * | ||
1511 | * The security blob for a file is a pointer to the master | ||
1512 | * label list, so no memory is freed. | ||
1513 | */ | ||
1514 | static void smack_file_free_security(struct file *file) | ||
1515 | { | ||
1516 | file->f_security = NULL; | ||
1517 | } | ||
1518 | |||
1519 | /** | ||
1520 | * smack_file_ioctl - Smack check on ioctls | 1457 | * smack_file_ioctl - Smack check on ioctls |
1521 | * @file: the object | 1458 | * @file: the object |
1522 | * @cmd: what to do | 1459 | * @cmd: what to do |
@@ -1653,7 +1590,7 @@ static int smack_mmap_file(struct file *file, | |||
1653 | if (unlikely(IS_PRIVATE(file_inode(file)))) | 1590 | if (unlikely(IS_PRIVATE(file_inode(file)))) |
1654 | return 0; | 1591 | return 0; |
1655 | 1592 | ||
1656 | isp = file_inode(file)->i_security; | 1593 | isp = smack_inode(file_inode(file)); |
1657 | if (isp->smk_mmap == NULL) | 1594 | if (isp->smk_mmap == NULL) |
1658 | return 0; | 1595 | return 0; |
1659 | sbsp = file_inode(file)->i_sb->s_security; | 1596 | sbsp = file_inode(file)->i_sb->s_security; |
@@ -1662,7 +1599,7 @@ static int smack_mmap_file(struct file *file, | |||
1662 | return -EACCES; | 1599 | return -EACCES; |
1663 | mkp = isp->smk_mmap; | 1600 | mkp = isp->smk_mmap; |
1664 | 1601 | ||
1665 | tsp = current_security(); | 1602 | tsp = smack_cred(current_cred()); |
1666 | skp = smk_of_current(); | 1603 | skp = smk_of_current(); |
1667 | rc = 0; | 1604 | rc = 0; |
1668 | 1605 | ||
@@ -1740,7 +1677,9 @@ static int smack_mmap_file(struct file *file, | |||
1740 | */ | 1677 | */ |
1741 | static void smack_file_set_fowner(struct file *file) | 1678 | static void smack_file_set_fowner(struct file *file) |
1742 | { | 1679 | { |
1743 | file->f_security = smk_of_current(); | 1680 | struct smack_known **blob = smack_file(file); |
1681 | |||
1682 | *blob = smk_of_current(); | ||
1744 | } | 1683 | } |
1745 | 1684 | ||
1746 | /** | 1685 | /** |
@@ -1757,8 +1696,9 @@ static void smack_file_set_fowner(struct file *file) | |||
1757 | static int smack_file_send_sigiotask(struct task_struct *tsk, | 1696 | static int smack_file_send_sigiotask(struct task_struct *tsk, |
1758 | struct fown_struct *fown, int signum) | 1697 | struct fown_struct *fown, int signum) |
1759 | { | 1698 | { |
1699 | struct smack_known **blob; | ||
1760 | struct smack_known *skp; | 1700 | struct smack_known *skp; |
1761 | struct smack_known *tkp = smk_of_task(tsk->cred->security); | 1701 | struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred)); |
1762 | const struct cred *tcred; | 1702 | const struct cred *tcred; |
1763 | struct file *file; | 1703 | struct file *file; |
1764 | int rc; | 1704 | int rc; |
@@ -1770,7 +1710,8 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, | |||
1770 | file = container_of(fown, struct file, f_owner); | 1710 | file = container_of(fown, struct file, f_owner); |
1771 | 1711 | ||
1772 | /* we don't log here as rc can be overriden */ | 1712 | /* we don't log here as rc can be overriden */ |
1773 | skp = file->f_security; | 1713 | blob = smack_file(file); |
1714 | skp = *blob; | ||
1774 | rc = smk_access(skp, tkp, MAY_DELIVER, NULL); | 1715 | rc = smk_access(skp, tkp, MAY_DELIVER, NULL); |
1775 | rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc); | 1716 | rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc); |
1776 | 1717 | ||
@@ -1811,7 +1752,7 @@ static int smack_file_receive(struct file *file) | |||
1811 | if (inode->i_sb->s_magic == SOCKFS_MAGIC) { | 1752 | if (inode->i_sb->s_magic == SOCKFS_MAGIC) { |
1812 | sock = SOCKET_I(inode); | 1753 | sock = SOCKET_I(inode); |
1813 | ssp = sock->sk->sk_security; | 1754 | ssp = sock->sk->sk_security; |
1814 | tsp = current_security(); | 1755 | tsp = smack_cred(current_cred()); |
1815 | /* | 1756 | /* |
1816 | * If the receiving process can't write to the | 1757 | * If the receiving process can't write to the |
1817 | * passed socket or if the passed socket can't | 1758 | * passed socket or if the passed socket can't |
@@ -1853,7 +1794,7 @@ static int smack_file_receive(struct file *file) | |||
1853 | */ | 1794 | */ |
1854 | static int smack_file_open(struct file *file) | 1795 | static int smack_file_open(struct file *file) |
1855 | { | 1796 | { |
1856 | struct task_smack *tsp = file->f_cred->security; | 1797 | struct task_smack *tsp = smack_cred(file->f_cred); |
1857 | struct inode *inode = file_inode(file); | 1798 | struct inode *inode = file_inode(file); |
1858 | struct smk_audit_info ad; | 1799 | struct smk_audit_info ad; |
1859 | int rc; | 1800 | int rc; |
@@ -1881,14 +1822,7 @@ static int smack_file_open(struct file *file) | |||
1881 | */ | 1822 | */ |
1882 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | 1823 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) |
1883 | { | 1824 | { |
1884 | struct task_smack *tsp; | 1825 | init_task_smack(smack_cred(cred), NULL, NULL); |
1885 | |||
1886 | tsp = new_task_smack(NULL, NULL, gfp); | ||
1887 | if (tsp == NULL) | ||
1888 | return -ENOMEM; | ||
1889 | |||
1890 | cred->security = tsp; | ||
1891 | |||
1892 | return 0; | 1826 | return 0; |
1893 | } | 1827 | } |
1894 | 1828 | ||
@@ -1900,15 +1834,11 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | |||
1900 | */ | 1834 | */ |
1901 | static void smack_cred_free(struct cred *cred) | 1835 | static void smack_cred_free(struct cred *cred) |
1902 | { | 1836 | { |
1903 | struct task_smack *tsp = cred->security; | 1837 | struct task_smack *tsp = smack_cred(cred); |
1904 | struct smack_rule *rp; | 1838 | struct smack_rule *rp; |
1905 | struct list_head *l; | 1839 | struct list_head *l; |
1906 | struct list_head *n; | 1840 | struct list_head *n; |
1907 | 1841 | ||
1908 | if (tsp == NULL) | ||
1909 | return; | ||
1910 | cred->security = NULL; | ||
1911 | |||
1912 | smk_destroy_label_list(&tsp->smk_relabel); | 1842 | smk_destroy_label_list(&tsp->smk_relabel); |
1913 | 1843 | ||
1914 | list_for_each_safe(l, n, &tsp->smk_rules) { | 1844 | list_for_each_safe(l, n, &tsp->smk_rules) { |
@@ -1916,7 +1846,6 @@ static void smack_cred_free(struct cred *cred) | |||
1916 | list_del(&rp->list); | 1846 | list_del(&rp->list); |
1917 | kfree(rp); | 1847 | kfree(rp); |
1918 | } | 1848 | } |
1919 | kfree(tsp); | ||
1920 | } | 1849 | } |
1921 | 1850 | ||
1922 | /** | 1851 | /** |
@@ -1930,15 +1859,11 @@ static void smack_cred_free(struct cred *cred) | |||
1930 | static int smack_cred_prepare(struct cred *new, const struct cred *old, | 1859 | static int smack_cred_prepare(struct cred *new, const struct cred *old, |
1931 | gfp_t gfp) | 1860 | gfp_t gfp) |
1932 | { | 1861 | { |
1933 | struct task_smack *old_tsp = old->security; | 1862 | struct task_smack *old_tsp = smack_cred(old); |
1934 | struct task_smack *new_tsp; | 1863 | struct task_smack *new_tsp = smack_cred(new); |
1935 | int rc; | 1864 | int rc; |
1936 | 1865 | ||
1937 | new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp); | 1866 | init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task); |
1938 | if (new_tsp == NULL) | ||
1939 | return -ENOMEM; | ||
1940 | |||
1941 | new->security = new_tsp; | ||
1942 | 1867 | ||
1943 | rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); | 1868 | rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); |
1944 | if (rc != 0) | 1869 | if (rc != 0) |
@@ -1946,10 +1871,7 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, | |||
1946 | 1871 | ||
1947 | rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel, | 1872 | rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel, |
1948 | gfp); | 1873 | gfp); |
1949 | if (rc != 0) | 1874 | return rc; |
1950 | return rc; | ||
1951 | |||
1952 | return 0; | ||
1953 | } | 1875 | } |
1954 | 1876 | ||
1955 | /** | 1877 | /** |
@@ -1961,15 +1883,14 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, | |||
1961 | */ | 1883 | */ |
1962 | static void smack_cred_transfer(struct cred *new, const struct cred *old) | 1884 | static void smack_cred_transfer(struct cred *new, const struct cred *old) |
1963 | { | 1885 | { |
1964 | struct task_smack *old_tsp = old->security; | 1886 | struct task_smack *old_tsp = smack_cred(old); |
1965 | struct task_smack *new_tsp = new->security; | 1887 | struct task_smack *new_tsp = smack_cred(new); |
1966 | 1888 | ||
1967 | new_tsp->smk_task = old_tsp->smk_task; | 1889 | new_tsp->smk_task = old_tsp->smk_task; |
1968 | new_tsp->smk_forked = old_tsp->smk_task; | 1890 | new_tsp->smk_forked = old_tsp->smk_task; |
1969 | mutex_init(&new_tsp->smk_rules_lock); | 1891 | mutex_init(&new_tsp->smk_rules_lock); |
1970 | INIT_LIST_HEAD(&new_tsp->smk_rules); | 1892 | INIT_LIST_HEAD(&new_tsp->smk_rules); |
1971 | 1893 | ||
1972 | |||
1973 | /* cbs copy rule list */ | 1894 | /* cbs copy rule list */ |
1974 | } | 1895 | } |
1975 | 1896 | ||
@@ -1980,12 +1901,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) | |||
1980 | * | 1901 | * |
1981 | * Sets the secid to contain a u32 version of the smack label. | 1902 | * Sets the secid to contain a u32 version of the smack label. |
1982 | */ | 1903 | */ |
1983 | static void smack_cred_getsecid(const struct cred *c, u32 *secid) | 1904 | static void smack_cred_getsecid(const struct cred *cred, u32 *secid) |
1984 | { | 1905 | { |
1985 | struct smack_known *skp; | 1906 | struct smack_known *skp; |
1986 | 1907 | ||
1987 | rcu_read_lock(); | 1908 | rcu_read_lock(); |
1988 | skp = smk_of_task(c->security); | 1909 | skp = smk_of_task(smack_cred(cred)); |
1989 | *secid = skp->smk_secid; | 1910 | *secid = skp->smk_secid; |
1990 | rcu_read_unlock(); | 1911 | rcu_read_unlock(); |
1991 | } | 1912 | } |
@@ -1999,7 +1920,7 @@ static void smack_cred_getsecid(const struct cred *c, u32 *secid) | |||
1999 | */ | 1920 | */ |
2000 | static int smack_kernel_act_as(struct cred *new, u32 secid) | 1921 | static int smack_kernel_act_as(struct cred *new, u32 secid) |
2001 | { | 1922 | { |
2002 | struct task_smack *new_tsp = new->security; | 1923 | struct task_smack *new_tsp = smack_cred(new); |
2003 | 1924 | ||
2004 | new_tsp->smk_task = smack_from_secid(secid); | 1925 | new_tsp->smk_task = smack_from_secid(secid); |
2005 | return 0; | 1926 | return 0; |
@@ -2016,8 +1937,8 @@ static int smack_kernel_act_as(struct cred *new, u32 secid) | |||
2016 | static int smack_kernel_create_files_as(struct cred *new, | 1937 | static int smack_kernel_create_files_as(struct cred *new, |
2017 | struct inode *inode) | 1938 | struct inode *inode) |
2018 | { | 1939 | { |
2019 | struct inode_smack *isp = inode->i_security; | 1940 | struct inode_smack *isp = smack_inode(inode); |
2020 | struct task_smack *tsp = new->security; | 1941 | struct task_smack *tsp = smack_cred(new); |
2021 | 1942 | ||
2022 | tsp->smk_forked = isp->smk_inode; | 1943 | tsp->smk_forked = isp->smk_inode; |
2023 | tsp->smk_task = tsp->smk_forked; | 1944 | tsp->smk_task = tsp->smk_forked; |
@@ -2201,7 +2122,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, | |||
2201 | * specific behavior. This is not clean. For one thing | 2122 | * specific behavior. This is not clean. For one thing |
2202 | * we can't take privilege into account. | 2123 | * we can't take privilege into account. |
2203 | */ | 2124 | */ |
2204 | skp = smk_of_task(cred->security); | 2125 | skp = smk_of_task(smack_cred(cred)); |
2205 | rc = smk_access(skp, tkp, MAY_DELIVER, &ad); | 2126 | rc = smk_access(skp, tkp, MAY_DELIVER, &ad); |
2206 | rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc); | 2127 | rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc); |
2207 | return rc; | 2128 | return rc; |
@@ -2216,7 +2137,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, | |||
2216 | */ | 2137 | */ |
2217 | static void smack_task_to_inode(struct task_struct *p, struct inode *inode) | 2138 | static void smack_task_to_inode(struct task_struct *p, struct inode *inode) |
2218 | { | 2139 | { |
2219 | struct inode_smack *isp = inode->i_security; | 2140 | struct inode_smack *isp = smack_inode(inode); |
2220 | struct smack_known *skp = smk_of_task_struct(p); | 2141 | struct smack_known *skp = smk_of_task_struct(p); |
2221 | 2142 | ||
2222 | isp->smk_inode = skp; | 2143 | isp->smk_inode = skp; |
@@ -2679,7 +2600,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
2679 | const void *value, size_t size, int flags) | 2600 | const void *value, size_t size, int flags) |
2680 | { | 2601 | { |
2681 | struct smack_known *skp; | 2602 | struct smack_known *skp; |
2682 | struct inode_smack *nsp = inode->i_security; | 2603 | struct inode_smack *nsp = smack_inode(inode); |
2683 | struct socket_smack *ssp; | 2604 | struct socket_smack *ssp; |
2684 | struct socket *sock; | 2605 | struct socket *sock; |
2685 | int rc = 0; | 2606 | int rc = 0; |
@@ -2888,24 +2809,13 @@ static int smack_flags_to_may(int flags) | |||
2888 | */ | 2809 | */ |
2889 | static int smack_msg_msg_alloc_security(struct msg_msg *msg) | 2810 | static int smack_msg_msg_alloc_security(struct msg_msg *msg) |
2890 | { | 2811 | { |
2891 | struct smack_known *skp = smk_of_current(); | 2812 | struct smack_known **blob = smack_msg_msg(msg); |
2892 | 2813 | ||
2893 | msg->security = skp; | 2814 | *blob = smk_of_current(); |
2894 | return 0; | 2815 | return 0; |
2895 | } | 2816 | } |
2896 | 2817 | ||
2897 | /** | 2818 | /** |
2898 | * smack_msg_msg_free_security - Clear the security blob for msg_msg | ||
2899 | * @msg: the object | ||
2900 | * | ||
2901 | * Clears the blob pointer | ||
2902 | */ | ||
2903 | static void smack_msg_msg_free_security(struct msg_msg *msg) | ||
2904 | { | ||
2905 | msg->security = NULL; | ||
2906 | } | ||
2907 | |||
2908 | /** | ||
2909 | * smack_of_ipc - the smack pointer for the ipc | 2819 | * smack_of_ipc - the smack pointer for the ipc |
2910 | * @isp: the object | 2820 | * @isp: the object |
2911 | * | 2821 | * |
@@ -2913,7 +2823,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg) | |||
2913 | */ | 2823 | */ |
2914 | static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp) | 2824 | static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp) |
2915 | { | 2825 | { |
2916 | return (struct smack_known *)isp->security; | 2826 | struct smack_known **blob = smack_ipc(isp); |
2827 | |||
2828 | return *blob; | ||
2917 | } | 2829 | } |
2918 | 2830 | ||
2919 | /** | 2831 | /** |
@@ -2924,24 +2836,13 @@ static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp) | |||
2924 | */ | 2836 | */ |
2925 | static int smack_ipc_alloc_security(struct kern_ipc_perm *isp) | 2837 | static int smack_ipc_alloc_security(struct kern_ipc_perm *isp) |
2926 | { | 2838 | { |
2927 | struct smack_known *skp = smk_of_current(); | 2839 | struct smack_known **blob = smack_ipc(isp); |
2928 | 2840 | ||
2929 | isp->security = skp; | 2841 | *blob = smk_of_current(); |
2930 | return 0; | 2842 | return 0; |
2931 | } | 2843 | } |
2932 | 2844 | ||
2933 | /** | 2845 | /** |
2934 | * smack_ipc_free_security - Clear the security blob for ipc | ||
2935 | * @isp: the object | ||
2936 | * | ||
2937 | * Clears the blob pointer | ||
2938 | */ | ||
2939 | static void smack_ipc_free_security(struct kern_ipc_perm *isp) | ||
2940 | { | ||
2941 | isp->security = NULL; | ||
2942 | } | ||
2943 | |||
2944 | /** | ||
2945 | * smk_curacc_shm : check if current has access on shm | 2846 | * smk_curacc_shm : check if current has access on shm |
2946 | * @isp : the object | 2847 | * @isp : the object |
2947 | * @access : access requested | 2848 | * @access : access requested |
@@ -3238,7 +3139,8 @@ static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp, struct msg_msg *msg | |||
3238 | */ | 3139 | */ |
3239 | static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) | 3140 | static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) |
3240 | { | 3141 | { |
3241 | struct smack_known *iskp = ipp->security; | 3142 | struct smack_known **blob = smack_ipc(ipp); |
3143 | struct smack_known *iskp = *blob; | ||
3242 | int may = smack_flags_to_may(flag); | 3144 | int may = smack_flags_to_may(flag); |
3243 | struct smk_audit_info ad; | 3145 | struct smk_audit_info ad; |
3244 | int rc; | 3146 | int rc; |
@@ -3259,7 +3161,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) | |||
3259 | */ | 3161 | */ |
3260 | static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) | 3162 | static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) |
3261 | { | 3163 | { |
3262 | struct smack_known *iskp = ipp->security; | 3164 | struct smack_known **blob = smack_ipc(ipp); |
3165 | struct smack_known *iskp = *blob; | ||
3263 | 3166 | ||
3264 | *secid = iskp->smk_secid; | 3167 | *secid = iskp->smk_secid; |
3265 | } | 3168 | } |
@@ -3287,7 +3190,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
3287 | if (inode == NULL) | 3190 | if (inode == NULL) |
3288 | return; | 3191 | return; |
3289 | 3192 | ||
3290 | isp = inode->i_security; | 3193 | isp = smack_inode(inode); |
3291 | 3194 | ||
3292 | mutex_lock(&isp->smk_lock); | 3195 | mutex_lock(&isp->smk_lock); |
3293 | /* | 3196 | /* |
@@ -3390,13 +3293,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
3390 | */ | 3293 | */ |
3391 | final = &smack_known_star; | 3294 | final = &smack_known_star; |
3392 | /* | 3295 | /* |
3393 | * Fall through. | ||
3394 | * | ||
3395 | * If a smack value has been set we want to use it, | 3296 | * If a smack value has been set we want to use it, |
3396 | * but since tmpfs isn't giving us the opportunity | 3297 | * but since tmpfs isn't giving us the opportunity |
3397 | * to set mount options simulate setting the | 3298 | * to set mount options simulate setting the |
3398 | * superblock default. | 3299 | * superblock default. |
3399 | */ | 3300 | */ |
3301 | /* Fall through */ | ||
3400 | default: | 3302 | default: |
3401 | /* | 3303 | /* |
3402 | * This isn't an understood special case. | 3304 | * This isn't an understood special case. |
@@ -3528,7 +3430,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) | |||
3528 | */ | 3430 | */ |
3529 | static int smack_setprocattr(const char *name, void *value, size_t size) | 3431 | static int smack_setprocattr(const char *name, void *value, size_t size) |
3530 | { | 3432 | { |
3531 | struct task_smack *tsp = current_security(); | 3433 | struct task_smack *tsp = smack_cred(current_cred()); |
3532 | struct cred *new; | 3434 | struct cred *new; |
3533 | struct smack_known *skp; | 3435 | struct smack_known *skp; |
3534 | struct smack_known_list_elem *sklep; | 3436 | struct smack_known_list_elem *sklep; |
@@ -3569,7 +3471,7 @@ static int smack_setprocattr(const char *name, void *value, size_t size) | |||
3569 | if (new == NULL) | 3471 | if (new == NULL) |
3570 | return -ENOMEM; | 3472 | return -ENOMEM; |
3571 | 3473 | ||
3572 | tsp = new->security; | 3474 | tsp = smack_cred(new); |
3573 | tsp->smk_task = skp; | 3475 | tsp->smk_task = skp; |
3574 | /* | 3476 | /* |
3575 | * process can change its label only once | 3477 | * process can change its label only once |
@@ -4214,7 +4116,7 @@ static void smack_inet_csk_clone(struct sock *sk, | |||
4214 | static int smack_key_alloc(struct key *key, const struct cred *cred, | 4116 | static int smack_key_alloc(struct key *key, const struct cred *cred, |
4215 | unsigned long flags) | 4117 | unsigned long flags) |
4216 | { | 4118 | { |
4217 | struct smack_known *skp = smk_of_task(cred->security); | 4119 | struct smack_known *skp = smk_of_task(smack_cred(cred)); |
4218 | 4120 | ||
4219 | key->security = skp; | 4121 | key->security = skp; |
4220 | return 0; | 4122 | return 0; |
@@ -4245,7 +4147,7 @@ static int smack_key_permission(key_ref_t key_ref, | |||
4245 | { | 4147 | { |
4246 | struct key *keyp; | 4148 | struct key *keyp; |
4247 | struct smk_audit_info ad; | 4149 | struct smk_audit_info ad; |
4248 | struct smack_known *tkp = smk_of_task(cred->security); | 4150 | struct smack_known *tkp = smk_of_task(smack_cred(cred)); |
4249 | int request = 0; | 4151 | int request = 0; |
4250 | int rc; | 4152 | int rc; |
4251 | 4153 | ||
@@ -4520,12 +4422,12 @@ static int smack_inode_copy_up(struct dentry *dentry, struct cred **new) | |||
4520 | return -ENOMEM; | 4422 | return -ENOMEM; |
4521 | } | 4423 | } |
4522 | 4424 | ||
4523 | tsp = new_creds->security; | 4425 | tsp = smack_cred(new_creds); |
4524 | 4426 | ||
4525 | /* | 4427 | /* |
4526 | * Get label from overlay inode and set it in create_sid | 4428 | * Get label from overlay inode and set it in create_sid |
4527 | */ | 4429 | */ |
4528 | isp = d_inode(dentry->d_parent)->i_security; | 4430 | isp = smack_inode(d_inode(dentry->d_parent)); |
4529 | skp = isp->smk_inode; | 4431 | skp = isp->smk_inode; |
4530 | tsp->smk_task = skp; | 4432 | tsp->smk_task = skp; |
4531 | *new = new_creds; | 4433 | *new = new_creds; |
@@ -4548,8 +4450,8 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, | |||
4548 | const struct cred *old, | 4450 | const struct cred *old, |
4549 | struct cred *new) | 4451 | struct cred *new) |
4550 | { | 4452 | { |
4551 | struct task_smack *otsp = old->security; | 4453 | struct task_smack *otsp = smack_cred(old); |
4552 | struct task_smack *ntsp = new->security; | 4454 | struct task_smack *ntsp = smack_cred(new); |
4553 | struct inode_smack *isp; | 4455 | struct inode_smack *isp; |
4554 | int may; | 4456 | int may; |
4555 | 4457 | ||
@@ -4562,7 +4464,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, | |||
4562 | /* | 4464 | /* |
4563 | * the attribute of the containing directory | 4465 | * the attribute of the containing directory |
4564 | */ | 4466 | */ |
4565 | isp = d_inode(dentry->d_parent)->i_security; | 4467 | isp = smack_inode(d_inode(dentry->d_parent)); |
4566 | 4468 | ||
4567 | if (isp->smk_flags & SMK_INODE_TRANSMUTE) { | 4469 | if (isp->smk_flags & SMK_INODE_TRANSMUTE) { |
4568 | rcu_read_lock(); | 4470 | rcu_read_lock(); |
@@ -4582,6 +4484,14 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, | |||
4582 | return 0; | 4484 | return 0; |
4583 | } | 4485 | } |
4584 | 4486 | ||
4487 | struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { | ||
4488 | .lbs_cred = sizeof(struct task_smack), | ||
4489 | .lbs_file = sizeof(struct smack_known *), | ||
4490 | .lbs_inode = sizeof(struct inode_smack), | ||
4491 | .lbs_ipc = sizeof(struct smack_known *), | ||
4492 | .lbs_msg_msg = sizeof(struct smack_known *), | ||
4493 | }; | ||
4494 | |||
4585 | static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | 4495 | static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { |
4586 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), | 4496 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), |
4587 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), | 4497 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), |
@@ -4597,7 +4507,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | |||
4597 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), | 4507 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), |
4598 | 4508 | ||
4599 | LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), | 4509 | LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), |
4600 | LSM_HOOK_INIT(inode_free_security, smack_inode_free_security), | ||
4601 | LSM_HOOK_INIT(inode_init_security, smack_inode_init_security), | 4510 | LSM_HOOK_INIT(inode_init_security, smack_inode_init_security), |
4602 | LSM_HOOK_INIT(inode_link, smack_inode_link), | 4511 | LSM_HOOK_INIT(inode_link, smack_inode_link), |
4603 | LSM_HOOK_INIT(inode_unlink, smack_inode_unlink), | 4512 | LSM_HOOK_INIT(inode_unlink, smack_inode_unlink), |
@@ -4616,7 +4525,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | |||
4616 | LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), | 4525 | LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), |
4617 | 4526 | ||
4618 | LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), | 4527 | LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), |
4619 | LSM_HOOK_INIT(file_free_security, smack_file_free_security), | ||
4620 | LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), | 4528 | LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), |
4621 | LSM_HOOK_INIT(file_lock, smack_file_lock), | 4529 | LSM_HOOK_INIT(file_lock, smack_file_lock), |
4622 | LSM_HOOK_INIT(file_fcntl, smack_file_fcntl), | 4530 | LSM_HOOK_INIT(file_fcntl, smack_file_fcntl), |
@@ -4652,23 +4560,19 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | |||
4652 | LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid), | 4560 | LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid), |
4653 | 4561 | ||
4654 | LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security), | 4562 | LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security), |
4655 | LSM_HOOK_INIT(msg_msg_free_security, smack_msg_msg_free_security), | ||
4656 | 4563 | ||
4657 | LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security), | 4564 | LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security), |
4658 | LSM_HOOK_INIT(msg_queue_free_security, smack_ipc_free_security), | ||
4659 | LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate), | 4565 | LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate), |
4660 | LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl), | 4566 | LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl), |
4661 | LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd), | 4567 | LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd), |
4662 | LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv), | 4568 | LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv), |
4663 | 4569 | ||
4664 | LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security), | 4570 | LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security), |
4665 | LSM_HOOK_INIT(shm_free_security, smack_ipc_free_security), | ||
4666 | LSM_HOOK_INIT(shm_associate, smack_shm_associate), | 4571 | LSM_HOOK_INIT(shm_associate, smack_shm_associate), |
4667 | LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl), | 4572 | LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl), |
4668 | LSM_HOOK_INIT(shm_shmat, smack_shm_shmat), | 4573 | LSM_HOOK_INIT(shm_shmat, smack_shm_shmat), |
4669 | 4574 | ||
4670 | LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security), | 4575 | LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security), |
4671 | LSM_HOOK_INIT(sem_free_security, smack_ipc_free_security), | ||
4672 | LSM_HOOK_INIT(sem_associate, smack_sem_associate), | 4576 | LSM_HOOK_INIT(sem_associate, smack_sem_associate), |
4673 | LSM_HOOK_INIT(sem_semctl, smack_sem_semctl), | 4577 | LSM_HOOK_INIT(sem_semctl, smack_sem_semctl), |
4674 | LSM_HOOK_INIT(sem_semop, smack_sem_semop), | 4578 | LSM_HOOK_INIT(sem_semop, smack_sem_semop), |
@@ -4759,23 +4663,23 @@ static __init void init_smack_known_list(void) | |||
4759 | */ | 4663 | */ |
4760 | static __init int smack_init(void) | 4664 | static __init int smack_init(void) |
4761 | { | 4665 | { |
4762 | struct cred *cred; | 4666 | struct cred *cred = (struct cred *) current->cred; |
4763 | struct task_smack *tsp; | 4667 | struct task_smack *tsp; |
4764 | 4668 | ||
4765 | if (!security_module_enable("smack")) | ||
4766 | return 0; | ||
4767 | |||
4768 | smack_inode_cache = KMEM_CACHE(inode_smack, 0); | 4669 | smack_inode_cache = KMEM_CACHE(inode_smack, 0); |
4769 | if (!smack_inode_cache) | 4670 | if (!smack_inode_cache) |
4770 | return -ENOMEM; | 4671 | return -ENOMEM; |
4771 | 4672 | ||
4772 | tsp = new_task_smack(&smack_known_floor, &smack_known_floor, | 4673 | /* |
4773 | GFP_KERNEL); | 4674 | * Set the security state for the initial task. |
4774 | if (tsp == NULL) { | 4675 | */ |
4775 | kmem_cache_destroy(smack_inode_cache); | 4676 | tsp = smack_cred(cred); |
4776 | return -ENOMEM; | 4677 | init_task_smack(tsp, &smack_known_floor, &smack_known_floor); |
4777 | } | ||
4778 | 4678 | ||
4679 | /* | ||
4680 | * Register with LSM | ||
4681 | */ | ||
4682 | security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); | ||
4779 | smack_enabled = 1; | 4683 | smack_enabled = 1; |
4780 | 4684 | ||
4781 | pr_info("Smack: Initializing.\n"); | 4685 | pr_info("Smack: Initializing.\n"); |
@@ -4789,20 +4693,9 @@ static __init int smack_init(void) | |||
4789 | pr_info("Smack: IPv6 Netfilter enabled.\n"); | 4693 | pr_info("Smack: IPv6 Netfilter enabled.\n"); |
4790 | #endif | 4694 | #endif |
4791 | 4695 | ||
4792 | /* | ||
4793 | * Set the security state for the initial task. | ||
4794 | */ | ||
4795 | cred = (struct cred *) current->cred; | ||
4796 | cred->security = tsp; | ||
4797 | |||
4798 | /* initialize the smack_known_list */ | 4696 | /* initialize the smack_known_list */ |
4799 | init_smack_known_list(); | 4697 | init_smack_known_list(); |
4800 | 4698 | ||
4801 | /* | ||
4802 | * Register with LSM | ||
4803 | */ | ||
4804 | security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); | ||
4805 | |||
4806 | return 0; | 4699 | return 0; |
4807 | } | 4700 | } |
4808 | 4701 | ||
@@ -4812,5 +4705,7 @@ static __init int smack_init(void) | |||
4812 | */ | 4705 | */ |
4813 | DEFINE_LSM(smack) = { | 4706 | DEFINE_LSM(smack) = { |
4814 | .name = "smack", | 4707 | .name = "smack", |
4708 | .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, | ||
4709 | .blobs = &smack_blob_sizes, | ||
4815 | .init = smack_init, | 4710 | .init = smack_init, |
4816 | }; | 4711 | }; |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 06b517075ec0..faf2ea3968b3 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -2208,14 +2208,14 @@ static const struct file_operations smk_logging_ops = { | |||
2208 | 2208 | ||
2209 | static void *load_self_seq_start(struct seq_file *s, loff_t *pos) | 2209 | static void *load_self_seq_start(struct seq_file *s, loff_t *pos) |
2210 | { | 2210 | { |
2211 | struct task_smack *tsp = current_security(); | 2211 | struct task_smack *tsp = smack_cred(current_cred()); |
2212 | 2212 | ||
2213 | return smk_seq_start(s, pos, &tsp->smk_rules); | 2213 | return smk_seq_start(s, pos, &tsp->smk_rules); |
2214 | } | 2214 | } |
2215 | 2215 | ||
2216 | static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos) | 2216 | static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos) |
2217 | { | 2217 | { |
2218 | struct task_smack *tsp = current_security(); | 2218 | struct task_smack *tsp = smack_cred(current_cred()); |
2219 | 2219 | ||
2220 | return smk_seq_next(s, v, pos, &tsp->smk_rules); | 2220 | return smk_seq_next(s, v, pos, &tsp->smk_rules); |
2221 | } | 2221 | } |
@@ -2262,7 +2262,7 @@ static int smk_open_load_self(struct inode *inode, struct file *file) | |||
2262 | static ssize_t smk_write_load_self(struct file *file, const char __user *buf, | 2262 | static ssize_t smk_write_load_self(struct file *file, const char __user *buf, |
2263 | size_t count, loff_t *ppos) | 2263 | size_t count, loff_t *ppos) |
2264 | { | 2264 | { |
2265 | struct task_smack *tsp = current_security(); | 2265 | struct task_smack *tsp = smack_cred(current_cred()); |
2266 | 2266 | ||
2267 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, | 2267 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, |
2268 | &tsp->smk_rules_lock, SMK_FIXED24_FMT); | 2268 | &tsp->smk_rules_lock, SMK_FIXED24_FMT); |
@@ -2414,14 +2414,14 @@ static const struct file_operations smk_load2_ops = { | |||
2414 | 2414 | ||
2415 | static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) | 2415 | static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) |
2416 | { | 2416 | { |
2417 | struct task_smack *tsp = current_security(); | 2417 | struct task_smack *tsp = smack_cred(current_cred()); |
2418 | 2418 | ||
2419 | return smk_seq_start(s, pos, &tsp->smk_rules); | 2419 | return smk_seq_start(s, pos, &tsp->smk_rules); |
2420 | } | 2420 | } |
2421 | 2421 | ||
2422 | static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) | 2422 | static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) |
2423 | { | 2423 | { |
2424 | struct task_smack *tsp = current_security(); | 2424 | struct task_smack *tsp = smack_cred(current_cred()); |
2425 | 2425 | ||
2426 | return smk_seq_next(s, v, pos, &tsp->smk_rules); | 2426 | return smk_seq_next(s, v, pos, &tsp->smk_rules); |
2427 | } | 2427 | } |
@@ -2467,7 +2467,7 @@ static int smk_open_load_self2(struct inode *inode, struct file *file) | |||
2467 | static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, | 2467 | static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, |
2468 | size_t count, loff_t *ppos) | 2468 | size_t count, loff_t *ppos) |
2469 | { | 2469 | { |
2470 | struct task_smack *tsp = current_security(); | 2470 | struct task_smack *tsp = smack_cred(current_cred()); |
2471 | 2471 | ||
2472 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, | 2472 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, |
2473 | &tsp->smk_rules_lock, SMK_LONG_FMT); | 2473 | &tsp->smk_rules_lock, SMK_LONG_FMT); |
@@ -2681,14 +2681,14 @@ static const struct file_operations smk_syslog_ops = { | |||
2681 | 2681 | ||
2682 | static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos) | 2682 | static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos) |
2683 | { | 2683 | { |
2684 | struct task_smack *tsp = current_security(); | 2684 | struct task_smack *tsp = smack_cred(current_cred()); |
2685 | 2685 | ||
2686 | return smk_seq_start(s, pos, &tsp->smk_relabel); | 2686 | return smk_seq_start(s, pos, &tsp->smk_relabel); |
2687 | } | 2687 | } |
2688 | 2688 | ||
2689 | static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos) | 2689 | static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos) |
2690 | { | 2690 | { |
2691 | struct task_smack *tsp = current_security(); | 2691 | struct task_smack *tsp = smack_cred(current_cred()); |
2692 | 2692 | ||
2693 | return smk_seq_next(s, v, pos, &tsp->smk_relabel); | 2693 | return smk_seq_next(s, v, pos, &tsp->smk_relabel); |
2694 | } | 2694 | } |
@@ -2736,7 +2736,7 @@ static int smk_open_relabel_self(struct inode *inode, struct file *file) | |||
2736 | static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf, | 2736 | static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf, |
2737 | size_t count, loff_t *ppos) | 2737 | size_t count, loff_t *ppos) |
2738 | { | 2738 | { |
2739 | struct task_smack *tsp = current_security(); | 2739 | struct task_smack *tsp = smack_cred(current_cred()); |
2740 | char *data; | 2740 | char *data; |
2741 | int rc; | 2741 | int rc; |
2742 | LIST_HEAD(list_tmp); | 2742 | LIST_HEAD(list_tmp); |
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 479b03a7a17e..3c96e8402e94 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c | |||
@@ -32,6 +32,7 @@ static char *tomoyo_print_bprm(struct linux_binprm *bprm, | |||
32 | int argv_count = bprm->argc; | 32 | int argv_count = bprm->argc; |
33 | int envp_count = bprm->envc; | 33 | int envp_count = bprm->envc; |
34 | bool truncated = false; | 34 | bool truncated = false; |
35 | |||
35 | if (!buffer) | 36 | if (!buffer) |
36 | return NULL; | 37 | return NULL; |
37 | len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ "); | 38 | len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ "); |
@@ -49,6 +50,7 @@ static char *tomoyo_print_bprm(struct linux_binprm *bprm, | |||
49 | while (offset < PAGE_SIZE) { | 50 | while (offset < PAGE_SIZE) { |
50 | const char *kaddr = dump->data; | 51 | const char *kaddr = dump->data; |
51 | const unsigned char c = kaddr[offset++]; | 52 | const unsigned char c = kaddr[offset++]; |
53 | |||
52 | if (cp == last_start) | 54 | if (cp == last_start) |
53 | *cp++ = '"'; | 55 | *cp++ = '"'; |
54 | if (cp >= buffer + tomoyo_buffer_len - 32) { | 56 | if (cp >= buffer + tomoyo_buffer_len - 32) { |
@@ -154,19 +156,18 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
154 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | 156 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); |
155 | int pos; | 157 | int pos; |
156 | u8 i; | 158 | u8 i; |
159 | |||
157 | if (!buffer) | 160 | if (!buffer) |
158 | return NULL; | 161 | return NULL; |
159 | 162 | ||
160 | tomoyo_convert_time(ktime_get_real_seconds(), &stamp); | 163 | tomoyo_convert_time(ktime_get_real_seconds(), &stamp); |
161 | 164 | ||
162 | pos = snprintf(buffer, tomoyo_buffer_len - 1, | 165 | pos = snprintf(buffer, tomoyo_buffer_len - 1, |
163 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " | 166 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s granted=%s (global-pid=%u) task={ pid=%u ppid=%u uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", |
164 | "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " | 167 | stamp.year, stamp.month, stamp.day, stamp.hour, |
165 | "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " | 168 | stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode], |
166 | "fsuid=%u fsgid=%u }", stamp.year, stamp.month, | 169 | tomoyo_yesno(r->granted), gpid, tomoyo_sys_getpid(), |
167 | stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, | 170 | tomoyo_sys_getppid(), |
168 | tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, | ||
169 | tomoyo_sys_getpid(), tomoyo_sys_getppid(), | ||
170 | from_kuid(&init_user_ns, current_uid()), | 171 | from_kuid(&init_user_ns, current_uid()), |
171 | from_kgid(&init_user_ns, current_gid()), | 172 | from_kgid(&init_user_ns, current_gid()), |
172 | from_kuid(&init_user_ns, current_euid()), | 173 | from_kuid(&init_user_ns, current_euid()), |
@@ -185,6 +186,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
185 | struct tomoyo_mini_stat *stat; | 186 | struct tomoyo_mini_stat *stat; |
186 | unsigned int dev; | 187 | unsigned int dev; |
187 | umode_t mode; | 188 | umode_t mode; |
189 | |||
188 | if (!obj->stat_valid[i]) | 190 | if (!obj->stat_valid[i]) |
189 | continue; | 191 | continue; |
190 | stat = &obj->stat[i]; | 192 | stat = &obj->stat[i]; |
@@ -193,8 +195,8 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
193 | if (i & 1) { | 195 | if (i & 1) { |
194 | pos += snprintf(buffer + pos, | 196 | pos += snprintf(buffer + pos, |
195 | tomoyo_buffer_len - 1 - pos, | 197 | tomoyo_buffer_len - 1 - pos, |
196 | " path%u.parent={ uid=%u gid=%u " | 198 | " path%u.parent={ uid=%u gid=%u ino=%lu perm=0%o }", |
197 | "ino=%lu perm=0%o }", (i >> 1) + 1, | 199 | (i >> 1) + 1, |
198 | from_kuid(&init_user_ns, stat->uid), | 200 | from_kuid(&init_user_ns, stat->uid), |
199 | from_kgid(&init_user_ns, stat->gid), | 201 | from_kgid(&init_user_ns, stat->gid), |
200 | (unsigned long)stat->ino, | 202 | (unsigned long)stat->ino, |
@@ -202,8 +204,8 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
202 | continue; | 204 | continue; |
203 | } | 205 | } |
204 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | 206 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, |
205 | " path%u={ uid=%u gid=%u ino=%lu major=%u" | 207 | " path%u={ uid=%u gid=%u ino=%lu major=%u minor=%u perm=0%o type=%s", |
206 | " minor=%u perm=0%o type=%s", (i >> 1) + 1, | 208 | (i >> 1) + 1, |
207 | from_kuid(&init_user_ns, stat->uid), | 209 | from_kuid(&init_user_ns, stat->uid), |
208 | from_kgid(&init_user_ns, stat->gid), | 210 | from_kgid(&init_user_ns, stat->gid), |
209 | (unsigned long)stat->ino, | 211 | (unsigned long)stat->ino, |
@@ -249,6 +251,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | |||
249 | const char *symlink = NULL; | 251 | const char *symlink = NULL; |
250 | int pos; | 252 | int pos; |
251 | const char *domainname = r->domain->domainname->name; | 253 | const char *domainname = r->domain->domainname->name; |
254 | |||
252 | header = tomoyo_print_header(r); | 255 | header = tomoyo_print_header(r); |
253 | if (!header) | 256 | if (!header) |
254 | return NULL; | 257 | return NULL; |
@@ -256,6 +259,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | |||
256 | len += strlen(domainname) + strlen(header) + 10; | 259 | len += strlen(domainname) + strlen(header) + 10; |
257 | if (r->ee) { | 260 | if (r->ee) { |
258 | struct file *file = r->ee->bprm->file; | 261 | struct file *file = r->ee->bprm->file; |
262 | |||
259 | realpath = tomoyo_realpath_from_path(&file->f_path); | 263 | realpath = tomoyo_realpath_from_path(&file->f_path); |
260 | bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump); | 264 | bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump); |
261 | if (!realpath || !bprm_info) | 265 | if (!realpath || !bprm_info) |
@@ -275,6 +279,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | |||
275 | pos = snprintf(buf, len, "%s", header); | 279 | pos = snprintf(buf, len, "%s", header); |
276 | if (realpath) { | 280 | if (realpath) { |
277 | struct linux_binprm *bprm = r->ee->bprm; | 281 | struct linux_binprm *bprm = r->ee->bprm; |
282 | |||
278 | pos += snprintf(buf + pos, len - pos, | 283 | pos += snprintf(buf + pos, len - pos, |
279 | " exec={ realpath=\"%s\" argc=%d envc=%d %s }", | 284 | " exec={ realpath=\"%s\" argc=%d envc=%d %s }", |
280 | realpath, bprm->argc, bprm->envc, bprm_info); | 285 | realpath, bprm->argc, bprm->envc, bprm_info); |
@@ -328,6 +333,7 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, | |||
328 | const u8 category = tomoyo_index2category[index] + | 333 | const u8 category = tomoyo_index2category[index] + |
329 | TOMOYO_MAX_MAC_INDEX; | 334 | TOMOYO_MAX_MAC_INDEX; |
330 | struct tomoyo_profile *p; | 335 | struct tomoyo_profile *p; |
336 | |||
331 | if (!tomoyo_policy_loaded) | 337 | if (!tomoyo_policy_loaded) |
332 | return false; | 338 | return false; |
333 | p = tomoyo_profile(ns, profile); | 339 | p = tomoyo_profile(ns, profile); |
@@ -362,6 +368,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | |||
362 | char *buf; | 368 | char *buf; |
363 | struct tomoyo_log *entry; | 369 | struct tomoyo_log *entry; |
364 | bool quota_exceeded = false; | 370 | bool quota_exceeded = false; |
371 | |||
365 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, | 372 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, |
366 | r->matched_acl, r->granted)) | 373 | r->matched_acl, r->granted)) |
367 | goto out; | 374 | goto out; |
@@ -413,6 +420,7 @@ void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | |||
413 | { | 420 | { |
414 | va_list args; | 421 | va_list args; |
415 | int len; | 422 | int len; |
423 | |||
416 | va_start(args, fmt); | 424 | va_start(args, fmt); |
417 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | 425 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; |
418 | va_end(args); | 426 | va_end(args); |
@@ -431,6 +439,7 @@ void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | |||
431 | void tomoyo_read_log(struct tomoyo_io_buffer *head) | 439 | void tomoyo_read_log(struct tomoyo_io_buffer *head) |
432 | { | 440 | { |
433 | struct tomoyo_log *ptr = NULL; | 441 | struct tomoyo_log *ptr = NULL; |
442 | |||
434 | if (head->r.w_pos) | 443 | if (head->r.w_pos) |
435 | return; | 444 | return; |
436 | kfree(head->read_buf); | 445 | kfree(head->read_buf); |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index c598aa00d5e3..57988d95d33d 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -197,6 +197,7 @@ static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) | |||
197 | { | 197 | { |
198 | va_list args; | 198 | va_list args; |
199 | const int pos = strlen(buffer); | 199 | const int pos = strlen(buffer); |
200 | |||
200 | va_start(args, fmt); | 201 | va_start(args, fmt); |
201 | vsnprintf(buffer + pos, len - pos - 1, fmt, args); | 202 | vsnprintf(buffer + pos, len - pos - 1, fmt, args); |
202 | va_end(args); | 203 | va_end(args); |
@@ -214,6 +215,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head) | |||
214 | while (head->r.w_pos) { | 215 | while (head->r.w_pos) { |
215 | const char *w = head->r.w[0]; | 216 | const char *w = head->r.w[0]; |
216 | size_t len = strlen(w); | 217 | size_t len = strlen(w); |
218 | |||
217 | if (len) { | 219 | if (len) { |
218 | if (len > head->read_user_buf_avail) | 220 | if (len > head->read_user_buf_avail) |
219 | len = head->read_user_buf_avail; | 221 | len = head->read_user_buf_avail; |
@@ -279,6 +281,7 @@ static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, | |||
279 | size_t len; | 281 | size_t len; |
280 | size_t pos = head->r.avail; | 282 | size_t pos = head->r.avail; |
281 | int size = head->readbuf_size - pos; | 283 | int size = head->readbuf_size - pos; |
284 | |||
282 | if (size <= 0) | 285 | if (size <= 0) |
283 | return; | 286 | return; |
284 | va_start(args, fmt); | 287 | va_start(args, fmt); |
@@ -344,13 +347,14 @@ static bool tomoyo_namespace_enabled; | |||
344 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) | 347 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) |
345 | { | 348 | { |
346 | unsigned int idx; | 349 | unsigned int idx; |
350 | |||
347 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) | 351 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) |
348 | INIT_LIST_HEAD(&ns->acl_group[idx]); | 352 | INIT_LIST_HEAD(&ns->acl_group[idx]); |
349 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | 353 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) |
350 | INIT_LIST_HEAD(&ns->group_list[idx]); | 354 | INIT_LIST_HEAD(&ns->group_list[idx]); |
351 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | 355 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) |
352 | INIT_LIST_HEAD(&ns->policy_list[idx]); | 356 | INIT_LIST_HEAD(&ns->policy_list[idx]); |
353 | ns->profile_version = 20110903; | 357 | ns->profile_version = 20150505; |
354 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); | 358 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); |
355 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); | 359 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); |
356 | } | 360 | } |
@@ -433,6 +437,7 @@ static void tomoyo_print_number_union_nospace | |||
433 | u8 min_type = ptr->value_type[0]; | 437 | u8 min_type = ptr->value_type[0]; |
434 | const u8 max_type = ptr->value_type[1]; | 438 | const u8 max_type = ptr->value_type[1]; |
435 | char buffer[128]; | 439 | char buffer[128]; |
440 | |||
436 | buffer[0] = '\0'; | 441 | buffer[0] = '\0'; |
437 | for (i = 0; i < 2; i++) { | 442 | for (i = 0; i < 2; i++) { |
438 | switch (min_type) { | 443 | switch (min_type) { |
@@ -487,6 +492,7 @@ static struct tomoyo_profile *tomoyo_assign_profile | |||
487 | { | 492 | { |
488 | struct tomoyo_profile *ptr; | 493 | struct tomoyo_profile *ptr; |
489 | struct tomoyo_profile *entry; | 494 | struct tomoyo_profile *entry; |
495 | |||
490 | if (profile >= TOMOYO_MAX_PROFILES) | 496 | if (profile >= TOMOYO_MAX_PROFILES) |
491 | return NULL; | 497 | return NULL; |
492 | ptr = ns->profile_ptr[profile]; | 498 | ptr = ns->profile_ptr[profile]; |
@@ -530,6 +536,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, | |||
530 | { | 536 | { |
531 | static struct tomoyo_profile tomoyo_null_profile; | 537 | static struct tomoyo_profile tomoyo_null_profile; |
532 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; | 538 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; |
539 | |||
533 | if (!ptr) | 540 | if (!ptr) |
534 | ptr = &tomoyo_null_profile; | 541 | ptr = &tomoyo_null_profile; |
535 | return ptr; | 542 | return ptr; |
@@ -546,6 +553,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, | |||
546 | static s8 tomoyo_find_yesno(const char *string, const char *find) | 553 | static s8 tomoyo_find_yesno(const char *string, const char *find) |
547 | { | 554 | { |
548 | const char *cp = strstr(string, find); | 555 | const char *cp = strstr(string, find); |
556 | |||
549 | if (cp) { | 557 | if (cp) { |
550 | cp += strlen(find); | 558 | cp += strlen(find); |
551 | if (!strncmp(cp, "=yes", 4)) | 559 | if (!strncmp(cp, "=yes", 4)) |
@@ -569,6 +577,7 @@ static void tomoyo_set_uint(unsigned int *i, const char *string, | |||
569 | const char *find) | 577 | const char *find) |
570 | { | 578 | { |
571 | const char *cp = strstr(string, find); | 579 | const char *cp = strstr(string, find); |
580 | |||
572 | if (cp) | 581 | if (cp) |
573 | sscanf(cp + strlen(find), "=%u", i); | 582 | sscanf(cp + strlen(find), "=%u", i); |
574 | } | 583 | } |
@@ -587,6 +596,7 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
587 | { | 596 | { |
588 | u8 i; | 597 | u8 i; |
589 | u8 config; | 598 | u8 config; |
599 | |||
590 | if (!strcmp(name, "CONFIG")) { | 600 | if (!strcmp(name, "CONFIG")) { |
591 | i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; | 601 | i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; |
592 | config = profile->default_config; | 602 | config = profile->default_config; |
@@ -595,10 +605,12 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
595 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX | 605 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX |
596 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { | 606 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { |
597 | int len = 0; | 607 | int len = 0; |
608 | |||
598 | if (i < TOMOYO_MAX_MAC_INDEX) { | 609 | if (i < TOMOYO_MAX_MAC_INDEX) { |
599 | const u8 c = tomoyo_index2category[i]; | 610 | const u8 c = tomoyo_index2category[i]; |
600 | const char *category = | 611 | const char *category = |
601 | tomoyo_category_keywords[c]; | 612 | tomoyo_category_keywords[c]; |
613 | |||
602 | len = strlen(category); | 614 | len = strlen(category); |
603 | if (strncmp(name, category, len) || | 615 | if (strncmp(name, category, len) || |
604 | name[len++] != ':' || name[len++] != ':') | 616 | name[len++] != ':' || name[len++] != ':') |
@@ -618,6 +630,7 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
618 | config = TOMOYO_CONFIG_USE_DEFAULT; | 630 | config = TOMOYO_CONFIG_USE_DEFAULT; |
619 | } else { | 631 | } else { |
620 | u8 mode; | 632 | u8 mode; |
633 | |||
621 | for (mode = 0; mode < 4; mode++) | 634 | for (mode = 0; mode < 4; mode++) |
622 | if (strstr(value, tomoyo_mode[mode])) | 635 | if (strstr(value, tomoyo_mode[mode])) |
623 | /* | 636 | /* |
@@ -664,6 +677,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
664 | unsigned int i; | 677 | unsigned int i; |
665 | char *cp; | 678 | char *cp; |
666 | struct tomoyo_profile *profile; | 679 | struct tomoyo_profile *profile; |
680 | |||
667 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) | 681 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) |
668 | == 1) | 682 | == 1) |
669 | return 0; | 683 | return 0; |
@@ -683,6 +697,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
683 | const struct tomoyo_path_info *new_comment | 697 | const struct tomoyo_path_info *new_comment |
684 | = tomoyo_get_name(cp); | 698 | = tomoyo_get_name(cp); |
685 | const struct tomoyo_path_info *old_comment; | 699 | const struct tomoyo_path_info *old_comment; |
700 | |||
686 | if (!new_comment) | 701 | if (!new_comment) |
687 | return -ENOMEM; | 702 | return -ENOMEM; |
688 | spin_lock(&lock); | 703 | spin_lock(&lock); |
@@ -732,6 +747,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
732 | struct tomoyo_policy_namespace *ns = | 747 | struct tomoyo_policy_namespace *ns = |
733 | container_of(head->r.ns, typeof(*ns), namespace_list); | 748 | container_of(head->r.ns, typeof(*ns), namespace_list); |
734 | const struct tomoyo_profile *profile; | 749 | const struct tomoyo_profile *profile; |
750 | |||
735 | if (head->r.eof) | 751 | if (head->r.eof) |
736 | return; | 752 | return; |
737 | next: | 753 | next: |
@@ -760,6 +776,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
760 | u8 i; | 776 | u8 i; |
761 | const struct tomoyo_path_info *comment = | 777 | const struct tomoyo_path_info *comment = |
762 | profile->comment; | 778 | profile->comment; |
779 | |||
763 | tomoyo_print_namespace(head); | 780 | tomoyo_print_namespace(head); |
764 | tomoyo_io_printf(head, "%u-COMMENT=", index); | 781 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
765 | tomoyo_set_string(head, comment ? comment->name : ""); | 782 | tomoyo_set_string(head, comment ? comment->name : ""); |
@@ -788,6 +805,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
788 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) { | 805 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) { |
789 | const u8 i = head->r.bit; | 806 | const u8 i = head->r.bit; |
790 | const u8 config = profile->config[i]; | 807 | const u8 config = profile->config[i]; |
808 | |||
791 | if (config == TOMOYO_CONFIG_USE_DEFAULT) | 809 | if (config == TOMOYO_CONFIG_USE_DEFAULT) |
792 | continue; | 810 | continue; |
793 | tomoyo_print_namespace(head); | 811 | tomoyo_print_namespace(head); |
@@ -847,10 +865,10 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
847 | struct tomoyo_acl_param param = { | 865 | struct tomoyo_acl_param param = { |
848 | /* .ns = &tomoyo_kernel_namespace, */ | 866 | /* .ns = &tomoyo_kernel_namespace, */ |
849 | .is_delete = is_delete, | 867 | .is_delete = is_delete, |
850 | .list = &tomoyo_kernel_namespace. | 868 | .list = &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], |
851 | policy_list[TOMOYO_ID_MANAGER], | ||
852 | }; | 869 | }; |
853 | int error = is_delete ? -ENOENT : -ENOMEM; | 870 | int error = is_delete ? -ENOENT : -ENOMEM; |
871 | |||
854 | if (!tomoyo_correct_domain(manager) && | 872 | if (!tomoyo_correct_domain(manager) && |
855 | !tomoyo_correct_word(manager)) | 873 | !tomoyo_correct_word(manager)) |
856 | return -EINVAL; | 874 | return -EINVAL; |
@@ -894,10 +912,10 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head) | |||
894 | { | 912 | { |
895 | if (head->r.eof) | 913 | if (head->r.eof) |
896 | return; | 914 | return; |
897 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace. | 915 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER]) { |
898 | policy_list[TOMOYO_ID_MANAGER]) { | ||
899 | struct tomoyo_manager *ptr = | 916 | struct tomoyo_manager *ptr = |
900 | list_entry(head->r.acl, typeof(*ptr), head.list); | 917 | list_entry(head->r.acl, typeof(*ptr), head.list); |
918 | |||
901 | if (ptr->head.is_deleted) | 919 | if (ptr->head.is_deleted) |
902 | continue; | 920 | continue; |
903 | if (!tomoyo_flush(head)) | 921 | if (!tomoyo_flush(head)) |
@@ -933,8 +951,7 @@ static bool tomoyo_manager(void) | |||
933 | exe = tomoyo_get_exe(); | 951 | exe = tomoyo_get_exe(); |
934 | if (!exe) | 952 | if (!exe) |
935 | return false; | 953 | return false; |
936 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | 954 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], head.list) { |
937 | policy_list[TOMOYO_ID_MANAGER], head.list) { | ||
938 | if (!ptr->head.is_deleted && | 955 | if (!ptr->head.is_deleted && |
939 | (!tomoyo_pathcmp(domainname, ptr->manager) || | 956 | (!tomoyo_pathcmp(domainname, ptr->manager) || |
940 | !strcmp(exe, ptr->manager->name))) { | 957 | !strcmp(exe, ptr->manager->name))) { |
@@ -945,9 +962,10 @@ static bool tomoyo_manager(void) | |||
945 | if (!found) { /* Reduce error messages. */ | 962 | if (!found) { /* Reduce error messages. */ |
946 | static pid_t last_pid; | 963 | static pid_t last_pid; |
947 | const pid_t pid = current->pid; | 964 | const pid_t pid = current->pid; |
965 | |||
948 | if (last_pid != pid) { | 966 | if (last_pid != pid) { |
949 | printk(KERN_WARNING "%s ( %s ) is not permitted to " | 967 | pr_warn("%s ( %s ) is not permitted to update policies.\n", |
950 | "update policies.\n", domainname->name, exe); | 968 | domainname->name, exe); |
951 | last_pid = pid; | 969 | last_pid = pid; |
952 | } | 970 | } |
953 | } | 971 | } |
@@ -974,19 +992,21 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, | |||
974 | unsigned int pid; | 992 | unsigned int pid; |
975 | struct tomoyo_domain_info *domain = NULL; | 993 | struct tomoyo_domain_info *domain = NULL; |
976 | bool global_pid = false; | 994 | bool global_pid = false; |
995 | |||
977 | if (strncmp(data, "select ", 7)) | 996 | if (strncmp(data, "select ", 7)) |
978 | return false; | 997 | return false; |
979 | data += 7; | 998 | data += 7; |
980 | if (sscanf(data, "pid=%u", &pid) == 1 || | 999 | if (sscanf(data, "pid=%u", &pid) == 1 || |
981 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { | 1000 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { |
982 | struct task_struct *p; | 1001 | struct task_struct *p; |
1002 | |||
983 | rcu_read_lock(); | 1003 | rcu_read_lock(); |
984 | if (global_pid) | 1004 | if (global_pid) |
985 | p = find_task_by_pid_ns(pid, &init_pid_ns); | 1005 | p = find_task_by_pid_ns(pid, &init_pid_ns); |
986 | else | 1006 | else |
987 | p = find_task_by_vpid(pid); | 1007 | p = find_task_by_vpid(pid); |
988 | if (p) | 1008 | if (p) |
989 | domain = tomoyo_real_domain(p); | 1009 | domain = tomoyo_task(p)->domain_info; |
990 | rcu_read_unlock(); | 1010 | rcu_read_unlock(); |
991 | } else if (!strncmp(data, "domain=", 7)) { | 1011 | } else if (!strncmp(data, "domain=", 7)) { |
992 | if (tomoyo_domain_def(data + 7)) | 1012 | if (tomoyo_domain_def(data + 7)) |
@@ -1020,10 +1040,11 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, | |||
1020 | * Returns true if @a == @b, false otherwise. | 1040 | * Returns true if @a == @b, false otherwise. |
1021 | */ | 1041 | */ |
1022 | static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a, | 1042 | static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a, |
1023 | const struct tomoyo_acl_info *b) | 1043 | const struct tomoyo_acl_info *b) |
1024 | { | 1044 | { |
1025 | const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head); | 1045 | const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head); |
1026 | const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head); | 1046 | const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head); |
1047 | |||
1027 | return p1->domainname == p2->domainname; | 1048 | return p1->domainname == p2->domainname; |
1028 | } | 1049 | } |
1029 | 1050 | ||
@@ -1039,11 +1060,13 @@ static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a, | |||
1039 | static int tomoyo_write_task(struct tomoyo_acl_param *param) | 1060 | static int tomoyo_write_task(struct tomoyo_acl_param *param) |
1040 | { | 1061 | { |
1041 | int error = -EINVAL; | 1062 | int error = -EINVAL; |
1063 | |||
1042 | if (tomoyo_str_starts(¶m->data, "manual_domain_transition ")) { | 1064 | if (tomoyo_str_starts(¶m->data, "manual_domain_transition ")) { |
1043 | struct tomoyo_task_acl e = { | 1065 | struct tomoyo_task_acl e = { |
1044 | .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL, | 1066 | .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL, |
1045 | .domainname = tomoyo_get_domainname(param), | 1067 | .domainname = tomoyo_get_domainname(param), |
1046 | }; | 1068 | }; |
1069 | |||
1047 | if (e.domainname) | 1070 | if (e.domainname) |
1048 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | 1071 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
1049 | tomoyo_same_task_acl, | 1072 | tomoyo_same_task_acl, |
@@ -1110,7 +1133,7 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, | |||
1110 | }; | 1133 | }; |
1111 | static const struct { | 1134 | static const struct { |
1112 | const char *keyword; | 1135 | const char *keyword; |
1113 | int (*write) (struct tomoyo_acl_param *); | 1136 | int (*write)(struct tomoyo_acl_param *param); |
1114 | } tomoyo_callback[5] = { | 1137 | } tomoyo_callback[5] = { |
1115 | { "file ", tomoyo_write_file }, | 1138 | { "file ", tomoyo_write_file }, |
1116 | { "network inet ", tomoyo_write_inet_network }, | 1139 | { "network inet ", tomoyo_write_inet_network }, |
@@ -1151,9 +1174,11 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | |||
1151 | struct tomoyo_domain_info *domain = head->w.domain; | 1174 | struct tomoyo_domain_info *domain = head->w.domain; |
1152 | const bool is_delete = head->w.is_delete; | 1175 | const bool is_delete = head->w.is_delete; |
1153 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); | 1176 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); |
1154 | unsigned int profile; | 1177 | unsigned int idx; |
1178 | |||
1155 | if (*data == '<') { | 1179 | if (*data == '<') { |
1156 | int ret = 0; | 1180 | int ret = 0; |
1181 | |||
1157 | domain = NULL; | 1182 | domain = NULL; |
1158 | if (is_delete) | 1183 | if (is_delete) |
1159 | ret = tomoyo_delete_domain(data); | 1184 | ret = tomoyo_delete_domain(data); |
@@ -1167,23 +1192,27 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | |||
1167 | if (!domain) | 1192 | if (!domain) |
1168 | return -EINVAL; | 1193 | return -EINVAL; |
1169 | ns = domain->ns; | 1194 | ns = domain->ns; |
1170 | if (sscanf(data, "use_profile %u", &profile) == 1 | 1195 | if (sscanf(data, "use_profile %u", &idx) == 1 |
1171 | && profile < TOMOYO_MAX_PROFILES) { | 1196 | && idx < TOMOYO_MAX_PROFILES) { |
1172 | if (!tomoyo_policy_loaded || ns->profile_ptr[profile]) | 1197 | if (!tomoyo_policy_loaded || ns->profile_ptr[idx]) |
1173 | domain->profile = (u8) profile; | 1198 | if (!is_delete) |
1199 | domain->profile = (u8) idx; | ||
1174 | return 0; | 1200 | return 0; |
1175 | } | 1201 | } |
1176 | if (sscanf(data, "use_group %u\n", &profile) == 1 | 1202 | if (sscanf(data, "use_group %u\n", &idx) == 1 |
1177 | && profile < TOMOYO_MAX_ACL_GROUPS) { | 1203 | && idx < TOMOYO_MAX_ACL_GROUPS) { |
1178 | if (!is_delete) | 1204 | if (!is_delete) |
1179 | domain->group = (u8) profile; | 1205 | set_bit(idx, domain->group); |
1206 | else | ||
1207 | clear_bit(idx, domain->group); | ||
1180 | return 0; | 1208 | return 0; |
1181 | } | 1209 | } |
1182 | for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) { | 1210 | for (idx = 0; idx < TOMOYO_MAX_DOMAIN_INFO_FLAGS; idx++) { |
1183 | const char *cp = tomoyo_dif[profile]; | 1211 | const char *cp = tomoyo_dif[idx]; |
1212 | |||
1184 | if (strncmp(data, cp, strlen(cp) - 1)) | 1213 | if (strncmp(data, cp, strlen(cp) - 1)) |
1185 | continue; | 1214 | continue; |
1186 | domain->flags[profile] = !is_delete; | 1215 | domain->flags[idx] = !is_delete; |
1187 | return 0; | 1216 | return 0; |
1188 | } | 1217 | } |
1189 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, | 1218 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, |
@@ -1225,9 +1254,11 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1225 | const struct tomoyo_envp *envp = | 1254 | const struct tomoyo_envp *envp = |
1226 | (typeof(envp)) (argv + cond->argc); | 1255 | (typeof(envp)) (argv + cond->argc); |
1227 | u16 skip; | 1256 | u16 skip; |
1257 | |||
1228 | for (skip = 0; skip < head->r.cond_index; skip++) { | 1258 | for (skip = 0; skip < head->r.cond_index; skip++) { |
1229 | const u8 left = condp->left; | 1259 | const u8 left = condp->left; |
1230 | const u8 right = condp->right; | 1260 | const u8 right = condp->right; |
1261 | |||
1231 | condp++; | 1262 | condp++; |
1232 | switch (left) { | 1263 | switch (left) { |
1233 | case TOMOYO_ARGV_ENTRY: | 1264 | case TOMOYO_ARGV_ENTRY: |
@@ -1253,6 +1284,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1253 | const u8 match = condp->equals; | 1284 | const u8 match = condp->equals; |
1254 | const u8 left = condp->left; | 1285 | const u8 left = condp->left; |
1255 | const u8 right = condp->right; | 1286 | const u8 right = condp->right; |
1287 | |||
1256 | if (!tomoyo_flush(head)) | 1288 | if (!tomoyo_flush(head)) |
1257 | return false; | 1289 | return false; |
1258 | condp++; | 1290 | condp++; |
@@ -1262,8 +1294,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1262 | case TOMOYO_ARGV_ENTRY: | 1294 | case TOMOYO_ARGV_ENTRY: |
1263 | tomoyo_io_printf(head, | 1295 | tomoyo_io_printf(head, |
1264 | "exec.argv[%lu]%s=\"", | 1296 | "exec.argv[%lu]%s=\"", |
1265 | argv->index, argv-> | 1297 | argv->index, argv->is_not ? "!" : ""); |
1266 | is_not ? "!" : ""); | ||
1267 | tomoyo_set_string(head, | 1298 | tomoyo_set_string(head, |
1268 | argv->value->name); | 1299 | argv->value->name); |
1269 | tomoyo_set_string(head, "\""); | 1300 | tomoyo_set_string(head, "\""); |
@@ -1274,12 +1305,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1274 | "exec.envp[\""); | 1305 | "exec.envp[\""); |
1275 | tomoyo_set_string(head, | 1306 | tomoyo_set_string(head, |
1276 | envp->name->name); | 1307 | envp->name->name); |
1277 | tomoyo_io_printf(head, "\"]%s=", envp-> | 1308 | tomoyo_io_printf(head, "\"]%s=", envp->is_not ? "!" : ""); |
1278 | is_not ? "!" : ""); | ||
1279 | if (envp->value) { | 1309 | if (envp->value) { |
1280 | tomoyo_set_string(head, "\""); | 1310 | tomoyo_set_string(head, "\""); |
1281 | tomoyo_set_string(head, envp-> | 1311 | tomoyo_set_string(head, envp->value->name); |
1282 | value->name); | ||
1283 | tomoyo_set_string(head, "\""); | 1312 | tomoyo_set_string(head, "\""); |
1284 | } else { | 1313 | } else { |
1285 | tomoyo_set_string(head, | 1314 | tomoyo_set_string(head, |
@@ -1375,6 +1404,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1375 | struct tomoyo_path_acl *ptr = | 1404 | struct tomoyo_path_acl *ptr = |
1376 | container_of(acl, typeof(*ptr), head); | 1405 | container_of(acl, typeof(*ptr), head); |
1377 | const u16 perm = ptr->perm; | 1406 | const u16 perm = ptr->perm; |
1407 | |||
1378 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1408 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
1379 | if (!(perm & (1 << bit))) | 1409 | if (!(perm & (1 << bit))) |
1380 | continue; | 1410 | continue; |
@@ -1395,6 +1425,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1395 | } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) { | 1425 | } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) { |
1396 | struct tomoyo_task_acl *ptr = | 1426 | struct tomoyo_task_acl *ptr = |
1397 | container_of(acl, typeof(*ptr), head); | 1427 | container_of(acl, typeof(*ptr), head); |
1428 | |||
1398 | tomoyo_set_group(head, "task "); | 1429 | tomoyo_set_group(head, "task "); |
1399 | tomoyo_set_string(head, "manual_domain_transition "); | 1430 | tomoyo_set_string(head, "manual_domain_transition "); |
1400 | tomoyo_set_string(head, ptr->domainname->name); | 1431 | tomoyo_set_string(head, ptr->domainname->name); |
@@ -1404,6 +1435,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1404 | struct tomoyo_path2_acl *ptr = | 1435 | struct tomoyo_path2_acl *ptr = |
1405 | container_of(acl, typeof(*ptr), head); | 1436 | container_of(acl, typeof(*ptr), head); |
1406 | const u8 perm = ptr->perm; | 1437 | const u8 perm = ptr->perm; |
1438 | |||
1407 | for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { | 1439 | for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
1408 | if (!(perm & (1 << bit))) | 1440 | if (!(perm & (1 << bit))) |
1409 | continue; | 1441 | continue; |
@@ -1424,6 +1456,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1424 | struct tomoyo_path_number_acl *ptr = | 1456 | struct tomoyo_path_number_acl *ptr = |
1425 | container_of(acl, typeof(*ptr), head); | 1457 | container_of(acl, typeof(*ptr), head); |
1426 | const u8 perm = ptr->perm; | 1458 | const u8 perm = ptr->perm; |
1459 | |||
1427 | for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { | 1460 | for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { |
1428 | if (!(perm & (1 << bit))) | 1461 | if (!(perm & (1 << bit))) |
1429 | continue; | 1462 | continue; |
@@ -1444,6 +1477,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1444 | struct tomoyo_mkdev_acl *ptr = | 1477 | struct tomoyo_mkdev_acl *ptr = |
1445 | container_of(acl, typeof(*ptr), head); | 1478 | container_of(acl, typeof(*ptr), head); |
1446 | const u8 perm = ptr->perm; | 1479 | const u8 perm = ptr->perm; |
1480 | |||
1447 | for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { | 1481 | for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { |
1448 | if (!(perm & (1 << bit))) | 1482 | if (!(perm & (1 << bit))) |
1449 | continue; | 1483 | continue; |
@@ -1490,6 +1524,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1490 | ->name); | 1524 | ->name); |
1491 | } else { | 1525 | } else { |
1492 | char buf[128]; | 1526 | char buf[128]; |
1527 | |||
1493 | tomoyo_print_ip(buf, sizeof(buf), &ptr->address); | 1528 | tomoyo_print_ip(buf, sizeof(buf), &ptr->address); |
1494 | tomoyo_io_printf(head, "%s", buf); | 1529 | tomoyo_io_printf(head, "%s", buf); |
1495 | } | 1530 | } |
@@ -1519,6 +1554,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1519 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 1554 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
1520 | struct tomoyo_mount_acl *ptr = | 1555 | struct tomoyo_mount_acl *ptr = |
1521 | container_of(acl, typeof(*ptr), head); | 1556 | container_of(acl, typeof(*ptr), head); |
1557 | |||
1522 | tomoyo_set_group(head, "file mount"); | 1558 | tomoyo_set_group(head, "file mount"); |
1523 | tomoyo_print_name_union(head, &ptr->dev_name); | 1559 | tomoyo_print_name_union(head, &ptr->dev_name); |
1524 | tomoyo_print_name_union(head, &ptr->dir_name); | 1560 | tomoyo_print_name_union(head, &ptr->dir_name); |
@@ -1562,6 +1598,7 @@ static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, | |||
1562 | list_for_each_cookie(head->r.acl, list) { | 1598 | list_for_each_cookie(head->r.acl, list) { |
1563 | struct tomoyo_acl_info *ptr = | 1599 | struct tomoyo_acl_info *ptr = |
1564 | list_entry(head->r.acl, typeof(*ptr), list); | 1600 | list_entry(head->r.acl, typeof(*ptr), list); |
1601 | |||
1565 | if (!tomoyo_print_entry(head, ptr)) | 1602 | if (!tomoyo_print_entry(head, ptr)) |
1566 | return false; | 1603 | return false; |
1567 | } | 1604 | } |
@@ -1583,8 +1620,9 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1583 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { | 1620 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { |
1584 | struct tomoyo_domain_info *domain = | 1621 | struct tomoyo_domain_info *domain = |
1585 | list_entry(head->r.domain, typeof(*domain), list); | 1622 | list_entry(head->r.domain, typeof(*domain), list); |
1623 | u8 i; | ||
1624 | |||
1586 | switch (head->r.step) { | 1625 | switch (head->r.step) { |
1587 | u8 i; | ||
1588 | case 0: | 1626 | case 0: |
1589 | if (domain->is_deleted && | 1627 | if (domain->is_deleted && |
1590 | !head->r.print_this_domain_only) | 1628 | !head->r.print_this_domain_only) |
@@ -1594,22 +1632,33 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1594 | tomoyo_set_lf(head); | 1632 | tomoyo_set_lf(head); |
1595 | tomoyo_io_printf(head, "use_profile %u\n", | 1633 | tomoyo_io_printf(head, "use_profile %u\n", |
1596 | domain->profile); | 1634 | domain->profile); |
1597 | tomoyo_io_printf(head, "use_group %u\n", | ||
1598 | domain->group); | ||
1599 | for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) | 1635 | for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) |
1600 | if (domain->flags[i]) | 1636 | if (domain->flags[i]) |
1601 | tomoyo_set_string(head, tomoyo_dif[i]); | 1637 | tomoyo_set_string(head, tomoyo_dif[i]); |
1638 | head->r.index = 0; | ||
1602 | head->r.step++; | 1639 | head->r.step++; |
1603 | tomoyo_set_lf(head); | ||
1604 | /* fall through */ | 1640 | /* fall through */ |
1605 | case 1: | 1641 | case 1: |
1642 | while (head->r.index < TOMOYO_MAX_ACL_GROUPS) { | ||
1643 | i = head->r.index++; | ||
1644 | if (!test_bit(i, domain->group)) | ||
1645 | continue; | ||
1646 | tomoyo_io_printf(head, "use_group %u\n", i); | ||
1647 | if (!tomoyo_flush(head)) | ||
1648 | return; | ||
1649 | } | ||
1650 | head->r.index = 0; | ||
1651 | head->r.step++; | ||
1652 | tomoyo_set_lf(head); | ||
1653 | /* fall through */ | ||
1654 | case 2: | ||
1606 | if (!tomoyo_read_domain2(head, &domain->acl_info_list)) | 1655 | if (!tomoyo_read_domain2(head, &domain->acl_info_list)) |
1607 | return; | 1656 | return; |
1608 | head->r.step++; | 1657 | head->r.step++; |
1609 | if (!tomoyo_set_lf(head)) | 1658 | if (!tomoyo_set_lf(head)) |
1610 | return; | 1659 | return; |
1611 | /* fall through */ | 1660 | /* fall through */ |
1612 | case 2: | 1661 | case 3: |
1613 | head->r.step = 0; | 1662 | head->r.step = 0; |
1614 | if (head->r.print_this_domain_only) | 1663 | if (head->r.print_this_domain_only) |
1615 | goto done; | 1664 | goto done; |
@@ -1668,7 +1717,7 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1668 | else | 1717 | else |
1669 | p = find_task_by_vpid(pid); | 1718 | p = find_task_by_vpid(pid); |
1670 | if (p) | 1719 | if (p) |
1671 | domain = tomoyo_real_domain(p); | 1720 | domain = tomoyo_task(p)->domain_info; |
1672 | rcu_read_unlock(); | 1721 | rcu_read_unlock(); |
1673 | if (!domain) | 1722 | if (!domain) |
1674 | return; | 1723 | return; |
@@ -1711,6 +1760,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1711 | .data = head->write_buf, | 1760 | .data = head->write_buf, |
1712 | }; | 1761 | }; |
1713 | u8 i; | 1762 | u8 i; |
1763 | |||
1714 | if (tomoyo_str_starts(¶m.data, "aggregator ")) | 1764 | if (tomoyo_str_starts(¶m.data, "aggregator ")) |
1715 | return tomoyo_write_aggregator(¶m); | 1765 | return tomoyo_write_aggregator(¶m); |
1716 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) | 1766 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) |
@@ -1722,6 +1772,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1722 | if (tomoyo_str_starts(¶m.data, "acl_group ")) { | 1772 | if (tomoyo_str_starts(¶m.data, "acl_group ")) { |
1723 | unsigned int group; | 1773 | unsigned int group; |
1724 | char *data; | 1774 | char *data; |
1775 | |||
1725 | group = simple_strtoul(param.data, &data, 10); | 1776 | group = simple_strtoul(param.data, &data, 10); |
1726 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') | 1777 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') |
1727 | return tomoyo_write_domain2 | 1778 | return tomoyo_write_domain2 |
@@ -1746,12 +1797,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1746 | struct tomoyo_policy_namespace *ns = | 1797 | struct tomoyo_policy_namespace *ns = |
1747 | container_of(head->r.ns, typeof(*ns), namespace_list); | 1798 | container_of(head->r.ns, typeof(*ns), namespace_list); |
1748 | struct list_head *list = &ns->group_list[idx]; | 1799 | struct list_head *list = &ns->group_list[idx]; |
1800 | |||
1749 | list_for_each_cookie(head->r.group, list) { | 1801 | list_for_each_cookie(head->r.group, list) { |
1750 | struct tomoyo_group *group = | 1802 | struct tomoyo_group *group = |
1751 | list_entry(head->r.group, typeof(*group), head.list); | 1803 | list_entry(head->r.group, typeof(*group), head.list); |
1804 | |||
1752 | list_for_each_cookie(head->r.acl, &group->member_list) { | 1805 | list_for_each_cookie(head->r.acl, &group->member_list) { |
1753 | struct tomoyo_acl_head *ptr = | 1806 | struct tomoyo_acl_head *ptr = |
1754 | list_entry(head->r.acl, typeof(*ptr), list); | 1807 | list_entry(head->r.acl, typeof(*ptr), list); |
1808 | |||
1755 | if (ptr->is_deleted) | 1809 | if (ptr->is_deleted) |
1756 | continue; | 1810 | continue; |
1757 | if (!tomoyo_flush(head)) | 1811 | if (!tomoyo_flush(head)) |
@@ -1771,10 +1825,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1771 | head)->number); | 1825 | head)->number); |
1772 | } else if (idx == TOMOYO_ADDRESS_GROUP) { | 1826 | } else if (idx == TOMOYO_ADDRESS_GROUP) { |
1773 | char buffer[128]; | 1827 | char buffer[128]; |
1774 | |||
1775 | struct tomoyo_address_group *member = | 1828 | struct tomoyo_address_group *member = |
1776 | container_of(ptr, typeof(*member), | 1829 | container_of(ptr, typeof(*member), |
1777 | head); | 1830 | head); |
1831 | |||
1778 | tomoyo_print_ip(buffer, sizeof(buffer), | 1832 | tomoyo_print_ip(buffer, sizeof(buffer), |
1779 | &member->address); | 1833 | &member->address); |
1780 | tomoyo_io_printf(head, " %s", buffer); | 1834 | tomoyo_io_printf(head, " %s", buffer); |
@@ -1802,6 +1856,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1802 | struct tomoyo_policy_namespace *ns = | 1856 | struct tomoyo_policy_namespace *ns = |
1803 | container_of(head->r.ns, typeof(*ns), namespace_list); | 1857 | container_of(head->r.ns, typeof(*ns), namespace_list); |
1804 | struct list_head *list = &ns->policy_list[idx]; | 1858 | struct list_head *list = &ns->policy_list[idx]; |
1859 | |||
1805 | list_for_each_cookie(head->r.acl, list) { | 1860 | list_for_each_cookie(head->r.acl, list) { |
1806 | struct tomoyo_acl_head *acl = | 1861 | struct tomoyo_acl_head *acl = |
1807 | container_of(head->r.acl, typeof(*acl), list); | 1862 | container_of(head->r.acl, typeof(*acl), list); |
@@ -1814,6 +1869,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1814 | { | 1869 | { |
1815 | struct tomoyo_transition_control *ptr = | 1870 | struct tomoyo_transition_control *ptr = |
1816 | container_of(acl, typeof(*ptr), head); | 1871 | container_of(acl, typeof(*ptr), head); |
1872 | |||
1817 | tomoyo_print_namespace(head); | 1873 | tomoyo_print_namespace(head); |
1818 | tomoyo_set_string(head, tomoyo_transition_type | 1874 | tomoyo_set_string(head, tomoyo_transition_type |
1819 | [ptr->type]); | 1875 | [ptr->type]); |
@@ -1829,6 +1885,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1829 | { | 1885 | { |
1830 | struct tomoyo_aggregator *ptr = | 1886 | struct tomoyo_aggregator *ptr = |
1831 | container_of(acl, typeof(*ptr), head); | 1887 | container_of(acl, typeof(*ptr), head); |
1888 | |||
1832 | tomoyo_print_namespace(head); | 1889 | tomoyo_print_namespace(head); |
1833 | tomoyo_set_string(head, "aggregator "); | 1890 | tomoyo_set_string(head, "aggregator "); |
1834 | tomoyo_set_string(head, | 1891 | tomoyo_set_string(head, |
@@ -1858,6 +1915,7 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | |||
1858 | { | 1915 | { |
1859 | struct tomoyo_policy_namespace *ns = | 1916 | struct tomoyo_policy_namespace *ns = |
1860 | container_of(head->r.ns, typeof(*ns), namespace_list); | 1917 | container_of(head->r.ns, typeof(*ns), namespace_list); |
1918 | |||
1861 | if (head->r.eof) | 1919 | if (head->r.eof) |
1862 | return; | 1920 | return; |
1863 | while (head->r.step < TOMOYO_MAX_POLICY && | 1921 | while (head->r.step < TOMOYO_MAX_POLICY && |
@@ -1921,6 +1979,7 @@ static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | |||
1921 | static int tomoyo_truncate(char *str) | 1979 | static int tomoyo_truncate(char *str) |
1922 | { | 1980 | { |
1923 | char *start = str; | 1981 | char *start = str; |
1982 | |||
1924 | while (*(unsigned char *) str > (unsigned char) ' ') | 1983 | while (*(unsigned char *) str > (unsigned char) ' ') |
1925 | str++; | 1984 | str++; |
1926 | *str = '\0'; | 1985 | *str = '\0'; |
@@ -1943,6 +2002,7 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) | |||
1943 | char *symlink = NULL; | 2002 | char *symlink = NULL; |
1944 | char *cp = strchr(header, '\n'); | 2003 | char *cp = strchr(header, '\n'); |
1945 | int len; | 2004 | int len; |
2005 | |||
1946 | if (!cp) | 2006 | if (!cp) |
1947 | return; | 2007 | return; |
1948 | cp = strchr(cp + 1, '\n'); | 2008 | cp = strchr(cp + 1, '\n'); |
@@ -2002,6 +2062,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | |||
2002 | static unsigned int tomoyo_serial; | 2062 | static unsigned int tomoyo_serial; |
2003 | struct tomoyo_query entry = { }; | 2063 | struct tomoyo_query entry = { }; |
2004 | bool quota_exceeded = false; | 2064 | bool quota_exceeded = false; |
2065 | |||
2005 | va_start(args, fmt); | 2066 | va_start(args, fmt); |
2006 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | 2067 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; |
2007 | va_end(args); | 2068 | va_end(args); |
@@ -2063,8 +2124,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | |||
2063 | (tomoyo_answer_wait, entry.answer || | 2124 | (tomoyo_answer_wait, entry.answer || |
2064 | !atomic_read(&tomoyo_query_observers), HZ)) | 2125 | !atomic_read(&tomoyo_query_observers), HZ)) |
2065 | break; | 2126 | break; |
2066 | else | 2127 | entry.timer++; |
2067 | entry.timer++; | ||
2068 | } | 2128 | } |
2069 | spin_lock(&tomoyo_query_list_lock); | 2129 | spin_lock(&tomoyo_query_list_lock); |
2070 | list_del(&entry.list); | 2130 | list_del(&entry.list); |
@@ -2100,6 +2160,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid | |||
2100 | { | 2160 | { |
2101 | struct tomoyo_query *ptr; | 2161 | struct tomoyo_query *ptr; |
2102 | struct tomoyo_domain_info *domain = NULL; | 2162 | struct tomoyo_domain_info *domain = NULL; |
2163 | |||
2103 | spin_lock(&tomoyo_query_list_lock); | 2164 | spin_lock(&tomoyo_query_list_lock); |
2104 | list_for_each_entry(ptr, &tomoyo_query_list, list) { | 2165 | list_for_each_entry(ptr, &tomoyo_query_list, list) { |
2105 | if (ptr->serial != serial) | 2166 | if (ptr->serial != serial) |
@@ -2142,15 +2203,15 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
2142 | unsigned int pos = 0; | 2203 | unsigned int pos = 0; |
2143 | size_t len = 0; | 2204 | size_t len = 0; |
2144 | char *buf; | 2205 | char *buf; |
2206 | |||
2145 | if (head->r.w_pos) | 2207 | if (head->r.w_pos) |
2146 | return; | 2208 | return; |
2147 | if (head->read_buf) { | 2209 | kfree(head->read_buf); |
2148 | kfree(head->read_buf); | 2210 | head->read_buf = NULL; |
2149 | head->read_buf = NULL; | ||
2150 | } | ||
2151 | spin_lock(&tomoyo_query_list_lock); | 2211 | spin_lock(&tomoyo_query_list_lock); |
2152 | list_for_each(tmp, &tomoyo_query_list) { | 2212 | list_for_each(tmp, &tomoyo_query_list) { |
2153 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 2213 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
2214 | |||
2154 | if (pos++ != head->r.query_index) | 2215 | if (pos++ != head->r.query_index) |
2155 | continue; | 2216 | continue; |
2156 | len = ptr->query_len; | 2217 | len = ptr->query_len; |
@@ -2168,6 +2229,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
2168 | spin_lock(&tomoyo_query_list_lock); | 2229 | spin_lock(&tomoyo_query_list_lock); |
2169 | list_for_each(tmp, &tomoyo_query_list) { | 2230 | list_for_each(tmp, &tomoyo_query_list) { |
2170 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 2231 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
2232 | |||
2171 | if (pos++ != head->r.query_index) | 2233 | if (pos++ != head->r.query_index) |
2172 | continue; | 2234 | continue; |
2173 | /* | 2235 | /* |
@@ -2202,9 +2264,11 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
2202 | struct list_head *tmp; | 2264 | struct list_head *tmp; |
2203 | unsigned int serial; | 2265 | unsigned int serial; |
2204 | unsigned int answer; | 2266 | unsigned int answer; |
2267 | |||
2205 | spin_lock(&tomoyo_query_list_lock); | 2268 | spin_lock(&tomoyo_query_list_lock); |
2206 | list_for_each(tmp, &tomoyo_query_list) { | 2269 | list_for_each(tmp, &tomoyo_query_list) { |
2207 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 2270 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
2271 | |||
2208 | ptr->timer = 0; | 2272 | ptr->timer = 0; |
2209 | } | 2273 | } |
2210 | spin_unlock(&tomoyo_query_list_lock); | 2274 | spin_unlock(&tomoyo_query_list_lock); |
@@ -2213,6 +2277,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
2213 | spin_lock(&tomoyo_query_list_lock); | 2277 | spin_lock(&tomoyo_query_list_lock); |
2214 | list_for_each(tmp, &tomoyo_query_list) { | 2278 | list_for_each(tmp, &tomoyo_query_list) { |
2215 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 2279 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
2280 | |||
2216 | if (ptr->serial != serial) | 2281 | if (ptr->serial != serial) |
2217 | continue; | 2282 | continue; |
2218 | ptr->answer = answer; | 2283 | ptr->answer = answer; |
@@ -2235,7 +2300,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
2235 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 2300 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
2236 | { | 2301 | { |
2237 | if (!head->r.eof) { | 2302 | if (!head->r.eof) { |
2238 | tomoyo_io_printf(head, "2.5.0"); | 2303 | tomoyo_io_printf(head, "2.6.0"); |
2239 | head->r.eof = true; | 2304 | head->r.eof = true; |
2240 | } | 2305 | } |
2241 | } | 2306 | } |
@@ -2287,6 +2352,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head) | |||
2287 | { | 2352 | { |
2288 | u8 i; | 2353 | u8 i; |
2289 | unsigned int total = 0; | 2354 | unsigned int total = 0; |
2355 | |||
2290 | if (head->r.eof) | 2356 | if (head->r.eof) |
2291 | return; | 2357 | return; |
2292 | for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { | 2358 | for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { |
@@ -2295,9 +2361,9 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head) | |||
2295 | tomoyo_stat_updated[i]); | 2361 | tomoyo_stat_updated[i]); |
2296 | if (tomoyo_stat_modified[i]) { | 2362 | if (tomoyo_stat_modified[i]) { |
2297 | struct tomoyo_time stamp; | 2363 | struct tomoyo_time stamp; |
2364 | |||
2298 | tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); | 2365 | tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); |
2299 | tomoyo_io_printf(head, " (Last: %04u/%02u/%02u " | 2366 | tomoyo_io_printf(head, " (Last: %04u/%02u/%02u %02u:%02u:%02u)", |
2300 | "%02u:%02u:%02u)", | ||
2301 | stamp.year, stamp.month, stamp.day, | 2367 | stamp.year, stamp.month, stamp.day, |
2302 | stamp.hour, stamp.min, stamp.sec); | 2368 | stamp.hour, stamp.min, stamp.sec); |
2303 | } | 2369 | } |
@@ -2305,6 +2371,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head) | |||
2305 | } | 2371 | } |
2306 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { | 2372 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { |
2307 | unsigned int used = tomoyo_memory_used[i]; | 2373 | unsigned int used = tomoyo_memory_used[i]; |
2374 | |||
2308 | total += used; | 2375 | total += used; |
2309 | tomoyo_io_printf(head, "Memory used by %-22s %10u", | 2376 | tomoyo_io_printf(head, "Memory used by %-22s %10u", |
2310 | tomoyo_memory_headers[i], used); | 2377 | tomoyo_memory_headers[i], used); |
@@ -2329,6 +2396,7 @@ static int tomoyo_write_stat(struct tomoyo_io_buffer *head) | |||
2329 | { | 2396 | { |
2330 | char *data = head->write_buf; | 2397 | char *data = head->write_buf; |
2331 | u8 i; | 2398 | u8 i; |
2399 | |||
2332 | if (tomoyo_str_starts(&data, "Memory used by ")) | 2400 | if (tomoyo_str_starts(&data, "Memory used by ")) |
2333 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) | 2401 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) |
2334 | if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) | 2402 | if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) |
@@ -2457,6 +2525,7 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
2457 | __poll_t tomoyo_poll_control(struct file *file, poll_table *wait) | 2525 | __poll_t tomoyo_poll_control(struct file *file, poll_table *wait) |
2458 | { | 2526 | { |
2459 | struct tomoyo_io_buffer *head = file->private_data; | 2527 | struct tomoyo_io_buffer *head = file->private_data; |
2528 | |||
2460 | if (head->poll) | 2529 | if (head->poll) |
2461 | return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM; | 2530 | return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM; |
2462 | return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM; | 2531 | return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM; |
@@ -2472,6 +2541,7 @@ __poll_t tomoyo_poll_control(struct file *file, poll_table *wait) | |||
2472 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) | 2541 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) |
2473 | { | 2542 | { |
2474 | struct list_head *ns; | 2543 | struct list_head *ns; |
2544 | |||
2475 | if (head->type != TOMOYO_EXCEPTIONPOLICY && | 2545 | if (head->type != TOMOYO_EXCEPTIONPOLICY && |
2476 | head->type != TOMOYO_PROFILE) | 2546 | head->type != TOMOYO_PROFILE) |
2477 | return; | 2547 | return; |
@@ -2517,7 +2587,7 @@ ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, | |||
2517 | int idx; | 2587 | int idx; |
2518 | 2588 | ||
2519 | if (!head->read) | 2589 | if (!head->read) |
2520 | return -ENOSYS; | 2590 | return -EINVAL; |
2521 | if (mutex_lock_interruptible(&head->io_sem)) | 2591 | if (mutex_lock_interruptible(&head->io_sem)) |
2522 | return -EINTR; | 2592 | return -EINTR; |
2523 | head->read_user_buf = buffer; | 2593 | head->read_user_buf = buffer; |
@@ -2557,6 +2627,7 @@ static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) | |||
2557 | head->type == TOMOYO_PROFILE) { | 2627 | head->type == TOMOYO_PROFILE) { |
2558 | if (*line == '<') { | 2628 | if (*line == '<') { |
2559 | char *cp = strchr(line, ' '); | 2629 | char *cp = strchr(line, ' '); |
2630 | |||
2560 | if (cp) { | 2631 | if (cp) { |
2561 | *cp++ = '\0'; | 2632 | *cp++ = '\0'; |
2562 | head->w.ns = tomoyo_assign_namespace(line); | 2633 | head->w.ns = tomoyo_assign_namespace(line); |
@@ -2589,8 +2660,9 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | |||
2589 | size_t avail_len = buffer_len; | 2660 | size_t avail_len = buffer_len; |
2590 | char *cp0 = head->write_buf; | 2661 | char *cp0 = head->write_buf; |
2591 | int idx; | 2662 | int idx; |
2663 | |||
2592 | if (!head->write) | 2664 | if (!head->write) |
2593 | return -ENOSYS; | 2665 | return -EINVAL; |
2594 | if (!access_ok(buffer, buffer_len)) | 2666 | if (!access_ok(buffer, buffer_len)) |
2595 | return -EFAULT; | 2667 | return -EFAULT; |
2596 | if (mutex_lock_interruptible(&head->io_sem)) | 2668 | if (mutex_lock_interruptible(&head->io_sem)) |
@@ -2600,9 +2672,11 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | |||
2600 | /* Read a line and dispatch it to the policy handler. */ | 2672 | /* Read a line and dispatch it to the policy handler. */ |
2601 | while (avail_len > 0) { | 2673 | while (avail_len > 0) { |
2602 | char c; | 2674 | char c; |
2675 | |||
2603 | if (head->w.avail >= head->writebuf_size - 1) { | 2676 | if (head->w.avail >= head->writebuf_size - 1) { |
2604 | const int len = head->writebuf_size * 2; | 2677 | const int len = head->writebuf_size * 2; |
2605 | char *cp = kzalloc(len, GFP_NOFS); | 2678 | char *cp = kzalloc(len, GFP_NOFS); |
2679 | |||
2606 | if (!cp) { | 2680 | if (!cp) { |
2607 | error = -ENOMEM; | 2681 | error = -ENOMEM; |
2608 | break; | 2682 | break; |
@@ -2701,30 +2775,32 @@ void tomoyo_check_profile(void) | |||
2701 | { | 2775 | { |
2702 | struct tomoyo_domain_info *domain; | 2776 | struct tomoyo_domain_info *domain; |
2703 | const int idx = tomoyo_read_lock(); | 2777 | const int idx = tomoyo_read_lock(); |
2778 | |||
2704 | tomoyo_policy_loaded = true; | 2779 | tomoyo_policy_loaded = true; |
2705 | printk(KERN_INFO "TOMOYO: 2.5.0\n"); | 2780 | pr_info("TOMOYO: 2.6.0\n"); |
2706 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 2781 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
2707 | const u8 profile = domain->profile; | 2782 | const u8 profile = domain->profile; |
2708 | const struct tomoyo_policy_namespace *ns = domain->ns; | 2783 | struct tomoyo_policy_namespace *ns = domain->ns; |
2709 | if (ns->profile_version != 20110903) | 2784 | |
2710 | printk(KERN_ERR | 2785 | if (ns->profile_version == 20110903) { |
2711 | "Profile version %u is not supported.\n", | 2786 | pr_info_once("Converting profile version from %u to %u.\n", |
2787 | 20110903, 20150505); | ||
2788 | ns->profile_version = 20150505; | ||
2789 | } | ||
2790 | if (ns->profile_version != 20150505) | ||
2791 | pr_err("Profile version %u is not supported.\n", | ||
2712 | ns->profile_version); | 2792 | ns->profile_version); |
2713 | else if (!ns->profile_ptr[profile]) | 2793 | else if (!ns->profile_ptr[profile]) |
2714 | printk(KERN_ERR | 2794 | pr_err("Profile %u (used by '%s') is not defined.\n", |
2715 | "Profile %u (used by '%s') is not defined.\n", | ||
2716 | profile, domain->domainname->name); | 2795 | profile, domain->domainname->name); |
2717 | else | 2796 | else |
2718 | continue; | 2797 | continue; |
2719 | printk(KERN_ERR | 2798 | pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n"); |
2720 | "Userland tools for TOMOYO 2.5 must be installed and " | 2799 | pr_err("Please see https://tomoyo.osdn.jp/2.6/ for more information.\n"); |
2721 | "policy must be initialized.\n"); | ||
2722 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ " | ||
2723 | "for more information.\n"); | ||
2724 | panic("STOP!"); | 2800 | panic("STOP!"); |
2725 | } | 2801 | } |
2726 | tomoyo_read_unlock(idx); | 2802 | tomoyo_read_unlock(idx); |
2727 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2803 | pr_info("Mandatory Access Control activated.\n"); |
2728 | } | 2804 | } |
2729 | 2805 | ||
2730 | /** | 2806 | /** |
@@ -2743,9 +2819,11 @@ void __init tomoyo_load_builtin_policy(void) | |||
2743 | #include "builtin-policy.h" | 2819 | #include "builtin-policy.h" |
2744 | u8 i; | 2820 | u8 i; |
2745 | const int idx = tomoyo_read_lock(); | 2821 | const int idx = tomoyo_read_lock(); |
2822 | |||
2746 | for (i = 0; i < 5; i++) { | 2823 | for (i = 0; i < 5; i++) { |
2747 | struct tomoyo_io_buffer head = { }; | 2824 | struct tomoyo_io_buffer head = { }; |
2748 | char *start = ""; | 2825 | char *start = ""; |
2826 | |||
2749 | switch (i) { | 2827 | switch (i) { |
2750 | case 0: | 2828 | case 0: |
2751 | start = tomoyo_builtin_profile; | 2829 | start = tomoyo_builtin_profile; |
@@ -2775,6 +2853,7 @@ void __init tomoyo_load_builtin_policy(void) | |||
2775 | } | 2853 | } |
2776 | while (1) { | 2854 | while (1) { |
2777 | char *end = strchr(start, '\n'); | 2855 | char *end = strchr(start, '\n'); |
2856 | |||
2778 | if (!end) | 2857 | if (!end) |
2779 | break; | 2858 | break; |
2780 | *end = '\0'; | 2859 | *end = '\0'; |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 539bcdd30bb8..050473df5809 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #ifndef _SECURITY_TOMOYO_COMMON_H | 10 | #ifndef _SECURITY_TOMOYO_COMMON_H |
11 | #define _SECURITY_TOMOYO_COMMON_H | 11 | #define _SECURITY_TOMOYO_COMMON_H |
12 | 12 | ||
13 | #define pr_fmt(fmt) fmt | ||
14 | |||
13 | #include <linux/ctype.h> | 15 | #include <linux/ctype.h> |
14 | #include <linux/string.h> | 16 | #include <linux/string.h> |
15 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
@@ -29,6 +31,7 @@ | |||
29 | #include <linux/in.h> | 31 | #include <linux/in.h> |
30 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
31 | #include <linux/un.h> | 33 | #include <linux/un.h> |
34 | #include <linux/lsm_hooks.h> | ||
32 | #include <net/sock.h> | 35 | #include <net/sock.h> |
33 | #include <net/af_unix.h> | 36 | #include <net/af_unix.h> |
34 | #include <net/ip.h> | 37 | #include <net/ip.h> |
@@ -681,11 +684,12 @@ struct tomoyo_domain_info { | |||
681 | const struct tomoyo_path_info *domainname; | 684 | const struct tomoyo_path_info *domainname; |
682 | /* Namespace for this domain. Never NULL. */ | 685 | /* Namespace for this domain. Never NULL. */ |
683 | struct tomoyo_policy_namespace *ns; | 686 | struct tomoyo_policy_namespace *ns; |
687 | /* Group numbers to use. */ | ||
688 | unsigned long group[TOMOYO_MAX_ACL_GROUPS / BITS_PER_LONG]; | ||
684 | u8 profile; /* Profile number to use. */ | 689 | u8 profile; /* Profile number to use. */ |
685 | u8 group; /* Group number to use. */ | ||
686 | bool is_deleted; /* Delete flag. */ | 690 | bool is_deleted; /* Delete flag. */ |
687 | bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; | 691 | bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; |
688 | atomic_t users; /* Number of referring credentials. */ | 692 | atomic_t users; /* Number of referring tasks. */ |
689 | }; | 693 | }; |
690 | 694 | ||
691 | /* | 695 | /* |
@@ -787,9 +791,9 @@ struct tomoyo_acl_param { | |||
787 | * interfaces. | 791 | * interfaces. |
788 | */ | 792 | */ |
789 | struct tomoyo_io_buffer { | 793 | struct tomoyo_io_buffer { |
790 | void (*read) (struct tomoyo_io_buffer *); | 794 | void (*read)(struct tomoyo_io_buffer *head); |
791 | int (*write) (struct tomoyo_io_buffer *); | 795 | int (*write)(struct tomoyo_io_buffer *head); |
792 | __poll_t (*poll) (struct file *file, poll_table *wait); | 796 | __poll_t (*poll)(struct file *file, poll_table *wait); |
793 | /* Exclusive lock for this structure. */ | 797 | /* Exclusive lock for this structure. */ |
794 | struct mutex io_sem; | 798 | struct mutex io_sem; |
795 | char __user *read_user_buf; | 799 | char __user *read_user_buf; |
@@ -906,12 +910,18 @@ struct tomoyo_policy_namespace { | |||
906 | struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; | 910 | struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; |
907 | /* List for connecting to tomoyo_namespace_list list. */ | 911 | /* List for connecting to tomoyo_namespace_list list. */ |
908 | struct list_head namespace_list; | 912 | struct list_head namespace_list; |
909 | /* Profile version. Currently only 20110903 is defined. */ | 913 | /* Profile version. Currently only 20150505 is defined. */ |
910 | unsigned int profile_version; | 914 | unsigned int profile_version; |
911 | /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ | 915 | /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ |
912 | const char *name; | 916 | const char *name; |
913 | }; | 917 | }; |
914 | 918 | ||
919 | /* Structure for "struct task_struct"->security. */ | ||
920 | struct tomoyo_task { | ||
921 | struct tomoyo_domain_info *domain_info; | ||
922 | struct tomoyo_domain_info *old_domain_info; | ||
923 | }; | ||
924 | |||
915 | /********** Function prototypes. **********/ | 925 | /********** Function prototypes. **********/ |
916 | 926 | ||
917 | bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, | 927 | bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, |
@@ -1020,6 +1030,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | |||
1020 | struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param); | 1030 | struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param); |
1021 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | 1031 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, |
1022 | const bool transit); | 1032 | const bool transit); |
1033 | struct tomoyo_domain_info *tomoyo_domain(void); | ||
1023 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | 1034 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); |
1024 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | 1035 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, |
1025 | const u8 idx); | 1036 | const u8 idx); |
@@ -1034,8 +1045,8 @@ void *tomoyo_commit_ok(void *data, const unsigned int size); | |||
1034 | void __init tomoyo_load_builtin_policy(void); | 1045 | void __init tomoyo_load_builtin_policy(void); |
1035 | void __init tomoyo_mm_init(void); | 1046 | void __init tomoyo_mm_init(void); |
1036 | void tomoyo_check_acl(struct tomoyo_request_info *r, | 1047 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
1037 | bool (*check_entry) (struct tomoyo_request_info *, | 1048 | bool (*check_entry)(struct tomoyo_request_info *, |
1038 | const struct tomoyo_acl_info *)); | 1049 | const struct tomoyo_acl_info *)); |
1039 | void tomoyo_check_profile(void); | 1050 | void tomoyo_check_profile(void); |
1040 | void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp); | 1051 | void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp); |
1041 | void tomoyo_del_condition(struct list_head *element); | 1052 | void tomoyo_del_condition(struct list_head *element); |
@@ -1062,6 +1073,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | |||
1062 | /********** External variable definitions. **********/ | 1073 | /********** External variable definitions. **********/ |
1063 | 1074 | ||
1064 | extern bool tomoyo_policy_loaded; | 1075 | extern bool tomoyo_policy_loaded; |
1076 | extern int tomoyo_enabled; | ||
1065 | extern const char * const tomoyo_condition_keyword | 1077 | extern const char * const tomoyo_condition_keyword |
1066 | [TOMOYO_MAX_CONDITION_KEYWORD]; | 1078 | [TOMOYO_MAX_CONDITION_KEYWORD]; |
1067 | extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; | 1079 | extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; |
@@ -1085,6 +1097,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; | |||
1085 | extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; | 1097 | extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; |
1086 | extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; | 1098 | extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; |
1087 | extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; | 1099 | extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; |
1100 | extern struct lsm_blob_sizes tomoyo_blob_sizes; | ||
1088 | 1101 | ||
1089 | /********** Inlined functions. **********/ | 1102 | /********** Inlined functions. **********/ |
1090 | 1103 | ||
@@ -1121,6 +1134,7 @@ static inline void tomoyo_read_unlock(int idx) | |||
1121 | static inline pid_t tomoyo_sys_getppid(void) | 1134 | static inline pid_t tomoyo_sys_getppid(void) |
1122 | { | 1135 | { |
1123 | pid_t pid; | 1136 | pid_t pid; |
1137 | |||
1124 | rcu_read_lock(); | 1138 | rcu_read_lock(); |
1125 | pid = task_tgid_vnr(rcu_dereference(current->real_parent)); | 1139 | pid = task_tgid_vnr(rcu_dereference(current->real_parent)); |
1126 | rcu_read_unlock(); | 1140 | rcu_read_unlock(); |
@@ -1197,26 +1211,15 @@ static inline void tomoyo_put_group(struct tomoyo_group *group) | |||
1197 | } | 1211 | } |
1198 | 1212 | ||
1199 | /** | 1213 | /** |
1200 | * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. | 1214 | * tomoyo_task - Get "struct tomoyo_task" for specified thread. |
1201 | * | ||
1202 | * Returns pointer to "struct tomoyo_domain_info" for current thread. | ||
1203 | */ | ||
1204 | static inline struct tomoyo_domain_info *tomoyo_domain(void) | ||
1205 | { | ||
1206 | return current_cred()->security; | ||
1207 | } | ||
1208 | |||
1209 | /** | ||
1210 | * tomoyo_real_domain - Get "struct tomoyo_domain_info" for specified thread. | ||
1211 | * | 1215 | * |
1212 | * @task: Pointer to "struct task_struct". | 1216 | * @task - Pointer to "struct task_struct". |
1213 | * | 1217 | * |
1214 | * Returns pointer to "struct tomoyo_security" for specified thread. | 1218 | * Returns pointer to "struct tomoyo_task" for specified thread. |
1215 | */ | 1219 | */ |
1216 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | 1220 | static inline struct tomoyo_task *tomoyo_task(struct task_struct *task) |
1217 | *task) | ||
1218 | { | 1221 | { |
1219 | return task_cred_xxx(task, security); | 1222 | return task->security + tomoyo_blob_sizes.lbs_task; |
1220 | } | 1223 | } |
1221 | 1224 | ||
1222 | /** | 1225 | /** |
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 8d0e1b9c9c57..8f6d57c15df6 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
@@ -28,9 +28,11 @@ static bool tomoyo_argv(const unsigned int index, const char *arg_ptr, | |||
28 | { | 28 | { |
29 | int i; | 29 | int i; |
30 | struct tomoyo_path_info arg; | 30 | struct tomoyo_path_info arg; |
31 | |||
31 | arg.name = arg_ptr; | 32 | arg.name = arg_ptr; |
32 | for (i = 0; i < argc; argv++, checked++, i++) { | 33 | for (i = 0; i < argc; argv++, checked++, i++) { |
33 | bool result; | 34 | bool result; |
35 | |||
34 | if (index != argv->index) | 36 | if (index != argv->index) |
35 | continue; | 37 | continue; |
36 | *checked = 1; | 38 | *checked = 1; |
@@ -62,12 +64,14 @@ static bool tomoyo_envp(const char *env_name, const char *env_value, | |||
62 | int i; | 64 | int i; |
63 | struct tomoyo_path_info name; | 65 | struct tomoyo_path_info name; |
64 | struct tomoyo_path_info value; | 66 | struct tomoyo_path_info value; |
67 | |||
65 | name.name = env_name; | 68 | name.name = env_name; |
66 | tomoyo_fill_path_info(&name); | 69 | tomoyo_fill_path_info(&name); |
67 | value.name = env_value; | 70 | value.name = env_value; |
68 | tomoyo_fill_path_info(&value); | 71 | tomoyo_fill_path_info(&value); |
69 | for (i = 0; i < envc; envp++, checked++, i++) { | 72 | for (i = 0; i < envc; envp++, checked++, i++) { |
70 | bool result; | 73 | bool result; |
74 | |||
71 | if (!tomoyo_path_matches_pattern(&name, envp->name)) | 75 | if (!tomoyo_path_matches_pattern(&name, envp->name)) |
72 | continue; | 76 | continue; |
73 | *checked = 1; | 77 | *checked = 1; |
@@ -113,6 +117,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, | |||
113 | bool result = true; | 117 | bool result = true; |
114 | u8 local_checked[32]; | 118 | u8 local_checked[32]; |
115 | u8 *checked; | 119 | u8 *checked; |
120 | |||
116 | if (argc + envc <= sizeof(local_checked)) { | 121 | if (argc + envc <= sizeof(local_checked)) { |
117 | checked = local_checked; | 122 | checked = local_checked; |
118 | memset(local_checked, 0, sizeof(local_checked)); | 123 | memset(local_checked, 0, sizeof(local_checked)); |
@@ -131,6 +136,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, | |||
131 | /* Read. */ | 136 | /* Read. */ |
132 | const char *kaddr = dump->data; | 137 | const char *kaddr = dump->data; |
133 | const unsigned char c = kaddr[offset++]; | 138 | const unsigned char c = kaddr[offset++]; |
139 | |||
134 | if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { | 140 | if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { |
135 | if (c == '\\') { | 141 | if (c == '\\') { |
136 | arg_ptr[arg_len++] = '\\'; | 142 | arg_ptr[arg_len++] = '\\'; |
@@ -160,6 +166,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, | |||
160 | argv_count--; | 166 | argv_count--; |
161 | } else if (envp_count) { | 167 | } else if (envp_count) { |
162 | char *cp = strchr(arg_ptr, '='); | 168 | char *cp = strchr(arg_ptr, '='); |
169 | |||
163 | if (cp) { | 170 | if (cp) { |
164 | *cp = '\0'; | 171 | *cp = '\0'; |
165 | if (!tomoyo_envp(arg_ptr, cp + 1, | 172 | if (!tomoyo_envp(arg_ptr, cp + 1, |
@@ -182,6 +189,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, | |||
182 | out: | 189 | out: |
183 | if (result) { | 190 | if (result) { |
184 | int i; | 191 | int i; |
192 | |||
185 | /* Check not-yet-checked entries. */ | 193 | /* Check not-yet-checked entries. */ |
186 | for (i = 0; i < argc; i++) { | 194 | for (i = 0; i < argc; i++) { |
187 | if (checked[i]) | 195 | if (checked[i]) |
@@ -229,6 +237,7 @@ static bool tomoyo_scan_exec_realpath(struct file *file, | |||
229 | { | 237 | { |
230 | bool result; | 238 | bool result; |
231 | struct tomoyo_path_info exe; | 239 | struct tomoyo_path_info exe; |
240 | |||
232 | if (!file) | 241 | if (!file) |
233 | return false; | 242 | return false; |
234 | exe.name = tomoyo_realpath_from_path(&file->f_path); | 243 | exe.name = tomoyo_realpath_from_path(&file->f_path); |
@@ -250,6 +259,7 @@ static bool tomoyo_scan_exec_realpath(struct file *file, | |||
250 | static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) | 259 | static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) |
251 | { | 260 | { |
252 | char *cp = start + strlen(start) - 1; | 261 | char *cp = start + strlen(start) - 1; |
262 | |||
253 | if (cp == start || *start++ != '"' || *cp != '"') | 263 | if (cp == start || *start++ != '"' || *cp != '"') |
254 | return NULL; | 264 | return NULL; |
255 | *cp = '\0'; | 265 | *cp = '\0'; |
@@ -270,6 +280,7 @@ static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, | |||
270 | struct tomoyo_name_union *ptr) | 280 | struct tomoyo_name_union *ptr) |
271 | { | 281 | { |
272 | char *filename = param->data; | 282 | char *filename = param->data; |
283 | |||
273 | if (*filename == '@') | 284 | if (*filename == '@') |
274 | return tomoyo_parse_name_union(param, ptr); | 285 | return tomoyo_parse_name_union(param, ptr); |
275 | ptr->filename = tomoyo_get_dqword(filename); | 286 | ptr->filename = tomoyo_get_dqword(filename); |
@@ -310,6 +321,7 @@ static bool tomoyo_parse_envp(char *left, char *right, | |||
310 | const struct tomoyo_path_info *name; | 321 | const struct tomoyo_path_info *name; |
311 | const struct tomoyo_path_info *value; | 322 | const struct tomoyo_path_info *value; |
312 | char *cp = left + strlen(left) - 1; | 323 | char *cp = left + strlen(left) - 1; |
324 | |||
313 | if (*cp-- != ']' || *cp != '"') | 325 | if (*cp-- != ']' || *cp != '"') |
314 | goto out; | 326 | goto out; |
315 | *cp = '\0'; | 327 | *cp = '\0'; |
@@ -364,6 +376,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | |||
364 | static u8 tomoyo_condition_type(const char *word) | 376 | static u8 tomoyo_condition_type(const char *word) |
365 | { | 377 | { |
366 | u8 i; | 378 | u8 i; |
379 | |||
367 | for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) { | 380 | for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) { |
368 | if (!strcmp(word, tomoyo_condition_keyword[i])) | 381 | if (!strcmp(word, tomoyo_condition_keyword[i])) |
369 | break; | 382 | break; |
@@ -395,6 +408,7 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
395 | { | 408 | { |
396 | struct tomoyo_condition *ptr; | 409 | struct tomoyo_condition *ptr; |
397 | bool found = false; | 410 | bool found = false; |
411 | |||
398 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) { | 412 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) { |
399 | dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); | 413 | dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); |
400 | ptr = NULL; | 414 | ptr = NULL; |
@@ -442,12 +456,14 @@ static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param, | |||
442 | { | 456 | { |
443 | char * const pos = param->data; | 457 | char * const pos = param->data; |
444 | bool flag; | 458 | bool flag; |
459 | |||
445 | if (*pos == '<') { | 460 | if (*pos == '<') { |
446 | e->transit = tomoyo_get_domainname(param); | 461 | e->transit = tomoyo_get_domainname(param); |
447 | goto done; | 462 | goto done; |
448 | } | 463 | } |
449 | { | 464 | { |
450 | char *cp = strchr(pos, ' '); | 465 | char *cp = strchr(pos, ' '); |
466 | |||
451 | if (cp) | 467 | if (cp) |
452 | *cp = '\0'; | 468 | *cp = '\0'; |
453 | flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") || | 469 | flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") || |
@@ -489,6 +505,7 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | |||
489 | tomoyo_get_transit_preference(param, &e); | 505 | tomoyo_get_transit_preference(param, &e); |
490 | char * const end_of_string = start_of_string + strlen(start_of_string); | 506 | char * const end_of_string = start_of_string + strlen(start_of_string); |
491 | char *pos; | 507 | char *pos; |
508 | |||
492 | rerun: | 509 | rerun: |
493 | pos = start_of_string; | 510 | pos = start_of_string; |
494 | while (1) { | 511 | while (1) { |
@@ -498,6 +515,7 @@ rerun: | |||
498 | char *cp; | 515 | char *cp; |
499 | char *right_word; | 516 | char *right_word; |
500 | bool is_not; | 517 | bool is_not; |
518 | |||
501 | if (!*left_word) | 519 | if (!*left_word) |
502 | break; | 520 | break; |
503 | /* | 521 | /* |
@@ -622,8 +640,8 @@ rerun: | |||
622 | } | 640 | } |
623 | store_value: | 641 | store_value: |
624 | if (!condp) { | 642 | if (!condp) { |
625 | dprintk(KERN_WARNING "%u: dry_run left=%u right=%u " | 643 | dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n", |
626 | "match=%u\n", __LINE__, left, right, !is_not); | 644 | __LINE__, left, right, !is_not); |
627 | continue; | 645 | continue; |
628 | } | 646 | } |
629 | condp->left = left; | 647 | condp->left = left; |
@@ -660,6 +678,7 @@ store_value: | |||
660 | envp = (struct tomoyo_envp *) (argv + e.argc); | 678 | envp = (struct tomoyo_envp *) (argv + e.argc); |
661 | { | 679 | { |
662 | bool flag = false; | 680 | bool flag = false; |
681 | |||
663 | for (pos = start_of_string; pos < end_of_string; pos++) { | 682 | for (pos = start_of_string; pos < end_of_string; pos++) { |
664 | if (*pos) | 683 | if (*pos) |
665 | continue; | 684 | continue; |
@@ -698,6 +717,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj) | |||
698 | 717 | ||
699 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { | 718 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { |
700 | struct inode *inode; | 719 | struct inode *inode; |
720 | |||
701 | switch (i) { | 721 | switch (i) { |
702 | case TOMOYO_PATH1: | 722 | case TOMOYO_PATH1: |
703 | dentry = obj->path1.dentry; | 723 | dentry = obj->path1.dentry; |
@@ -718,6 +738,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj) | |||
718 | inode = d_backing_inode(dentry); | 738 | inode = d_backing_inode(dentry); |
719 | if (inode) { | 739 | if (inode) { |
720 | struct tomoyo_mini_stat *stat = &obj->stat[i]; | 740 | struct tomoyo_mini_stat *stat = &obj->stat[i]; |
741 | |||
721 | stat->uid = inode->i_uid; | 742 | stat->uid = inode->i_uid; |
722 | stat->gid = inode->i_gid; | 743 | stat->gid = inode->i_gid; |
723 | stat->ino = inode->i_ino; | 744 | stat->ino = inode->i_ino; |
@@ -726,8 +747,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj) | |||
726 | stat->rdev = inode->i_rdev; | 747 | stat->rdev = inode->i_rdev; |
727 | obj->stat_valid[i] = true; | 748 | obj->stat_valid[i] = true; |
728 | } | 749 | } |
729 | if (i & 1) /* i == TOMOYO_PATH1_PARENT || | 750 | if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */ |
730 | i == TOMOYO_PATH2_PARENT */ | ||
731 | dput(dentry); | 751 | dput(dentry); |
732 | } | 752 | } |
733 | } | 753 | } |
@@ -758,6 +778,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
758 | u16 argc; | 778 | u16 argc; |
759 | u16 envc; | 779 | u16 envc; |
760 | struct linux_binprm *bprm = NULL; | 780 | struct linux_binprm *bprm = NULL; |
781 | |||
761 | if (!cond) | 782 | if (!cond) |
762 | return true; | 783 | return true; |
763 | condc = cond->condc; | 784 | condc = cond->condc; |
@@ -780,6 +801,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
780 | const u8 right = condp->right; | 801 | const u8 right = condp->right; |
781 | bool is_bitop[2] = { false, false }; | 802 | bool is_bitop[2] = { false, false }; |
782 | u8 j; | 803 | u8 j; |
804 | |||
783 | condp++; | 805 | condp++; |
784 | /* Check argv[] and envp[] later. */ | 806 | /* Check argv[] and envp[] later. */ |
785 | if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY) | 807 | if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY) |
@@ -787,10 +809,11 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
787 | /* Check string expressions. */ | 809 | /* Check string expressions. */ |
788 | if (right == TOMOYO_NAME_UNION) { | 810 | if (right == TOMOYO_NAME_UNION) { |
789 | const struct tomoyo_name_union *ptr = names_p++; | 811 | const struct tomoyo_name_union *ptr = names_p++; |
812 | struct tomoyo_path_info *symlink; | ||
813 | struct tomoyo_execve *ee; | ||
814 | struct file *file; | ||
815 | |||
790 | switch (left) { | 816 | switch (left) { |
791 | struct tomoyo_path_info *symlink; | ||
792 | struct tomoyo_execve *ee; | ||
793 | struct file *file; | ||
794 | case TOMOYO_SYMLINK_TARGET: | 817 | case TOMOYO_SYMLINK_TARGET: |
795 | symlink = obj ? obj->symlink_target : NULL; | 818 | symlink = obj ? obj->symlink_target : NULL; |
796 | if (!symlink || | 819 | if (!symlink || |
@@ -812,6 +835,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
812 | for (j = 0; j < 2; j++) { | 835 | for (j = 0; j < 2; j++) { |
813 | const u8 index = j ? right : left; | 836 | const u8 index = j ? right : left; |
814 | unsigned long value = 0; | 837 | unsigned long value = 0; |
838 | |||
815 | switch (index) { | 839 | switch (index) { |
816 | case TOMOYO_TASK_UID: | 840 | case TOMOYO_TASK_UID: |
817 | value = from_kuid(&init_user_ns, current_uid()); | 841 | value = from_kuid(&init_user_ns, current_uid()); |
@@ -874,31 +898,31 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
874 | value = S_ISVTX; | 898 | value = S_ISVTX; |
875 | break; | 899 | break; |
876 | case TOMOYO_MODE_OWNER_READ: | 900 | case TOMOYO_MODE_OWNER_READ: |
877 | value = S_IRUSR; | 901 | value = 0400; |
878 | break; | 902 | break; |
879 | case TOMOYO_MODE_OWNER_WRITE: | 903 | case TOMOYO_MODE_OWNER_WRITE: |
880 | value = S_IWUSR; | 904 | value = 0200; |
881 | break; | 905 | break; |
882 | case TOMOYO_MODE_OWNER_EXECUTE: | 906 | case TOMOYO_MODE_OWNER_EXECUTE: |
883 | value = S_IXUSR; | 907 | value = 0100; |
884 | break; | 908 | break; |
885 | case TOMOYO_MODE_GROUP_READ: | 909 | case TOMOYO_MODE_GROUP_READ: |
886 | value = S_IRGRP; | 910 | value = 0040; |
887 | break; | 911 | break; |
888 | case TOMOYO_MODE_GROUP_WRITE: | 912 | case TOMOYO_MODE_GROUP_WRITE: |
889 | value = S_IWGRP; | 913 | value = 0020; |
890 | break; | 914 | break; |
891 | case TOMOYO_MODE_GROUP_EXECUTE: | 915 | case TOMOYO_MODE_GROUP_EXECUTE: |
892 | value = S_IXGRP; | 916 | value = 0010; |
893 | break; | 917 | break; |
894 | case TOMOYO_MODE_OTHERS_READ: | 918 | case TOMOYO_MODE_OTHERS_READ: |
895 | value = S_IROTH; | 919 | value = 0004; |
896 | break; | 920 | break; |
897 | case TOMOYO_MODE_OTHERS_WRITE: | 921 | case TOMOYO_MODE_OTHERS_WRITE: |
898 | value = S_IWOTH; | 922 | value = 0002; |
899 | break; | 923 | break; |
900 | case TOMOYO_MODE_OTHERS_EXECUTE: | 924 | case TOMOYO_MODE_OTHERS_EXECUTE: |
901 | value = S_IXOTH; | 925 | value = 0001; |
902 | break; | 926 | break; |
903 | case TOMOYO_EXEC_ARGC: | 927 | case TOMOYO_EXEC_ARGC: |
904 | if (!bprm) | 928 | if (!bprm) |
@@ -923,6 +947,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
923 | { | 947 | { |
924 | u8 stat_index; | 948 | u8 stat_index; |
925 | struct tomoyo_mini_stat *stat; | 949 | struct tomoyo_mini_stat *stat; |
950 | |||
926 | switch (index) { | 951 | switch (index) { |
927 | case TOMOYO_PATH1_UID: | 952 | case TOMOYO_PATH1_UID: |
928 | case TOMOYO_PATH1_GID: | 953 | case TOMOYO_PATH1_GID: |
@@ -1036,12 +1061,14 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
1036 | if (left == TOMOYO_NUMBER_UNION) { | 1061 | if (left == TOMOYO_NUMBER_UNION) { |
1037 | /* Fetch values now. */ | 1062 | /* Fetch values now. */ |
1038 | const struct tomoyo_number_union *ptr = numbers_p++; | 1063 | const struct tomoyo_number_union *ptr = numbers_p++; |
1064 | |||
1039 | min_v[0] = ptr->values[0]; | 1065 | min_v[0] = ptr->values[0]; |
1040 | max_v[0] = ptr->values[1]; | 1066 | max_v[0] = ptr->values[1]; |
1041 | } | 1067 | } |
1042 | if (right == TOMOYO_NUMBER_UNION) { | 1068 | if (right == TOMOYO_NUMBER_UNION) { |
1043 | /* Fetch values now. */ | 1069 | /* Fetch values now. */ |
1044 | const struct tomoyo_number_union *ptr = numbers_p++; | 1070 | const struct tomoyo_number_union *ptr = numbers_p++; |
1071 | |||
1045 | if (ptr->group) { | 1072 | if (ptr->group) { |
1046 | if (tomoyo_number_matches_group(min_v[0], | 1073 | if (tomoyo_number_matches_group(min_v[0], |
1047 | max_v[0], | 1074 | max_v[0], |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index f6758dad981f..8526a0a74023 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -30,10 +30,10 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
30 | */ | 30 | */ |
31 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | 31 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
32 | struct tomoyo_acl_param *param, | 32 | struct tomoyo_acl_param *param, |
33 | bool (*check_duplicate) (const struct tomoyo_acl_head | 33 | bool (*check_duplicate)(const struct tomoyo_acl_head |
34 | *, | 34 | *, |
35 | const struct tomoyo_acl_head | 35 | const struct tomoyo_acl_head |
36 | *)) | 36 | *)) |
37 | { | 37 | { |
38 | int error = param->is_delete ? -ENOENT : -ENOMEM; | 38 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
39 | struct tomoyo_acl_head *entry; | 39 | struct tomoyo_acl_head *entry; |
@@ -90,13 +90,13 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, | |||
90 | */ | 90 | */ |
91 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 91 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
92 | struct tomoyo_acl_param *param, | 92 | struct tomoyo_acl_param *param, |
93 | bool (*check_duplicate) (const struct tomoyo_acl_info | 93 | bool (*check_duplicate)(const struct tomoyo_acl_info |
94 | *, | 94 | *, |
95 | const struct tomoyo_acl_info | 95 | const struct tomoyo_acl_info |
96 | *), | 96 | *), |
97 | bool (*merge_duplicate) (struct tomoyo_acl_info *, | 97 | bool (*merge_duplicate)(struct tomoyo_acl_info *, |
98 | struct tomoyo_acl_info *, | 98 | struct tomoyo_acl_info *, |
99 | const bool)) | 99 | const bool)) |
100 | { | 100 | { |
101 | const bool is_delete = param->is_delete; | 101 | const bool is_delete = param->is_delete; |
102 | int error = is_delete ? -ENOENT : -ENOMEM; | 102 | int error = is_delete ? -ENOENT : -ENOMEM; |
@@ -157,13 +157,13 @@ out: | |||
157 | * Caller holds tomoyo_read_lock(). | 157 | * Caller holds tomoyo_read_lock(). |
158 | */ | 158 | */ |
159 | void tomoyo_check_acl(struct tomoyo_request_info *r, | 159 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
160 | bool (*check_entry) (struct tomoyo_request_info *, | 160 | bool (*check_entry)(struct tomoyo_request_info *, |
161 | const struct tomoyo_acl_info *)) | 161 | const struct tomoyo_acl_info *)) |
162 | { | 162 | { |
163 | const struct tomoyo_domain_info *domain = r->domain; | 163 | const struct tomoyo_domain_info *domain = r->domain; |
164 | struct tomoyo_acl_info *ptr; | 164 | struct tomoyo_acl_info *ptr; |
165 | bool retried = false; | ||
166 | const struct list_head *list = &domain->acl_info_list; | 165 | const struct list_head *list = &domain->acl_info_list; |
166 | u16 i = 0; | ||
167 | 167 | ||
168 | retry: | 168 | retry: |
169 | list_for_each_entry_rcu(ptr, list, list) { | 169 | list_for_each_entry_rcu(ptr, list, list) { |
@@ -177,9 +177,10 @@ retry: | |||
177 | r->granted = true; | 177 | r->granted = true; |
178 | return; | 178 | return; |
179 | } | 179 | } |
180 | if (!retried) { | 180 | for (; i < TOMOYO_MAX_ACL_GROUPS; i++) { |
181 | retried = true; | 181 | if (!test_bit(i, domain->group)) |
182 | list = &domain->ns->acl_group[domain->group]; | 182 | continue; |
183 | list = &domain->ns->acl_group[i++]; | ||
183 | goto retry; | 184 | goto retry; |
184 | } | 185 | } |
185 | r->granted = false; | 186 | r->granted = false; |
@@ -198,6 +199,7 @@ LIST_HEAD(tomoyo_domain_list); | |||
198 | static const char *tomoyo_last_word(const char *name) | 199 | static const char *tomoyo_last_word(const char *name) |
199 | { | 200 | { |
200 | const char *cp = strrchr(name, ' '); | 201 | const char *cp = strrchr(name, ' '); |
202 | |||
201 | if (cp) | 203 | if (cp) |
202 | return cp + 1; | 204 | return cp + 1; |
203 | return name; | 205 | return name; |
@@ -220,6 +222,7 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, | |||
220 | const struct tomoyo_transition_control *p2 = container_of(b, | 222 | const struct tomoyo_transition_control *p2 = container_of(b, |
221 | typeof(*p2), | 223 | typeof(*p2), |
222 | head); | 224 | head); |
225 | |||
223 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name | 226 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name |
224 | && p1->domainname == p2->domainname | 227 | && p1->domainname == p2->domainname |
225 | && p1->program == p2->program; | 228 | && p1->program == p2->program; |
@@ -240,6 +243,7 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param, | |||
240 | int error = param->is_delete ? -ENOENT : -ENOMEM; | 243 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
241 | char *program = param->data; | 244 | char *program = param->data; |
242 | char *domainname = strstr(program, " from "); | 245 | char *domainname = strstr(program, " from "); |
246 | |||
243 | if (domainname) { | 247 | if (domainname) { |
244 | *domainname = '\0'; | 248 | *domainname = '\0'; |
245 | domainname += 6; | 249 | domainname += 6; |
@@ -293,6 +297,7 @@ static inline bool tomoyo_scan_transition | |||
293 | const enum tomoyo_transition_type type) | 297 | const enum tomoyo_transition_type type) |
294 | { | 298 | { |
295 | const struct tomoyo_transition_control *ptr; | 299 | const struct tomoyo_transition_control *ptr; |
300 | |||
296 | list_for_each_entry_rcu(ptr, list, head.list) { | 301 | list_for_each_entry_rcu(ptr, list, head.list) { |
297 | if (ptr->head.is_deleted || ptr->type != type) | 302 | if (ptr->head.is_deleted || ptr->type != type) |
298 | continue; | 303 | continue; |
@@ -338,9 +343,11 @@ static enum tomoyo_transition_type tomoyo_transition_type | |||
338 | { | 343 | { |
339 | const char *last_name = tomoyo_last_word(domainname->name); | 344 | const char *last_name = tomoyo_last_word(domainname->name); |
340 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; | 345 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; |
346 | |||
341 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { | 347 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { |
342 | const struct list_head * const list = | 348 | const struct list_head * const list = |
343 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; | 349 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
350 | |||
344 | if (!tomoyo_scan_transition(list, domainname, program, | 351 | if (!tomoyo_scan_transition(list, domainname, program, |
345 | last_name, type)) { | 352 | last_name, type)) { |
346 | type++; | 353 | type++; |
@@ -375,6 +382,7 @@ static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, | |||
375 | head); | 382 | head); |
376 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), | 383 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), |
377 | head); | 384 | head); |
385 | |||
378 | return p1->original_name == p2->original_name && | 386 | return p1->original_name == p2->original_name && |
379 | p1->aggregated_name == p2->aggregated_name; | 387 | p1->aggregated_name == p2->aggregated_name; |
380 | } | 388 | } |
@@ -394,6 +402,7 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param) | |||
394 | int error = param->is_delete ? -ENOENT : -ENOMEM; | 402 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
395 | const char *original_name = tomoyo_read_token(param); | 403 | const char *original_name = tomoyo_read_token(param); |
396 | const char *aggregated_name = tomoyo_read_token(param); | 404 | const char *aggregated_name = tomoyo_read_token(param); |
405 | |||
397 | if (!tomoyo_correct_word(original_name) || | 406 | if (!tomoyo_correct_word(original_name) || |
398 | !tomoyo_correct_path(aggregated_name)) | 407 | !tomoyo_correct_path(aggregated_name)) |
399 | return -EINVAL; | 408 | return -EINVAL; |
@@ -426,6 +435,7 @@ static struct tomoyo_policy_namespace *tomoyo_find_namespace | |||
426 | (const char *name, const unsigned int len) | 435 | (const char *name, const unsigned int len) |
427 | { | 436 | { |
428 | struct tomoyo_policy_namespace *ns; | 437 | struct tomoyo_policy_namespace *ns; |
438 | |||
429 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { | 439 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
430 | if (strncmp(name, ns->name, len) || | 440 | if (strncmp(name, ns->name, len) || |
431 | (name[len] && name[len] != ' ')) | 441 | (name[len] && name[len] != ' ')) |
@@ -451,6 +461,7 @@ struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) | |||
451 | struct tomoyo_policy_namespace *entry; | 461 | struct tomoyo_policy_namespace *entry; |
452 | const char *cp = domainname; | 462 | const char *cp = domainname; |
453 | unsigned int len = 0; | 463 | unsigned int len = 0; |
464 | |||
454 | while (*cp && *cp++ != ' ') | 465 | while (*cp && *cp++ != ' ') |
455 | len++; | 466 | len++; |
456 | ptr = tomoyo_find_namespace(domainname, len); | 467 | ptr = tomoyo_find_namespace(domainname, len); |
@@ -466,6 +477,7 @@ struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) | |||
466 | ptr = tomoyo_find_namespace(domainname, len); | 477 | ptr = tomoyo_find_namespace(domainname, len); |
467 | if (!ptr && tomoyo_memory_ok(entry)) { | 478 | if (!ptr && tomoyo_memory_ok(entry)) { |
468 | char *name = (char *) (entry + 1); | 479 | char *name = (char *) (entry + 1); |
480 | |||
469 | ptr = entry; | 481 | ptr = entry; |
470 | memmove(name, domainname, len); | 482 | memmove(name, domainname, len); |
471 | name[len] = '\0'; | 483 | name[len] = '\0'; |
@@ -490,6 +502,7 @@ static bool tomoyo_namespace_jump(const char *domainname) | |||
490 | { | 502 | { |
491 | const char *namespace = tomoyo_current_namespace()->name; | 503 | const char *namespace = tomoyo_current_namespace()->name; |
492 | const int len = strlen(namespace); | 504 | const int len = strlen(namespace); |
505 | |||
493 | return strncmp(domainname, namespace, len) || | 506 | return strncmp(domainname, namespace, len) || |
494 | (domainname[len] && domainname[len] != ' '); | 507 | (domainname[len] && domainname[len] != ' '); |
495 | } | 508 | } |
@@ -510,6 +523,7 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | |||
510 | struct tomoyo_domain_info e = { }; | 523 | struct tomoyo_domain_info e = { }; |
511 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); | 524 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); |
512 | bool created = false; | 525 | bool created = false; |
526 | |||
513 | if (entry) { | 527 | if (entry) { |
514 | if (transit) { | 528 | if (transit) { |
515 | /* | 529 | /* |
@@ -546,8 +560,9 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | |||
546 | */ | 560 | */ |
547 | if (transit) { | 561 | if (transit) { |
548 | const struct tomoyo_domain_info *domain = tomoyo_domain(); | 562 | const struct tomoyo_domain_info *domain = tomoyo_domain(); |
563 | |||
549 | e.profile = domain->profile; | 564 | e.profile = domain->profile; |
550 | e.group = domain->group; | 565 | memcpy(e.group, domain->group, sizeof(e.group)); |
551 | } | 566 | } |
552 | e.domainname = tomoyo_get_name(domainname); | 567 | e.domainname = tomoyo_get_name(domainname); |
553 | if (!e.domainname) | 568 | if (!e.domainname) |
@@ -569,12 +584,17 @@ out: | |||
569 | if (entry && transit) { | 584 | if (entry && transit) { |
570 | if (created) { | 585 | if (created) { |
571 | struct tomoyo_request_info r; | 586 | struct tomoyo_request_info r; |
587 | int i; | ||
588 | |||
572 | tomoyo_init_request_info(&r, entry, | 589 | tomoyo_init_request_info(&r, entry, |
573 | TOMOYO_MAC_FILE_EXECUTE); | 590 | TOMOYO_MAC_FILE_EXECUTE); |
574 | r.granted = false; | 591 | r.granted = false; |
575 | tomoyo_write_log(&r, "use_profile %u\n", | 592 | tomoyo_write_log(&r, "use_profile %u\n", |
576 | entry->profile); | 593 | entry->profile); |
577 | tomoyo_write_log(&r, "use_group %u\n", entry->group); | 594 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) |
595 | if (test_bit(i, entry->group)) | ||
596 | tomoyo_write_log(&r, "use_group %u\n", | ||
597 | i); | ||
578 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | 598 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); |
579 | } | 599 | } |
580 | } | 600 | } |
@@ -712,6 +732,7 @@ retry: | |||
712 | struct tomoyo_aggregator *ptr; | 732 | struct tomoyo_aggregator *ptr; |
713 | struct list_head *list = | 733 | struct list_head *list = |
714 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; | 734 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
735 | |||
715 | /* Check 'aggregator' directive. */ | 736 | /* Check 'aggregator' directive. */ |
716 | candidate = &exename; | 737 | candidate = &exename; |
717 | list_for_each_entry_rcu(ptr, list, head.list) { | 738 | list_for_each_entry_rcu(ptr, list, head.list) { |
@@ -747,6 +768,7 @@ retry: | |||
747 | */ | 768 | */ |
748 | if (ee->transition) { | 769 | if (ee->transition) { |
749 | const char *domainname = ee->transition->name; | 770 | const char *domainname = ee->transition->name; |
771 | |||
750 | reject_on_transition_failure = true; | 772 | reject_on_transition_failure = true; |
751 | if (!strcmp(domainname, "keep")) | 773 | if (!strcmp(domainname, "keep")) |
752 | goto force_keep_domain; | 774 | goto force_keep_domain; |
@@ -758,6 +780,7 @@ retry: | |||
758 | goto force_initialize_domain; | 780 | goto force_initialize_domain; |
759 | if (!strcmp(domainname, "parent")) { | 781 | if (!strcmp(domainname, "parent")) { |
760 | char *cp; | 782 | char *cp; |
783 | |||
761 | strncpy(ee->tmp, old_domain->domainname->name, | 784 | strncpy(ee->tmp, old_domain->domainname->name, |
762 | TOMOYO_EXEC_TMPSIZE - 1); | 785 | TOMOYO_EXEC_TMPSIZE - 1); |
763 | cp = strrchr(ee->tmp, ' '); | 786 | cp = strrchr(ee->tmp, ' '); |
@@ -822,8 +845,7 @@ force_jump_domain: | |||
822 | if (domain) | 845 | if (domain) |
823 | retval = 0; | 846 | retval = 0; |
824 | else if (reject_on_transition_failure) { | 847 | else if (reject_on_transition_failure) { |
825 | printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", | 848 | pr_warn("ERROR: Domain '%s' not ready.\n", ee->tmp); |
826 | ee->tmp); | ||
827 | retval = -ENOMEM; | 849 | retval = -ENOMEM; |
828 | } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) | 850 | } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) |
829 | retval = -ENOMEM; | 851 | retval = -ENOMEM; |
@@ -834,16 +856,20 @@ force_jump_domain: | |||
834 | ee->r.granted = false; | 856 | ee->r.granted = false; |
835 | tomoyo_write_log(&ee->r, "%s", tomoyo_dif | 857 | tomoyo_write_log(&ee->r, "%s", tomoyo_dif |
836 | [TOMOYO_DIF_TRANSITION_FAILED]); | 858 | [TOMOYO_DIF_TRANSITION_FAILED]); |
837 | printk(KERN_WARNING | 859 | pr_warn("ERROR: Domain '%s' not defined.\n", ee->tmp); |
838 | "ERROR: Domain '%s' not defined.\n", ee->tmp); | ||
839 | } | 860 | } |
840 | } | 861 | } |
841 | out: | 862 | out: |
842 | if (!domain) | 863 | if (!domain) |
843 | domain = old_domain; | 864 | domain = old_domain; |
844 | /* Update reference count on "struct tomoyo_domain_info". */ | 865 | /* Update reference count on "struct tomoyo_domain_info". */ |
845 | atomic_inc(&domain->users); | 866 | { |
846 | bprm->cred->security = domain; | 867 | struct tomoyo_task *s = tomoyo_task(current); |
868 | |||
869 | s->old_domain_info = s->domain_info; | ||
870 | s->domain_info = domain; | ||
871 | atomic_inc(&domain->users); | ||
872 | } | ||
847 | kfree(exename.name); | 873 | kfree(exename.name); |
848 | if (!retval) { | 874 | if (!retval) { |
849 | ee->r.domain = domain; | 875 | ee->r.domain = domain; |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 2a374b4da8f5..86f7d1b90212 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -214,6 +214,7 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) | |||
214 | const u8 type = r->param.path_number.operation; | 214 | const u8 type = r->param.path_number.operation; |
215 | u8 radix; | 215 | u8 radix; |
216 | char buffer[64]; | 216 | char buffer[64]; |
217 | |||
217 | switch (type) { | 218 | switch (type) { |
218 | case TOMOYO_TYPE_CREATE: | 219 | case TOMOYO_TYPE_CREATE: |
219 | case TOMOYO_TYPE_MKDIR: | 220 | case TOMOYO_TYPE_MKDIR: |
@@ -253,6 +254,7 @@ static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, | |||
253 | { | 254 | { |
254 | const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), | 255 | const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), |
255 | head); | 256 | head); |
257 | |||
256 | if (acl->perm & (1 << r->param.path.operation)) { | 258 | if (acl->perm & (1 << r->param.path.operation)) { |
257 | r->param.path.matched_path = | 259 | r->param.path.matched_path = |
258 | tomoyo_compare_name_union(r->param.path.filename, | 260 | tomoyo_compare_name_union(r->param.path.filename, |
@@ -275,6 +277,7 @@ static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, | |||
275 | { | 277 | { |
276 | const struct tomoyo_path_number_acl *acl = | 278 | const struct tomoyo_path_number_acl *acl = |
277 | container_of(ptr, typeof(*acl), head); | 279 | container_of(ptr, typeof(*acl), head); |
280 | |||
278 | return (acl->perm & (1 << r->param.path_number.operation)) && | 281 | return (acl->perm & (1 << r->param.path_number.operation)) && |
279 | tomoyo_compare_number_union(r->param.path_number.number, | 282 | tomoyo_compare_number_union(r->param.path_number.number, |
280 | &acl->number) && | 283 | &acl->number) && |
@@ -295,6 +298,7 @@ static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, | |||
295 | { | 298 | { |
296 | const struct tomoyo_path2_acl *acl = | 299 | const struct tomoyo_path2_acl *acl = |
297 | container_of(ptr, typeof(*acl), head); | 300 | container_of(ptr, typeof(*acl), head); |
301 | |||
298 | return (acl->perm & (1 << r->param.path2.operation)) && | 302 | return (acl->perm & (1 << r->param.path2.operation)) && |
299 | tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) | 303 | tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) |
300 | && tomoyo_compare_name_union(r->param.path2.filename2, | 304 | && tomoyo_compare_name_union(r->param.path2.filename2, |
@@ -314,6 +318,7 @@ static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, | |||
314 | { | 318 | { |
315 | const struct tomoyo_mkdev_acl *acl = | 319 | const struct tomoyo_mkdev_acl *acl = |
316 | container_of(ptr, typeof(*acl), head); | 320 | container_of(ptr, typeof(*acl), head); |
321 | |||
317 | return (acl->perm & (1 << r->param.mkdev.operation)) && | 322 | return (acl->perm & (1 << r->param.mkdev.operation)) && |
318 | tomoyo_compare_number_union(r->param.mkdev.mode, | 323 | tomoyo_compare_number_union(r->param.mkdev.mode, |
319 | &acl->mode) && | 324 | &acl->mode) && |
@@ -338,6 +343,7 @@ static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, | |||
338 | { | 343 | { |
339 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); | 344 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); |
340 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); | 345 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); |
346 | |||
341 | return tomoyo_same_name_union(&p1->name, &p2->name); | 347 | return tomoyo_same_name_union(&p1->name, &p2->name); |
342 | } | 348 | } |
343 | 349 | ||
@@ -358,6 +364,7 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | |||
358 | ->perm; | 364 | ->perm; |
359 | u16 perm = *a_perm; | 365 | u16 perm = *a_perm; |
360 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; | 366 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; |
367 | |||
361 | if (is_delete) | 368 | if (is_delete) |
362 | perm &= ~b_perm; | 369 | perm &= ~b_perm; |
363 | else | 370 | else |
@@ -384,6 +391,7 @@ static int tomoyo_update_path_acl(const u16 perm, | |||
384 | .perm = perm | 391 | .perm = perm |
385 | }; | 392 | }; |
386 | int error; | 393 | int error; |
394 | |||
387 | if (!tomoyo_parse_name_union(param, &e.name)) | 395 | if (!tomoyo_parse_name_union(param, &e.name)) |
388 | error = -EINVAL; | 396 | error = -EINVAL; |
389 | else | 397 | else |
@@ -407,6 +415,7 @@ static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, | |||
407 | { | 415 | { |
408 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); | 416 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); |
409 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); | 417 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); |
418 | |||
410 | return tomoyo_same_name_union(&p1->name, &p2->name) && | 419 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
411 | tomoyo_same_number_union(&p1->mode, &p2->mode) && | 420 | tomoyo_same_number_union(&p1->mode, &p2->mode) && |
412 | tomoyo_same_number_union(&p1->major, &p2->major) && | 421 | tomoyo_same_number_union(&p1->major, &p2->major) && |
@@ -431,6 +440,7 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, | |||
431 | u8 perm = *a_perm; | 440 | u8 perm = *a_perm; |
432 | const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) | 441 | const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) |
433 | ->perm; | 442 | ->perm; |
443 | |||
434 | if (is_delete) | 444 | if (is_delete) |
435 | perm &= ~b_perm; | 445 | perm &= ~b_perm; |
436 | else | 446 | else |
@@ -457,6 +467,7 @@ static int tomoyo_update_mkdev_acl(const u8 perm, | |||
457 | .perm = perm | 467 | .perm = perm |
458 | }; | 468 | }; |
459 | int error; | 469 | int error; |
470 | |||
460 | if (!tomoyo_parse_name_union(param, &e.name) || | 471 | if (!tomoyo_parse_name_union(param, &e.name) || |
461 | !tomoyo_parse_number_union(param, &e.mode) || | 472 | !tomoyo_parse_number_union(param, &e.mode) || |
462 | !tomoyo_parse_number_union(param, &e.major) || | 473 | !tomoyo_parse_number_union(param, &e.major) || |
@@ -486,6 +497,7 @@ static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, | |||
486 | { | 497 | { |
487 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); | 498 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); |
488 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); | 499 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); |
500 | |||
489 | return tomoyo_same_name_union(&p1->name1, &p2->name1) && | 501 | return tomoyo_same_name_union(&p1->name1, &p2->name1) && |
490 | tomoyo_same_name_union(&p1->name2, &p2->name2); | 502 | tomoyo_same_name_union(&p1->name2, &p2->name2); |
491 | } | 503 | } |
@@ -507,6 +519,7 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, | |||
507 | ->perm; | 519 | ->perm; |
508 | u8 perm = *a_perm; | 520 | u8 perm = *a_perm; |
509 | const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; | 521 | const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; |
522 | |||
510 | if (is_delete) | 523 | if (is_delete) |
511 | perm &= ~b_perm; | 524 | perm &= ~b_perm; |
512 | else | 525 | else |
@@ -533,6 +546,7 @@ static int tomoyo_update_path2_acl(const u8 perm, | |||
533 | .perm = perm | 546 | .perm = perm |
534 | }; | 547 | }; |
535 | int error; | 548 | int error; |
549 | |||
536 | if (!tomoyo_parse_name_union(param, &e.name1) || | 550 | if (!tomoyo_parse_name_union(param, &e.name1) || |
537 | !tomoyo_parse_name_union(param, &e.name2)) | 551 | !tomoyo_parse_name_union(param, &e.name2)) |
538 | error = -EINVAL; | 552 | error = -EINVAL; |
@@ -621,6 +635,7 @@ static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, | |||
621 | head); | 635 | head); |
622 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), | 636 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), |
623 | head); | 637 | head); |
638 | |||
624 | return tomoyo_same_name_union(&p1->name, &p2->name) && | 639 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
625 | tomoyo_same_number_union(&p1->number, &p2->number); | 640 | tomoyo_same_number_union(&p1->number, &p2->number); |
626 | } | 641 | } |
@@ -643,6 +658,7 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, | |||
643 | u8 perm = *a_perm; | 658 | u8 perm = *a_perm; |
644 | const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) | 659 | const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) |
645 | ->perm; | 660 | ->perm; |
661 | |||
646 | if (is_delete) | 662 | if (is_delete) |
647 | perm &= ~b_perm; | 663 | perm &= ~b_perm; |
648 | else | 664 | else |
@@ -667,6 +683,7 @@ static int tomoyo_update_path_number_acl(const u8 perm, | |||
667 | .perm = perm | 683 | .perm = perm |
668 | }; | 684 | }; |
669 | int error; | 685 | int error; |
686 | |||
670 | if (!tomoyo_parse_name_union(param, &e.name) || | 687 | if (!tomoyo_parse_name_union(param, &e.name) || |
671 | !tomoyo_parse_number_union(param, &e.number)) | 688 | !tomoyo_parse_number_union(param, &e.number)) |
672 | error = -EINVAL; | 689 | error = -EINVAL; |
@@ -947,6 +964,7 @@ static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, | |||
947 | { | 964 | { |
948 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); | 965 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); |
949 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); | 966 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); |
967 | |||
950 | return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && | 968 | return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && |
951 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && | 969 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && |
952 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && | 970 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && |
@@ -966,6 +984,7 @@ static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) | |||
966 | { | 984 | { |
967 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; | 985 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; |
968 | int error; | 986 | int error; |
987 | |||
969 | if (!tomoyo_parse_name_union(param, &e.dev_name) || | 988 | if (!tomoyo_parse_name_union(param, &e.dev_name) || |
970 | !tomoyo_parse_name_union(param, &e.dir_name) || | 989 | !tomoyo_parse_name_union(param, &e.dir_name) || |
971 | !tomoyo_parse_name_union(param, &e.fs_type) || | 990 | !tomoyo_parse_name_union(param, &e.fs_type) || |
@@ -995,6 +1014,7 @@ int tomoyo_write_file(struct tomoyo_acl_param *param) | |||
995 | u16 perm = 0; | 1014 | u16 perm = 0; |
996 | u8 type; | 1015 | u8 type; |
997 | const char *operation = tomoyo_read_token(param); | 1016 | const char *operation = tomoyo_read_token(param); |
1017 | |||
998 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) | 1018 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) |
999 | if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) | 1019 | if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) |
1000 | perm |= 1 << type; | 1020 | perm |= 1 << type; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index e22bea811c57..9537832fca18 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -77,11 +77,13 @@ static bool tomoyo_name_used_by_io_buffer(const char *string) | |||
77 | spin_lock(&tomoyo_io_buffer_list_lock); | 77 | spin_lock(&tomoyo_io_buffer_list_lock); |
78 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | 78 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { |
79 | int i; | 79 | int i; |
80 | |||
80 | head->users++; | 81 | head->users++; |
81 | spin_unlock(&tomoyo_io_buffer_list_lock); | 82 | spin_unlock(&tomoyo_io_buffer_list_lock); |
82 | mutex_lock(&head->io_sem); | 83 | mutex_lock(&head->io_sem); |
83 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { | 84 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { |
84 | const char *w = head->r.w[i]; | 85 | const char *w = head->r.w[i]; |
86 | |||
85 | if (w < string || w > string + size) | 87 | if (w < string || w > string + size) |
86 | continue; | 88 | continue; |
87 | in_use = true; | 89 | in_use = true; |
@@ -108,6 +110,7 @@ static inline void tomoyo_del_transition_control(struct list_head *element) | |||
108 | { | 110 | { |
109 | struct tomoyo_transition_control *ptr = | 111 | struct tomoyo_transition_control *ptr = |
110 | container_of(element, typeof(*ptr), head.list); | 112 | container_of(element, typeof(*ptr), head.list); |
113 | |||
111 | tomoyo_put_name(ptr->domainname); | 114 | tomoyo_put_name(ptr->domainname); |
112 | tomoyo_put_name(ptr->program); | 115 | tomoyo_put_name(ptr->program); |
113 | } | 116 | } |
@@ -123,6 +126,7 @@ static inline void tomoyo_del_aggregator(struct list_head *element) | |||
123 | { | 126 | { |
124 | struct tomoyo_aggregator *ptr = | 127 | struct tomoyo_aggregator *ptr = |
125 | container_of(element, typeof(*ptr), head.list); | 128 | container_of(element, typeof(*ptr), head.list); |
129 | |||
126 | tomoyo_put_name(ptr->original_name); | 130 | tomoyo_put_name(ptr->original_name); |
127 | tomoyo_put_name(ptr->aggregated_name); | 131 | tomoyo_put_name(ptr->aggregated_name); |
128 | } | 132 | } |
@@ -138,6 +142,7 @@ static inline void tomoyo_del_manager(struct list_head *element) | |||
138 | { | 142 | { |
139 | struct tomoyo_manager *ptr = | 143 | struct tomoyo_manager *ptr = |
140 | container_of(element, typeof(*ptr), head.list); | 144 | container_of(element, typeof(*ptr), head.list); |
145 | |||
141 | tomoyo_put_name(ptr->manager); | 146 | tomoyo_put_name(ptr->manager); |
142 | } | 147 | } |
143 | 148 | ||
@@ -152,6 +157,7 @@ static void tomoyo_del_acl(struct list_head *element) | |||
152 | { | 157 | { |
153 | struct tomoyo_acl_info *acl = | 158 | struct tomoyo_acl_info *acl = |
154 | container_of(element, typeof(*acl), list); | 159 | container_of(element, typeof(*acl), list); |
160 | |||
155 | tomoyo_put_condition(acl->cond); | 161 | tomoyo_put_condition(acl->cond); |
156 | switch (acl->type) { | 162 | switch (acl->type) { |
157 | case TOMOYO_TYPE_PATH_ACL: | 163 | case TOMOYO_TYPE_PATH_ACL: |
@@ -226,6 +232,7 @@ static void tomoyo_del_acl(struct list_head *element) | |||
226 | { | 232 | { |
227 | struct tomoyo_task_acl *entry = | 233 | struct tomoyo_task_acl *entry = |
228 | container_of(acl, typeof(*entry), head); | 234 | container_of(acl, typeof(*entry), head); |
235 | |||
229 | tomoyo_put_name(entry->domainname); | 236 | tomoyo_put_name(entry->domainname); |
230 | } | 237 | } |
231 | break; | 238 | break; |
@@ -247,6 +254,7 @@ static inline void tomoyo_del_domain(struct list_head *element) | |||
247 | container_of(element, typeof(*domain), list); | 254 | container_of(element, typeof(*domain), list); |
248 | struct tomoyo_acl_info *acl; | 255 | struct tomoyo_acl_info *acl; |
249 | struct tomoyo_acl_info *tmp; | 256 | struct tomoyo_acl_info *tmp; |
257 | |||
250 | /* | 258 | /* |
251 | * Since this domain is referenced from neither | 259 | * Since this domain is referenced from neither |
252 | * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete | 260 | * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete |
@@ -286,6 +294,7 @@ void tomoyo_del_condition(struct list_head *element) | |||
286 | = (const struct tomoyo_argv *) (names_p + names_count); | 294 | = (const struct tomoyo_argv *) (names_p + names_count); |
287 | const struct tomoyo_envp *envp | 295 | const struct tomoyo_envp *envp |
288 | = (const struct tomoyo_envp *) (argv + argc); | 296 | = (const struct tomoyo_envp *) (argv + argc); |
297 | |||
289 | for (i = 0; i < numbers_count; i++) | 298 | for (i = 0; i < numbers_count; i++) |
290 | tomoyo_put_number_union(numbers_p++); | 299 | tomoyo_put_number_union(numbers_p++); |
291 | for (i = 0; i < names_count; i++) | 300 | for (i = 0; i < names_count; i++) |
@@ -321,6 +330,7 @@ static inline void tomoyo_del_path_group(struct list_head *element) | |||
321 | { | 330 | { |
322 | struct tomoyo_path_group *member = | 331 | struct tomoyo_path_group *member = |
323 | container_of(element, typeof(*member), head.list); | 332 | container_of(element, typeof(*member), head.list); |
333 | |||
324 | tomoyo_put_name(member->member_name); | 334 | tomoyo_put_name(member->member_name); |
325 | } | 335 | } |
326 | 336 | ||
@@ -335,6 +345,7 @@ static inline void tomoyo_del_group(struct list_head *element) | |||
335 | { | 345 | { |
336 | struct tomoyo_group *group = | 346 | struct tomoyo_group *group = |
337 | container_of(element, typeof(*group), head.list); | 347 | container_of(element, typeof(*group), head.list); |
348 | |||
338 | tomoyo_put_name(group->group_name); | 349 | tomoyo_put_name(group->group_name); |
339 | } | 350 | } |
340 | 351 | ||
@@ -476,6 +487,7 @@ static void tomoyo_collect_member(const enum tomoyo_policy_id id, | |||
476 | { | 487 | { |
477 | struct tomoyo_acl_head *member; | 488 | struct tomoyo_acl_head *member; |
478 | struct tomoyo_acl_head *tmp; | 489 | struct tomoyo_acl_head *tmp; |
490 | |||
479 | list_for_each_entry_safe(member, tmp, member_list, list) { | 491 | list_for_each_entry_safe(member, tmp, member_list, list) { |
480 | if (!member->is_deleted) | 492 | if (!member->is_deleted) |
481 | continue; | 493 | continue; |
@@ -495,6 +507,7 @@ static void tomoyo_collect_acl(struct list_head *list) | |||
495 | { | 507 | { |
496 | struct tomoyo_acl_info *acl; | 508 | struct tomoyo_acl_info *acl; |
497 | struct tomoyo_acl_info *tmp; | 509 | struct tomoyo_acl_info *tmp; |
510 | |||
498 | list_for_each_entry_safe(acl, tmp, list, list) { | 511 | list_for_each_entry_safe(acl, tmp, list, list) { |
499 | if (!acl->is_deleted) | 512 | if (!acl->is_deleted) |
500 | continue; | 513 | continue; |
@@ -513,10 +526,12 @@ static void tomoyo_collect_entry(void) | |||
513 | int i; | 526 | int i; |
514 | enum tomoyo_policy_id id; | 527 | enum tomoyo_policy_id id; |
515 | struct tomoyo_policy_namespace *ns; | 528 | struct tomoyo_policy_namespace *ns; |
529 | |||
516 | mutex_lock(&tomoyo_policy_lock); | 530 | mutex_lock(&tomoyo_policy_lock); |
517 | { | 531 | { |
518 | struct tomoyo_domain_info *domain; | 532 | struct tomoyo_domain_info *domain; |
519 | struct tomoyo_domain_info *tmp; | 533 | struct tomoyo_domain_info *tmp; |
534 | |||
520 | list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list, | 535 | list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list, |
521 | list) { | 536 | list) { |
522 | tomoyo_collect_acl(&domain->acl_info_list); | 537 | tomoyo_collect_acl(&domain->acl_info_list); |
@@ -534,6 +549,7 @@ static void tomoyo_collect_entry(void) | |||
534 | { | 549 | { |
535 | struct tomoyo_shared_acl_head *ptr; | 550 | struct tomoyo_shared_acl_head *ptr; |
536 | struct tomoyo_shared_acl_head *tmp; | 551 | struct tomoyo_shared_acl_head *tmp; |
552 | |||
537 | list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list, | 553 | list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list, |
538 | list) { | 554 | list) { |
539 | if (atomic_read(&ptr->users) > 0) | 555 | if (atomic_read(&ptr->users) > 0) |
@@ -547,6 +563,7 @@ static void tomoyo_collect_entry(void) | |||
547 | struct list_head *list = &ns->group_list[i]; | 563 | struct list_head *list = &ns->group_list[i]; |
548 | struct tomoyo_group *group; | 564 | struct tomoyo_group *group; |
549 | struct tomoyo_group *tmp; | 565 | struct tomoyo_group *tmp; |
566 | |||
550 | switch (i) { | 567 | switch (i) { |
551 | case 0: | 568 | case 0: |
552 | id = TOMOYO_ID_PATH_GROUP; | 569 | id = TOMOYO_ID_PATH_GROUP; |
@@ -574,6 +591,7 @@ static void tomoyo_collect_entry(void) | |||
574 | struct list_head *list = &tomoyo_name_list[i]; | 591 | struct list_head *list = &tomoyo_name_list[i]; |
575 | struct tomoyo_shared_acl_head *ptr; | 592 | struct tomoyo_shared_acl_head *ptr; |
576 | struct tomoyo_shared_acl_head *tmp; | 593 | struct tomoyo_shared_acl_head *tmp; |
594 | |||
577 | list_for_each_entry_safe(ptr, tmp, list, list) { | 595 | list_for_each_entry_safe(ptr, tmp, list, list) { |
578 | if (atomic_read(&ptr->users) > 0) | 596 | if (atomic_read(&ptr->users) > 0) |
579 | continue; | 597 | continue; |
@@ -595,6 +613,7 @@ static int tomoyo_gc_thread(void *unused) | |||
595 | { | 613 | { |
596 | /* Garbage collector thread is exclusive. */ | 614 | /* Garbage collector thread is exclusive. */ |
597 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 615 | static DEFINE_MUTEX(tomoyo_gc_mutex); |
616 | |||
598 | if (!mutex_trylock(&tomoyo_gc_mutex)) | 617 | if (!mutex_trylock(&tomoyo_gc_mutex)) |
599 | goto out; | 618 | goto out; |
600 | tomoyo_collect_entry(); | 619 | tomoyo_collect_entry(); |
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c index 21b0cc3a7e1a..a37c7dc66e44 100644 --- a/security/tomoyo/group.c +++ b/security/tomoyo/group.c | |||
@@ -75,11 +75,13 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) | |||
75 | { | 75 | { |
76 | struct tomoyo_group *group = tomoyo_get_group(param, type); | 76 | struct tomoyo_group *group = tomoyo_get_group(param, type); |
77 | int error = -EINVAL; | 77 | int error = -EINVAL; |
78 | |||
78 | if (!group) | 79 | if (!group) |
79 | return -ENOMEM; | 80 | return -ENOMEM; |
80 | param->list = &group->member_list; | 81 | param->list = &group->member_list; |
81 | if (type == TOMOYO_PATH_GROUP) { | 82 | if (type == TOMOYO_PATH_GROUP) { |
82 | struct tomoyo_path_group e = { }; | 83 | struct tomoyo_path_group e = { }; |
84 | |||
83 | e.member_name = tomoyo_get_name(tomoyo_read_token(param)); | 85 | e.member_name = tomoyo_get_name(tomoyo_read_token(param)); |
84 | if (!e.member_name) { | 86 | if (!e.member_name) { |
85 | error = -ENOMEM; | 87 | error = -ENOMEM; |
@@ -90,6 +92,7 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) | |||
90 | tomoyo_put_name(e.member_name); | 92 | tomoyo_put_name(e.member_name); |
91 | } else if (type == TOMOYO_NUMBER_GROUP) { | 93 | } else if (type == TOMOYO_NUMBER_GROUP) { |
92 | struct tomoyo_number_group e = { }; | 94 | struct tomoyo_number_group e = { }; |
95 | |||
93 | if (param->data[0] == '@' || | 96 | if (param->data[0] == '@' || |
94 | !tomoyo_parse_number_union(param, &e.number)) | 97 | !tomoyo_parse_number_union(param, &e.number)) |
95 | goto out; | 98 | goto out; |
@@ -129,6 +132,7 @@ tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, | |||
129 | const struct tomoyo_group *group) | 132 | const struct tomoyo_group *group) |
130 | { | 133 | { |
131 | struct tomoyo_path_group *member; | 134 | struct tomoyo_path_group *member; |
135 | |||
132 | list_for_each_entry_rcu(member, &group->member_list, head.list) { | 136 | list_for_each_entry_rcu(member, &group->member_list, head.list) { |
133 | if (member->head.is_deleted) | 137 | if (member->head.is_deleted) |
134 | continue; | 138 | continue; |
@@ -156,6 +160,7 @@ bool tomoyo_number_matches_group(const unsigned long min, | |||
156 | { | 160 | { |
157 | struct tomoyo_number_group *member; | 161 | struct tomoyo_number_group *member; |
158 | bool matched = false; | 162 | bool matched = false; |
163 | |||
159 | list_for_each_entry_rcu(member, &group->member_list, head.list) { | 164 | list_for_each_entry_rcu(member, &group->member_list, head.list) { |
160 | if (member->head.is_deleted) | 165 | if (member->head.is_deleted) |
161 | continue; | 166 | continue; |
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c index 81b951652051..3445ae6fd479 100644 --- a/security/tomoyo/load_policy.c +++ b/security/tomoyo/load_policy.c | |||
@@ -37,11 +37,12 @@ __setup("TOMOYO_loader=", tomoyo_loader_setup); | |||
37 | static bool tomoyo_policy_loader_exists(void) | 37 | static bool tomoyo_policy_loader_exists(void) |
38 | { | 38 | { |
39 | struct path path; | 39 | struct path path; |
40 | |||
40 | if (!tomoyo_loader) | 41 | if (!tomoyo_loader) |
41 | tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER; | 42 | tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER; |
42 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { | 43 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { |
43 | printk(KERN_INFO "Not activating Mandatory Access Control " | 44 | pr_info("Not activating Mandatory Access Control as %s does not exist.\n", |
44 | "as %s does not exist.\n", tomoyo_loader); | 45 | tomoyo_loader); |
45 | return false; | 46 | return false; |
46 | } | 47 | } |
47 | path_put(&path); | 48 | path_put(&path); |
@@ -96,8 +97,7 @@ void tomoyo_load_policy(const char *filename) | |||
96 | if (!tomoyo_policy_loader_exists()) | 97 | if (!tomoyo_policy_loader_exists()) |
97 | return; | 98 | return; |
98 | done = true; | 99 | done = true; |
99 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", | 100 | pr_info("Calling %s to load policy. Please wait.\n", tomoyo_loader); |
100 | tomoyo_loader); | ||
101 | argv[0] = (char *) tomoyo_loader; | 101 | argv[0] = (char *) tomoyo_loader; |
102 | argv[1] = NULL; | 102 | argv[1] = NULL; |
103 | envp[0] = "HOME=/"; | 103 | envp[0] = "HOME=/"; |
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 12477e0b0a11..2e7fcfa923c9 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -19,9 +19,9 @@ void tomoyo_warn_oom(const char *function) | |||
19 | /* Reduce error messages. */ | 19 | /* Reduce error messages. */ |
20 | static pid_t tomoyo_last_pid; | 20 | static pid_t tomoyo_last_pid; |
21 | const pid_t pid = current->pid; | 21 | const pid_t pid = current->pid; |
22 | |||
22 | if (tomoyo_last_pid != pid) { | 23 | if (tomoyo_last_pid != pid) { |
23 | printk(KERN_WARNING "ERROR: Out of memory at %s.\n", | 24 | pr_warn("ERROR: Out of memory at %s.\n", function); |
24 | function); | ||
25 | tomoyo_last_pid = pid; | 25 | tomoyo_last_pid = pid; |
26 | } | 26 | } |
27 | if (!tomoyo_policy_loaded) | 27 | if (!tomoyo_policy_loaded) |
@@ -48,6 +48,7 @@ bool tomoyo_memory_ok(void *ptr) | |||
48 | { | 48 | { |
49 | if (ptr) { | 49 | if (ptr) { |
50 | const size_t s = ksize(ptr); | 50 | const size_t s = ksize(ptr); |
51 | |||
51 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; | 52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; |
52 | if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || | 53 | if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || |
53 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= | 54 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= |
@@ -73,6 +74,7 @@ bool tomoyo_memory_ok(void *ptr) | |||
73 | void *tomoyo_commit_ok(void *data, const unsigned int size) | 74 | void *tomoyo_commit_ok(void *data, const unsigned int size) |
74 | { | 75 | { |
75 | void *ptr = kzalloc(size, GFP_NOFS); | 76 | void *ptr = kzalloc(size, GFP_NOFS); |
77 | |||
76 | if (tomoyo_memory_ok(ptr)) { | 78 | if (tomoyo_memory_ok(ptr)) { |
77 | memmove(ptr, data, size); | 79 | memmove(ptr, data, size); |
78 | memset(data, 0, size); | 80 | memset(data, 0, size); |
@@ -98,6 +100,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | |||
98 | struct list_head *list; | 100 | struct list_head *list; |
99 | const char *group_name = tomoyo_read_token(param); | 101 | const char *group_name = tomoyo_read_token(param); |
100 | bool found = false; | 102 | bool found = false; |
103 | |||
101 | if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) | 104 | if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) |
102 | return NULL; | 105 | return NULL; |
103 | e.group_name = tomoyo_get_name(group_name); | 106 | e.group_name = tomoyo_get_name(group_name); |
@@ -116,6 +119,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | |||
116 | } | 119 | } |
117 | if (!found) { | 120 | if (!found) { |
118 | struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); | 121 | struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); |
122 | |||
119 | if (entry) { | 123 | if (entry) { |
120 | INIT_LIST_HEAD(&entry->member_list); | 124 | INIT_LIST_HEAD(&entry->member_list); |
121 | atomic_set(&entry->head.users, 1); | 125 | atomic_set(&entry->head.users, 1); |
@@ -191,6 +195,7 @@ struct tomoyo_policy_namespace tomoyo_kernel_namespace; | |||
191 | void __init tomoyo_mm_init(void) | 195 | void __init tomoyo_mm_init(void) |
192 | { | 196 | { |
193 | int idx; | 197 | int idx; |
198 | |||
194 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) | 199 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) |
195 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | 200 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); |
196 | tomoyo_kernel_namespace.name = "<kernel>"; | 201 | tomoyo_kernel_namespace.name = "<kernel>"; |
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 7dc7f59b7dde..2755971f50df 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c | |||
@@ -49,6 +49,7 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, | |||
49 | { | 49 | { |
50 | const struct tomoyo_mount_acl *acl = | 50 | const struct tomoyo_mount_acl *acl = |
51 | container_of(ptr, typeof(*acl), head); | 51 | container_of(ptr, typeof(*acl), head); |
52 | |||
52 | return tomoyo_compare_number_union(r->param.mount.flags, | 53 | return tomoyo_compare_number_union(r->param.mount.flags, |
53 | &acl->flags) && | 54 | &acl->flags) && |
54 | tomoyo_compare_name_union(r->param.mount.type, | 55 | tomoyo_compare_name_union(r->param.mount.type, |
@@ -89,6 +90,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, | |||
89 | struct tomoyo_path_info rdir; | 90 | struct tomoyo_path_info rdir; |
90 | int need_dev = 0; | 91 | int need_dev = 0; |
91 | int error = -ENOMEM; | 92 | int error = -ENOMEM; |
93 | |||
92 | r->obj = &obj; | 94 | r->obj = &obj; |
93 | 95 | ||
94 | /* Get fstype. */ | 96 | /* Get fstype. */ |
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 6ff8c21e4fff..85e6e31dd1e5 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -94,11 +94,13 @@ static char *tomoyo_get_absolute_path(const struct path *path, char * const buff | |||
94 | const int buflen) | 94 | const int buflen) |
95 | { | 95 | { |
96 | char *pos = ERR_PTR(-ENOMEM); | 96 | char *pos = ERR_PTR(-ENOMEM); |
97 | |||
97 | if (buflen >= 256) { | 98 | if (buflen >= 256) { |
98 | /* go to whatever namespace root we are under */ | 99 | /* go to whatever namespace root we are under */ |
99 | pos = d_absolute_path(path, buffer, buflen - 1); | 100 | pos = d_absolute_path(path, buffer, buflen - 1); |
100 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { | 101 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { |
101 | struct inode *inode = d_backing_inode(path->dentry); | 102 | struct inode *inode = d_backing_inode(path->dentry); |
103 | |||
102 | if (inode && S_ISDIR(inode->i_mode)) { | 104 | if (inode && S_ISDIR(inode->i_mode)) { |
103 | buffer[buflen - 2] = '/'; | 105 | buffer[buflen - 2] = '/'; |
104 | buffer[buflen - 1] = '\0'; | 106 | buffer[buflen - 1] = '\0'; |
@@ -123,10 +125,12 @@ static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer, | |||
123 | const int buflen) | 125 | const int buflen) |
124 | { | 126 | { |
125 | char *pos = ERR_PTR(-ENOMEM); | 127 | char *pos = ERR_PTR(-ENOMEM); |
128 | |||
126 | if (buflen >= 256) { | 129 | if (buflen >= 256) { |
127 | pos = dentry_path_raw(dentry, buffer, buflen - 1); | 130 | pos = dentry_path_raw(dentry, buffer, buflen - 1); |
128 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { | 131 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { |
129 | struct inode *inode = d_backing_inode(dentry); | 132 | struct inode *inode = d_backing_inode(dentry); |
133 | |||
130 | if (inode && S_ISDIR(inode->i_mode)) { | 134 | if (inode && S_ISDIR(inode->i_mode)) { |
131 | buffer[buflen - 2] = '/'; | 135 | buffer[buflen - 2] = '/'; |
132 | buffer[buflen - 1] = '\0'; | 136 | buffer[buflen - 1] = '\0'; |
@@ -150,12 +154,14 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, | |||
150 | { | 154 | { |
151 | struct super_block *sb = dentry->d_sb; | 155 | struct super_block *sb = dentry->d_sb; |
152 | char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen); | 156 | char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen); |
157 | |||
153 | if (IS_ERR(pos)) | 158 | if (IS_ERR(pos)) |
154 | return pos; | 159 | return pos; |
155 | /* Convert from $PID to self if $PID is current thread. */ | 160 | /* Convert from $PID to self if $PID is current thread. */ |
156 | if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { | 161 | if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { |
157 | char *ep; | 162 | char *ep; |
158 | const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); | 163 | const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); |
164 | |||
159 | if (*ep == '/' && pid && pid == | 165 | if (*ep == '/' && pid && pid == |
160 | task_tgid_nr_ns(current, sb->s_fs_info)) { | 166 | task_tgid_nr_ns(current, sb->s_fs_info)) { |
161 | pos = ep - 5; | 167 | pos = ep - 5; |
@@ -170,6 +176,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, | |||
170 | goto prepend_filesystem_name; | 176 | goto prepend_filesystem_name; |
171 | { | 177 | { |
172 | struct inode *inode = d_backing_inode(sb->s_root); | 178 | struct inode *inode = d_backing_inode(sb->s_root); |
179 | |||
173 | /* | 180 | /* |
174 | * Use filesystem name if filesystem does not support rename() | 181 | * Use filesystem name if filesystem does not support rename() |
175 | * operation. | 182 | * operation. |
@@ -182,6 +189,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, | |||
182 | char name[64]; | 189 | char name[64]; |
183 | int name_len; | 190 | int name_len; |
184 | const dev_t dev = sb->s_dev; | 191 | const dev_t dev = sb->s_dev; |
192 | |||
185 | name[sizeof(name) - 1] = '\0'; | 193 | name[sizeof(name) - 1] = '\0'; |
186 | snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev), | 194 | snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev), |
187 | MINOR(dev)); | 195 | MINOR(dev)); |
@@ -197,6 +205,7 @@ prepend_filesystem_name: | |||
197 | { | 205 | { |
198 | const char *name = sb->s_type->name; | 206 | const char *name = sb->s_type->name; |
199 | const int name_len = strlen(name); | 207 | const int name_len = strlen(name); |
208 | |||
200 | pos -= name_len + 1; | 209 | pos -= name_len + 1; |
201 | if (pos < buffer) | 210 | if (pos < buffer) |
202 | goto out; | 211 | goto out; |
@@ -223,10 +232,10 @@ static char *tomoyo_get_socket_name(const struct path *path, char * const buffer | |||
223 | struct inode *inode = d_backing_inode(path->dentry); | 232 | struct inode *inode = d_backing_inode(path->dentry); |
224 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; | 233 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; |
225 | struct sock *sk = sock ? sock->sk : NULL; | 234 | struct sock *sk = sock ? sock->sk : NULL; |
235 | |||
226 | if (sk) { | 236 | if (sk) { |
227 | snprintf(buffer, buflen, "socket:[family=%u:type=%u:" | 237 | snprintf(buffer, buflen, "socket:[family=%u:type=%u:protocol=%u]", |
228 | "protocol=%u]", sk->sk_family, sk->sk_type, | 238 | sk->sk_family, sk->sk_type, sk->sk_protocol); |
229 | sk->sk_protocol); | ||
230 | } else { | 239 | } else { |
231 | snprintf(buffer, buflen, "socket:[unknown]"); | 240 | snprintf(buffer, buflen, "socket:[unknown]"); |
232 | } | 241 | } |
@@ -255,12 +264,14 @@ char *tomoyo_realpath_from_path(const struct path *path) | |||
255 | unsigned int buf_len = PAGE_SIZE / 2; | 264 | unsigned int buf_len = PAGE_SIZE / 2; |
256 | struct dentry *dentry = path->dentry; | 265 | struct dentry *dentry = path->dentry; |
257 | struct super_block *sb; | 266 | struct super_block *sb; |
267 | |||
258 | if (!dentry) | 268 | if (!dentry) |
259 | return NULL; | 269 | return NULL; |
260 | sb = dentry->d_sb; | 270 | sb = dentry->d_sb; |
261 | while (1) { | 271 | while (1) { |
262 | char *pos; | 272 | char *pos; |
263 | struct inode *inode; | 273 | struct inode *inode; |
274 | |||
264 | buf_len <<= 1; | 275 | buf_len <<= 1; |
265 | kfree(buf); | 276 | kfree(buf); |
266 | buf = kmalloc(buf_len, GFP_NOFS); | 277 | buf = kmalloc(buf_len, GFP_NOFS); |
@@ -323,6 +334,7 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
323 | 334 | ||
324 | if (pathname && kern_path(pathname, 0, &path) == 0) { | 335 | if (pathname && kern_path(pathname, 0, &path) == 0) { |
325 | char *buf = tomoyo_realpath_from_path(&path); | 336 | char *buf = tomoyo_realpath_from_path(&path); |
337 | |||
326 | path_put(&path); | 338 | path_put(&path); |
327 | return buf; | 339 | return buf; |
328 | } | 340 | } |
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index 1d3d7e7a1f05..546281c5b233 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c | |||
@@ -21,6 +21,7 @@ static bool tomoyo_check_task_acl(struct tomoyo_request_info *r, | |||
21 | { | 21 | { |
22 | const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), | 22 | const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), |
23 | head); | 23 | head); |
24 | |||
24 | return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname); | 25 | return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname); |
25 | } | 26 | } |
26 | 27 | ||
@@ -42,6 +43,7 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, | |||
42 | { | 43 | { |
43 | char *data; | 44 | char *data; |
44 | int error; | 45 | int error; |
46 | |||
45 | if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) | 47 | if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) |
46 | return -ENOMEM; | 48 | return -ENOMEM; |
47 | data = memdup_user_nul(buf, count); | 49 | data = memdup_user_nul(buf, count); |
@@ -52,6 +54,7 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, | |||
52 | const int idx = tomoyo_read_lock(); | 54 | const int idx = tomoyo_read_lock(); |
53 | struct tomoyo_path_info name; | 55 | struct tomoyo_path_info name; |
54 | struct tomoyo_request_info r; | 56 | struct tomoyo_request_info r; |
57 | |||
55 | name.name = data; | 58 | name.name = data; |
56 | tomoyo_fill_path_info(&name); | 59 | tomoyo_fill_path_info(&name); |
57 | /* Check "task manual_domain_transition" permission. */ | 60 | /* Check "task manual_domain_transition" permission. */ |
@@ -67,18 +70,14 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, | |||
67 | if (!new_domain) { | 70 | if (!new_domain) { |
68 | error = -ENOENT; | 71 | error = -ENOENT; |
69 | } else { | 72 | } else { |
70 | struct cred *cred = prepare_creds(); | 73 | struct tomoyo_task *s = tomoyo_task(current); |
71 | if (!cred) { | 74 | struct tomoyo_domain_info *old_domain = |
72 | error = -ENOMEM; | 75 | s->domain_info; |
73 | } else { | 76 | |
74 | struct tomoyo_domain_info *old_domain = | 77 | s->domain_info = new_domain; |
75 | cred->security; | 78 | atomic_inc(&new_domain->users); |
76 | cred->security = new_domain; | 79 | atomic_dec(&old_domain->users); |
77 | atomic_inc(&new_domain->users); | 80 | error = 0; |
78 | atomic_dec(&old_domain->users); | ||
79 | commit_creds(cred); | ||
80 | error = 0; | ||
81 | } | ||
82 | } | 81 | } |
83 | } | 82 | } |
84 | tomoyo_read_unlock(idx); | 83 | tomoyo_read_unlock(idx); |
@@ -104,6 +103,7 @@ static ssize_t tomoyo_read_self(struct file *file, char __user *buf, | |||
104 | const char *domain = tomoyo_domain()->domainname->name; | 103 | const char *domain = tomoyo_domain()->domainname->name; |
105 | loff_t len = strlen(domain); | 104 | loff_t len = strlen(domain); |
106 | loff_t pos = *ppos; | 105 | loff_t pos = *ppos; |
106 | |||
107 | if (pos >= len || !count) | 107 | if (pos >= len || !count) |
108 | return 0; | 108 | return 0; |
109 | len -= pos; | 109 | len -= pos; |
@@ -234,10 +234,14 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode, | |||
234 | */ | 234 | */ |
235 | static int __init tomoyo_initerface_init(void) | 235 | static int __init tomoyo_initerface_init(void) |
236 | { | 236 | { |
237 | struct tomoyo_domain_info *domain; | ||
237 | struct dentry *tomoyo_dir; | 238 | struct dentry *tomoyo_dir; |
238 | 239 | ||
240 | if (!tomoyo_enabled) | ||
241 | return 0; | ||
242 | domain = tomoyo_domain(); | ||
239 | /* Don't create securityfs entries unless registered. */ | 243 | /* Don't create securityfs entries unless registered. */ |
240 | if (current_cred()->security != &tomoyo_kernel_domain) | 244 | if (domain != &tomoyo_kernel_domain) |
241 | return 0; | 245 | return 0; |
242 | 246 | ||
243 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); | 247 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 1b5b5097efd7..716c92ec941a 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -9,17 +9,19 @@ | |||
9 | #include "common.h" | 9 | #include "common.h" |
10 | 10 | ||
11 | /** | 11 | /** |
12 | * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank(). | 12 | * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. |
13 | * | 13 | * |
14 | * @new: Pointer to "struct cred". | 14 | * Returns pointer to "struct tomoyo_domain_info" for current thread. |
15 | * @gfp: Memory allocation flags. | ||
16 | * | ||
17 | * Returns 0. | ||
18 | */ | 15 | */ |
19 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | 16 | struct tomoyo_domain_info *tomoyo_domain(void) |
20 | { | 17 | { |
21 | new->security = NULL; | 18 | struct tomoyo_task *s = tomoyo_task(current); |
22 | return 0; | 19 | |
20 | if (s->old_domain_info && !current->in_execve) { | ||
21 | atomic_dec(&s->old_domain_info->users); | ||
22 | s->old_domain_info = NULL; | ||
23 | } | ||
24 | return s->domain_info; | ||
23 | } | 25 | } |
24 | 26 | ||
25 | /** | 27 | /** |
@@ -34,42 +36,38 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | |||
34 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 36 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
35 | gfp_t gfp) | 37 | gfp_t gfp) |
36 | { | 38 | { |
37 | struct tomoyo_domain_info *domain = old->security; | 39 | /* Restore old_domain_info saved by previous execve() request. */ |
38 | new->security = domain; | 40 | struct tomoyo_task *s = tomoyo_task(current); |
39 | if (domain) | 41 | |
40 | atomic_inc(&domain->users); | 42 | if (s->old_domain_info && !current->in_execve) { |
43 | atomic_dec(&s->domain_info->users); | ||
44 | s->domain_info = s->old_domain_info; | ||
45 | s->old_domain_info = NULL; | ||
46 | } | ||
41 | return 0; | 47 | return 0; |
42 | } | 48 | } |
43 | 49 | ||
44 | /** | 50 | /** |
45 | * tomoyo_cred_transfer - Target for security_transfer_creds(). | 51 | * tomoyo_bprm_committed_creds - Target for security_bprm_committed_creds(). |
46 | * | 52 | * |
47 | * @new: Pointer to "struct cred". | 53 | * @bprm: Pointer to "struct linux_binprm". |
48 | * @old: Pointer to "struct cred". | ||
49 | */ | 54 | */ |
50 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | 55 | static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm) |
51 | { | 56 | { |
52 | tomoyo_cred_prepare(new, old, 0); | 57 | /* Clear old_domain_info saved by execve() request. */ |
53 | } | 58 | struct tomoyo_task *s = tomoyo_task(current); |
54 | 59 | ||
55 | /** | 60 | atomic_dec(&s->old_domain_info->users); |
56 | * tomoyo_cred_free - Target for security_cred_free(). | 61 | s->old_domain_info = NULL; |
57 | * | ||
58 | * @cred: Pointer to "struct cred". | ||
59 | */ | ||
60 | static void tomoyo_cred_free(struct cred *cred) | ||
61 | { | ||
62 | struct tomoyo_domain_info *domain = cred->security; | ||
63 | if (domain) | ||
64 | atomic_dec(&domain->users); | ||
65 | } | 62 | } |
66 | 63 | ||
64 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
67 | /** | 65 | /** |
68 | * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). | 66 | * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). |
69 | * | 67 | * |
70 | * @bprm: Pointer to "struct linux_binprm". | 68 | * @bprm: Pointer to "struct linux_binprm". |
71 | * | 69 | * |
72 | * Returns 0 on success, negative value otherwise. | 70 | * Returns 0. |
73 | */ | 71 | */ |
74 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 72 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
75 | { | 73 | { |
@@ -79,29 +77,15 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
79 | */ | 77 | */ |
80 | if (bprm->called_set_creds) | 78 | if (bprm->called_set_creds) |
81 | return 0; | 79 | return 0; |
82 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
83 | /* | 80 | /* |
84 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested | 81 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested |
85 | * for the first time. | 82 | * for the first time. |
86 | */ | 83 | */ |
87 | if (!tomoyo_policy_loaded) | 84 | if (!tomoyo_policy_loaded) |
88 | tomoyo_load_policy(bprm->filename); | 85 | tomoyo_load_policy(bprm->filename); |
89 | #endif | ||
90 | /* | ||
91 | * Release reference to "struct tomoyo_domain_info" stored inside | ||
92 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" | ||
93 | * stored inside "bprm->cred->security" will be acquired later inside | ||
94 | * tomoyo_find_next_domain(). | ||
95 | */ | ||
96 | atomic_dec(&((struct tomoyo_domain_info *) | ||
97 | bprm->cred->security)->users); | ||
98 | /* | ||
99 | * Tell tomoyo_bprm_check_security() is called for the first time of an | ||
100 | * execve operation. | ||
101 | */ | ||
102 | bprm->cred->security = NULL; | ||
103 | return 0; | 86 | return 0; |
104 | } | 87 | } |
88 | #endif | ||
105 | 89 | ||
106 | /** | 90 | /** |
107 | * tomoyo_bprm_check_security - Target for security_bprm_check(). | 91 | * tomoyo_bprm_check_security - Target for security_bprm_check(). |
@@ -112,23 +96,24 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
112 | */ | 96 | */ |
113 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | 97 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) |
114 | { | 98 | { |
115 | struct tomoyo_domain_info *domain = bprm->cred->security; | 99 | struct tomoyo_task *s = tomoyo_task(current); |
116 | 100 | ||
117 | /* | 101 | /* |
118 | * Execute permission is checked against pathname passed to do_execve() | 102 | * Execute permission is checked against pathname passed to do_execve() |
119 | * using current domain. | 103 | * using current domain. |
120 | */ | 104 | */ |
121 | if (!domain) { | 105 | if (!s->old_domain_info) { |
122 | const int idx = tomoyo_read_lock(); | 106 | const int idx = tomoyo_read_lock(); |
123 | const int err = tomoyo_find_next_domain(bprm); | 107 | const int err = tomoyo_find_next_domain(bprm); |
108 | |||
124 | tomoyo_read_unlock(idx); | 109 | tomoyo_read_unlock(idx); |
125 | return err; | 110 | return err; |
126 | } | 111 | } |
127 | /* | 112 | /* |
128 | * Read permission is checked against interpreters using next domain. | 113 | * Read permission is checked against interpreters using next domain. |
129 | */ | 114 | */ |
130 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, | 115 | return tomoyo_check_open_permission(s->domain_info, |
131 | O_RDONLY); | 116 | &bprm->file->f_path, O_RDONLY); |
132 | } | 117 | } |
133 | 118 | ||
134 | /** | 119 | /** |
@@ -167,6 +152,7 @@ static int tomoyo_path_truncate(const struct path *path) | |||
167 | static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) | 152 | static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) |
168 | { | 153 | { |
169 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; | 154 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
155 | |||
170 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); | 156 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); |
171 | } | 157 | } |
172 | 158 | ||
@@ -183,6 +169,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, | |||
183 | umode_t mode) | 169 | umode_t mode) |
184 | { | 170 | { |
185 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; | 171 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
172 | |||
186 | return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, | 173 | return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, |
187 | mode & S_IALLUGO); | 174 | mode & S_IALLUGO); |
188 | } | 175 | } |
@@ -198,6 +185,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, | |||
198 | static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) | 185 | static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) |
199 | { | 186 | { |
200 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; | 187 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
188 | |||
201 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); | 189 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); |
202 | } | 190 | } |
203 | 191 | ||
@@ -214,6 +202,7 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, | |||
214 | const char *old_name) | 202 | const char *old_name) |
215 | { | 203 | { |
216 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; | 204 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
205 | |||
217 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); | 206 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); |
218 | } | 207 | } |
219 | 208 | ||
@@ -271,6 +260,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_di | |||
271 | { | 260 | { |
272 | struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; | 261 | struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; |
273 | struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; | 262 | struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; |
263 | |||
274 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); | 264 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
275 | } | 265 | } |
276 | 266 | ||
@@ -291,6 +281,7 @@ static int tomoyo_path_rename(const struct path *old_parent, | |||
291 | { | 281 | { |
292 | struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; | 282 | struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; |
293 | struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; | 283 | struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; |
284 | |||
294 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); | 285 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
295 | } | 286 | } |
296 | 287 | ||
@@ -322,11 +313,11 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | |||
322 | */ | 313 | */ |
323 | static int tomoyo_file_open(struct file *f) | 314 | static int tomoyo_file_open(struct file *f) |
324 | { | 315 | { |
325 | int flags = f->f_flags; | ||
326 | /* Don't check read permission here if called from do_execve(). */ | 316 | /* Don't check read permission here if called from do_execve(). */ |
327 | if (current->in_execve) | 317 | if (current->in_execve) |
328 | return 0; | 318 | return 0; |
329 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 319 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, |
320 | f->f_flags); | ||
330 | } | 321 | } |
331 | 322 | ||
332 | /** | 323 | /** |
@@ -370,6 +361,7 @@ static int tomoyo_path_chmod(const struct path *path, umode_t mode) | |||
370 | static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid) | 361 | static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid) |
371 | { | 362 | { |
372 | int error = 0; | 363 | int error = 0; |
364 | |||
373 | if (uid_valid(uid)) | 365 | if (uid_valid(uid)) |
374 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, | 366 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, |
375 | from_kuid(&init_user_ns, uid)); | 367 | from_kuid(&init_user_ns, uid)); |
@@ -419,6 +411,7 @@ static int tomoyo_sb_mount(const char *dev_name, const struct path *path, | |||
419 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) | 411 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) |
420 | { | 412 | { |
421 | struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; | 413 | struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; |
414 | |||
422 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); | 415 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); |
423 | } | 416 | } |
424 | 417 | ||
@@ -493,16 +486,61 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
493 | return tomoyo_socket_sendmsg_permission(sock, msg, size); | 486 | return tomoyo_socket_sendmsg_permission(sock, msg, size); |
494 | } | 487 | } |
495 | 488 | ||
489 | struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = { | ||
490 | .lbs_task = sizeof(struct tomoyo_task), | ||
491 | }; | ||
492 | |||
493 | /** | ||
494 | * tomoyo_task_alloc - Target for security_task_alloc(). | ||
495 | * | ||
496 | * @task: Pointer to "struct task_struct". | ||
497 | * @flags: clone() flags. | ||
498 | * | ||
499 | * Returns 0. | ||
500 | */ | ||
501 | static int tomoyo_task_alloc(struct task_struct *task, | ||
502 | unsigned long clone_flags) | ||
503 | { | ||
504 | struct tomoyo_task *old = tomoyo_task(current); | ||
505 | struct tomoyo_task *new = tomoyo_task(task); | ||
506 | |||
507 | new->domain_info = old->domain_info; | ||
508 | atomic_inc(&new->domain_info->users); | ||
509 | new->old_domain_info = NULL; | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | /** | ||
514 | * tomoyo_task_free - Target for security_task_free(). | ||
515 | * | ||
516 | * @task: Pointer to "struct task_struct". | ||
517 | */ | ||
518 | static void tomoyo_task_free(struct task_struct *task) | ||
519 | { | ||
520 | struct tomoyo_task *s = tomoyo_task(task); | ||
521 | |||
522 | if (s->domain_info) { | ||
523 | atomic_dec(&s->domain_info->users); | ||
524 | s->domain_info = NULL; | ||
525 | } | ||
526 | if (s->old_domain_info) { | ||
527 | atomic_dec(&s->old_domain_info->users); | ||
528 | s->old_domain_info = NULL; | ||
529 | } | ||
530 | } | ||
531 | |||
496 | /* | 532 | /* |
497 | * tomoyo_security_ops is a "struct security_operations" which is used for | 533 | * tomoyo_security_ops is a "struct security_operations" which is used for |
498 | * registering TOMOYO. | 534 | * registering TOMOYO. |
499 | */ | 535 | */ |
500 | static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { | 536 | static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { |
501 | LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank), | ||
502 | LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), | 537 | LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), |
503 | LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer), | 538 | LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds), |
504 | LSM_HOOK_INIT(cred_free, tomoyo_cred_free), | 539 | LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), |
540 | LSM_HOOK_INIT(task_free, tomoyo_task_free), | ||
541 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
505 | LSM_HOOK_INIT(bprm_set_creds, tomoyo_bprm_set_creds), | 542 | LSM_HOOK_INIT(bprm_set_creds, tomoyo_bprm_set_creds), |
543 | #endif | ||
506 | LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), | 544 | LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), |
507 | LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl), | 545 | LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl), |
508 | LSM_HOOK_INIT(file_open, tomoyo_file_open), | 546 | LSM_HOOK_INIT(file_open, tomoyo_file_open), |
@@ -531,6 +569,8 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { | |||
531 | /* Lock for GC. */ | 569 | /* Lock for GC. */ |
532 | DEFINE_SRCU(tomoyo_ss); | 570 | DEFINE_SRCU(tomoyo_ss); |
533 | 571 | ||
572 | int tomoyo_enabled __lsm_ro_after_init = 1; | ||
573 | |||
534 | /** | 574 | /** |
535 | * tomoyo_init - Register TOMOYO Linux as a LSM module. | 575 | * tomoyo_init - Register TOMOYO Linux as a LSM module. |
536 | * | 576 | * |
@@ -538,19 +578,23 @@ DEFINE_SRCU(tomoyo_ss); | |||
538 | */ | 578 | */ |
539 | static int __init tomoyo_init(void) | 579 | static int __init tomoyo_init(void) |
540 | { | 580 | { |
541 | struct cred *cred = (struct cred *) current_cred(); | 581 | struct tomoyo_task *s = tomoyo_task(current); |
542 | 582 | ||
543 | if (!security_module_enable("tomoyo")) | ||
544 | return 0; | ||
545 | /* register ourselves with the security framework */ | 583 | /* register ourselves with the security framework */ |
546 | security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); | 584 | security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); |
547 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 585 | pr_info("TOMOYO Linux initialized\n"); |
548 | cred->security = &tomoyo_kernel_domain; | 586 | s->domain_info = &tomoyo_kernel_domain; |
587 | atomic_inc(&tomoyo_kernel_domain.users); | ||
588 | s->old_domain_info = NULL; | ||
549 | tomoyo_mm_init(); | 589 | tomoyo_mm_init(); |
590 | |||
550 | return 0; | 591 | return 0; |
551 | } | 592 | } |
552 | 593 | ||
553 | DEFINE_LSM(tomoyo) = { | 594 | DEFINE_LSM(tomoyo) = { |
554 | .name = "tomoyo", | 595 | .name = "tomoyo", |
596 | .enabled = &tomoyo_enabled, | ||
597 | .flags = LSM_FLAG_LEGACY_MAJOR, | ||
598 | .blobs = &tomoyo_blob_sizes, | ||
555 | .init = tomoyo_init, | 599 | .init = tomoyo_init, |
556 | }; | 600 | }; |
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index badffc8271c8..0517cbdd7275 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -91,6 +91,7 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { | |||
91 | void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp) | 91 | void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp) |
92 | { | 92 | { |
93 | struct tm tm; | 93 | struct tm tm; |
94 | |||
94 | time64_to_tm(time64, 0, &tm); | 95 | time64_to_tm(time64, 0, &tm); |
95 | stamp->sec = tm.tm_sec; | 96 | stamp->sec = tm.tm_sec; |
96 | stamp->min = tm.tm_min; | 97 | stamp->min = tm.tm_min; |
@@ -113,6 +114,7 @@ void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp) | |||
113 | bool tomoyo_permstr(const char *string, const char *keyword) | 114 | bool tomoyo_permstr(const char *string, const char *keyword) |
114 | { | 115 | { |
115 | const char *cp = strstr(string, keyword); | 116 | const char *cp = strstr(string, keyword); |
117 | |||
116 | if (cp) | 118 | if (cp) |
117 | return cp == string || *(cp - 1) == '/'; | 119 | return cp == string || *(cp - 1) == '/'; |
118 | return false; | 120 | return false; |
@@ -132,6 +134,7 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param) | |||
132 | { | 134 | { |
133 | char *pos = param->data; | 135 | char *pos = param->data; |
134 | char *del = strchr(pos, ' '); | 136 | char *del = strchr(pos, ' '); |
137 | |||
135 | if (del) | 138 | if (del) |
136 | *del++ = '\0'; | 139 | *del++ = '\0'; |
137 | else | 140 | else |
@@ -152,6 +155,7 @@ const struct tomoyo_path_info *tomoyo_get_domainname | |||
152 | { | 155 | { |
153 | char *start = param->data; | 156 | char *start = param->data; |
154 | char *pos = start; | 157 | char *pos = start; |
158 | |||
155 | while (*pos) { | 159 | while (*pos) { |
156 | if (*pos++ != ' ' || *pos++ == '/') | 160 | if (*pos++ != ' ' || *pos++ == '/') |
157 | continue; | 161 | continue; |
@@ -181,8 +185,10 @@ u8 tomoyo_parse_ulong(unsigned long *result, char **str) | |||
181 | const char *cp = *str; | 185 | const char *cp = *str; |
182 | char *ep; | 186 | char *ep; |
183 | int base = 10; | 187 | int base = 10; |
188 | |||
184 | if (*cp == '0') { | 189 | if (*cp == '0') { |
185 | char c = *(cp + 1); | 190 | char c = *(cp + 1); |
191 | |||
186 | if (c == 'x' || c == 'X') { | 192 | if (c == 'x' || c == 'X') { |
187 | base = 16; | 193 | base = 16; |
188 | cp += 2; | 194 | cp += 2; |
@@ -240,6 +246,7 @@ bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, | |||
240 | struct tomoyo_name_union *ptr) | 246 | struct tomoyo_name_union *ptr) |
241 | { | 247 | { |
242 | char *filename; | 248 | char *filename; |
249 | |||
243 | if (param->data[0] == '@') { | 250 | if (param->data[0] == '@') { |
244 | param->data++; | 251 | param->data++; |
245 | ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); | 252 | ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); |
@@ -266,6 +273,7 @@ bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, | |||
266 | char *data; | 273 | char *data; |
267 | u8 type; | 274 | u8 type; |
268 | unsigned long v; | 275 | unsigned long v; |
276 | |||
269 | memset(ptr, 0, sizeof(*ptr)); | 277 | memset(ptr, 0, sizeof(*ptr)); |
270 | if (param->data[0] == '@') { | 278 | if (param->data[0] == '@') { |
271 | param->data++; | 279 | param->data++; |
@@ -429,6 +437,7 @@ static bool tomoyo_correct_word2(const char *string, size_t len) | |||
429 | unsigned char c; | 437 | unsigned char c; |
430 | unsigned char d; | 438 | unsigned char d; |
431 | unsigned char e; | 439 | unsigned char e; |
440 | |||
432 | if (!len) | 441 | if (!len) |
433 | goto out; | 442 | goto out; |
434 | while (len--) { | 443 | while (len--) { |
@@ -533,6 +542,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname) | |||
533 | return true; | 542 | return true; |
534 | while (1) { | 543 | while (1) { |
535 | const unsigned char *cp = strchr(domainname, ' '); | 544 | const unsigned char *cp = strchr(domainname, ' '); |
545 | |||
536 | if (!cp) | 546 | if (!cp) |
537 | break; | 547 | break; |
538 | if (*domainname != '/' || | 548 | if (*domainname != '/' || |
@@ -554,6 +564,7 @@ bool tomoyo_domain_def(const unsigned char *buffer) | |||
554 | { | 564 | { |
555 | const unsigned char *cp; | 565 | const unsigned char *cp; |
556 | int len; | 566 | int len; |
567 | |||
557 | if (*buffer != '<') | 568 | if (*buffer != '<') |
558 | return false; | 569 | return false; |
559 | cp = strchr(buffer, ' '); | 570 | cp = strchr(buffer, ' '); |
@@ -668,6 +679,9 @@ static bool tomoyo_file_matches_pattern2(const char *filename, | |||
668 | { | 679 | { |
669 | while (filename < filename_end && pattern < pattern_end) { | 680 | while (filename < filename_end && pattern < pattern_end) { |
670 | char c; | 681 | char c; |
682 | int i; | ||
683 | int j; | ||
684 | |||
671 | if (*pattern != '\\') { | 685 | if (*pattern != '\\') { |
672 | if (*filename++ != *pattern++) | 686 | if (*filename++ != *pattern++) |
673 | return false; | 687 | return false; |
@@ -676,8 +690,6 @@ static bool tomoyo_file_matches_pattern2(const char *filename, | |||
676 | c = *filename; | 690 | c = *filename; |
677 | pattern++; | 691 | pattern++; |
678 | switch (*pattern) { | 692 | switch (*pattern) { |
679 | int i; | ||
680 | int j; | ||
681 | case '?': | 693 | case '?': |
682 | if (c == '/') { | 694 | if (c == '/') { |
683 | return false; | 695 | return false; |
@@ -985,6 +997,7 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, | |||
985 | struct tomoyo_domain_info *domain, const u8 index) | 997 | struct tomoyo_domain_info *domain, const u8 index) |
986 | { | 998 | { |
987 | u8 profile; | 999 | u8 profile; |
1000 | |||
988 | memset(r, 0, sizeof(*r)); | 1001 | memset(r, 0, sizeof(*r)); |
989 | if (!domain) | 1002 | if (!domain) |
990 | domain = tomoyo_domain(); | 1003 | domain = tomoyo_domain(); |
@@ -1018,6 +1031,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
1018 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 1031 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
1019 | u16 perm; | 1032 | u16 perm; |
1020 | u8 i; | 1033 | u8 i; |
1034 | |||
1021 | if (ptr->is_deleted) | 1035 | if (ptr->is_deleted) |
1022 | continue; | 1036 | continue; |
1023 | switch (ptr->type) { | 1037 | switch (ptr->type) { |
@@ -1062,9 +1076,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
1062 | domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; | 1076 | domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; |
1063 | /* r->granted = false; */ | 1077 | /* r->granted = false; */ |
1064 | tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); | 1078 | tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); |
1065 | printk(KERN_WARNING "WARNING: " | 1079 | pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n", |
1066 | "Domain '%s' has too many ACLs to hold. " | 1080 | domain->domainname->name); |
1067 | "Stopped learning mode.\n", domain->domainname->name); | ||
1068 | } | 1081 | } |
1069 | return false; | 1082 | return false; |
1070 | } | 1083 | } |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 02514fe558b4..57cc60722dd3 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -479,9 +479,15 @@ static void __init yama_init_sysctl(void) | |||
479 | static inline void yama_init_sysctl(void) { } | 479 | static inline void yama_init_sysctl(void) { } |
480 | #endif /* CONFIG_SYSCTL */ | 480 | #endif /* CONFIG_SYSCTL */ |
481 | 481 | ||
482 | void __init yama_add_hooks(void) | 482 | static int __init yama_init(void) |
483 | { | 483 | { |
484 | pr_info("Yama: becoming mindful.\n"); | 484 | pr_info("Yama: becoming mindful.\n"); |
485 | security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama"); | 485 | security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama"); |
486 | yama_init_sysctl(); | 486 | yama_init_sysctl(); |
487 | return 0; | ||
487 | } | 488 | } |
489 | |||
490 | DEFINE_LSM(yama) = { | ||
491 | .name = "yama", | ||
492 | .init = yama_init, | ||
493 | }; | ||
diff --git a/tools/testing/selftests/safesetid/.gitignore b/tools/testing/selftests/safesetid/.gitignore new file mode 100644 index 000000000000..9c1a629bca01 --- /dev/null +++ b/tools/testing/selftests/safesetid/.gitignore | |||
@@ -0,0 +1 @@ | |||
safesetid-test | |||
diff --git a/tools/testing/selftests/safesetid/Makefile b/tools/testing/selftests/safesetid/Makefile new file mode 100644 index 000000000000..98da7a504737 --- /dev/null +++ b/tools/testing/selftests/safesetid/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | # Makefile for mount selftests. | ||
3 | CFLAGS = -Wall -lcap -O2 | ||
4 | |||
5 | TEST_PROGS := run_tests.sh | ||
6 | TEST_GEN_FILES := safesetid-test | ||
7 | |||
8 | include ../lib.mk | ||
diff --git a/tools/testing/selftests/safesetid/config b/tools/testing/selftests/safesetid/config new file mode 100644 index 000000000000..9d44e5c2e096 --- /dev/null +++ b/tools/testing/selftests/safesetid/config | |||
@@ -0,0 +1,2 @@ | |||
1 | CONFIG_SECURITY=y | ||
2 | CONFIG_SECURITYFS=y | ||
diff --git a/tools/testing/selftests/safesetid/safesetid-test.c b/tools/testing/selftests/safesetid/safesetid-test.c new file mode 100644 index 000000000000..892c8e8b1b8b --- /dev/null +++ b/tools/testing/selftests/safesetid/safesetid-test.c | |||
@@ -0,0 +1,334 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #define _GNU_SOURCE | ||
3 | #include <stdio.h> | ||
4 | #include <errno.h> | ||
5 | #include <pwd.h> | ||
6 | #include <string.h> | ||
7 | #include <syscall.h> | ||
8 | #include <sys/capability.h> | ||
9 | #include <sys/types.h> | ||
10 | #include <sys/mount.h> | ||
11 | #include <sys/prctl.h> | ||
12 | #include <sys/wait.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <unistd.h> | ||
15 | #include <fcntl.h> | ||
16 | #include <stdbool.h> | ||
17 | #include <stdarg.h> | ||
18 | |||
19 | #ifndef CLONE_NEWUSER | ||
20 | # define CLONE_NEWUSER 0x10000000 | ||
21 | #endif | ||
22 | |||
23 | #define ROOT_USER 0 | ||
24 | #define RESTRICTED_PARENT 1 | ||
25 | #define ALLOWED_CHILD1 2 | ||
26 | #define ALLOWED_CHILD2 3 | ||
27 | #define NO_POLICY_USER 4 | ||
28 | |||
29 | char* add_whitelist_policy_file = "/sys/kernel/security/safesetid/add_whitelist_policy"; | ||
30 | |||
31 | static void die(char *fmt, ...) | ||
32 | { | ||
33 | va_list ap; | ||
34 | va_start(ap, fmt); | ||
35 | vfprintf(stderr, fmt, ap); | ||
36 | va_end(ap); | ||
37 | exit(EXIT_FAILURE); | ||
38 | } | ||
39 | |||
40 | static bool vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap) | ||
41 | { | ||
42 | char buf[4096]; | ||
43 | int fd; | ||
44 | ssize_t written; | ||
45 | int buf_len; | ||
46 | |||
47 | buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); | ||
48 | if (buf_len < 0) { | ||
49 | printf("vsnprintf failed: %s\n", | ||
50 | strerror(errno)); | ||
51 | return false; | ||
52 | } | ||
53 | if (buf_len >= sizeof(buf)) { | ||
54 | printf("vsnprintf output truncated\n"); | ||
55 | return false; | ||
56 | } | ||
57 | |||
58 | fd = open(filename, O_WRONLY); | ||
59 | if (fd < 0) { | ||
60 | if ((errno == ENOENT) && enoent_ok) | ||
61 | return true; | ||
62 | return false; | ||
63 | } | ||
64 | written = write(fd, buf, buf_len); | ||
65 | if (written != buf_len) { | ||
66 | if (written >= 0) { | ||
67 | printf("short write to %s\n", filename); | ||
68 | return false; | ||
69 | } else { | ||
70 | printf("write to %s failed: %s\n", | ||
71 | filename, strerror(errno)); | ||
72 | return false; | ||
73 | } | ||
74 | } | ||
75 | if (close(fd) != 0) { | ||
76 | printf("close of %s failed: %s\n", | ||
77 | filename, strerror(errno)); | ||
78 | return false; | ||
79 | } | ||
80 | return true; | ||
81 | } | ||
82 | |||
83 | static bool write_file(char *filename, char *fmt, ...) | ||
84 | { | ||
85 | va_list ap; | ||
86 | bool ret; | ||
87 | |||
88 | va_start(ap, fmt); | ||
89 | ret = vmaybe_write_file(false, filename, fmt, ap); | ||
90 | va_end(ap); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static void ensure_user_exists(uid_t uid) | ||
96 | { | ||
97 | struct passwd p; | ||
98 | |||
99 | FILE *fd; | ||
100 | char name_str[10]; | ||
101 | |||
102 | if (getpwuid(uid) == NULL) { | ||
103 | memset(&p,0x00,sizeof(p)); | ||
104 | fd=fopen("/etc/passwd","a"); | ||
105 | if (fd == NULL) | ||
106 | die("couldn't open file\n"); | ||
107 | if (fseek(fd, 0, SEEK_END)) | ||
108 | die("couldn't fseek\n"); | ||
109 | snprintf(name_str, 10, "%d", uid); | ||
110 | p.pw_name=name_str; | ||
111 | p.pw_uid=uid; | ||
112 | p.pw_gecos="Test account"; | ||
113 | p.pw_dir="/dev/null"; | ||
114 | p.pw_shell="/bin/false"; | ||
115 | int value = putpwent(&p,fd); | ||
116 | if (value != 0) | ||
117 | die("putpwent failed\n"); | ||
118 | if (fclose(fd)) | ||
119 | die("fclose failed\n"); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static void ensure_securityfs_mounted(void) | ||
124 | { | ||
125 | int fd = open(add_whitelist_policy_file, O_WRONLY); | ||
126 | if (fd < 0) { | ||
127 | if (errno == ENOENT) { | ||
128 | // Need to mount securityfs | ||
129 | if (mount("securityfs", "/sys/kernel/security", | ||
130 | "securityfs", 0, NULL) < 0) | ||
131 | die("mounting securityfs failed\n"); | ||
132 | } else { | ||
133 | die("couldn't find securityfs for unknown reason\n"); | ||
134 | } | ||
135 | } else { | ||
136 | if (close(fd) != 0) { | ||
137 | die("close of %s failed: %s\n", | ||
138 | add_whitelist_policy_file, strerror(errno)); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | |||
143 | static void write_policies(void) | ||
144 | { | ||
145 | ssize_t written; | ||
146 | int fd; | ||
147 | |||
148 | fd = open(add_whitelist_policy_file, O_WRONLY); | ||
149 | if (fd < 0) | ||
150 | die("cant open add_whitelist_policy file\n"); | ||
151 | written = write(fd, "1:2", strlen("1:2")); | ||
152 | if (written != strlen("1:2")) { | ||
153 | if (written >= 0) { | ||
154 | die("short write to %s\n", add_whitelist_policy_file); | ||
155 | } else { | ||
156 | die("write to %s failed: %s\n", | ||
157 | add_whitelist_policy_file, strerror(errno)); | ||
158 | } | ||
159 | } | ||
160 | written = write(fd, "1:3", strlen("1:3")); | ||
161 | if (written != strlen("1:3")) { | ||
162 | if (written >= 0) { | ||
163 | die("short write to %s\n", add_whitelist_policy_file); | ||
164 | } else { | ||
165 | die("write to %s failed: %s\n", | ||
166 | add_whitelist_policy_file, strerror(errno)); | ||
167 | } | ||
168 | } | ||
169 | if (close(fd) != 0) { | ||
170 | die("close of %s failed: %s\n", | ||
171 | add_whitelist_policy_file, strerror(errno)); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static bool test_userns(bool expect_success) | ||
176 | { | ||
177 | uid_t uid; | ||
178 | char map_file_name[32]; | ||
179 | size_t sz = sizeof(map_file_name); | ||
180 | pid_t cpid; | ||
181 | bool success; | ||
182 | |||
183 | uid = getuid(); | ||
184 | |||
185 | int clone_flags = CLONE_NEWUSER; | ||
186 | cpid = syscall(SYS_clone, clone_flags, NULL); | ||
187 | if (cpid == -1) { | ||
188 | printf("clone failed"); | ||
189 | return false; | ||
190 | } | ||
191 | |||
192 | if (cpid == 0) { /* Code executed by child */ | ||
193 | // Give parent 1 second to write map file | ||
194 | sleep(1); | ||
195 | exit(EXIT_SUCCESS); | ||
196 | } else { /* Code executed by parent */ | ||
197 | if(snprintf(map_file_name, sz, "/proc/%d/uid_map", cpid) < 0) { | ||
198 | printf("preparing file name string failed"); | ||
199 | return false; | ||
200 | } | ||
201 | success = write_file(map_file_name, "0 0 1", uid); | ||
202 | return success == expect_success; | ||
203 | } | ||
204 | |||
205 | printf("should not reach here"); | ||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static void test_setuid(uid_t child_uid, bool expect_success) | ||
210 | { | ||
211 | pid_t cpid, w; | ||
212 | int wstatus; | ||
213 | |||
214 | cpid = fork(); | ||
215 | if (cpid == -1) { | ||
216 | die("fork\n"); | ||
217 | } | ||
218 | |||
219 | if (cpid == 0) { /* Code executed by child */ | ||
220 | setuid(child_uid); | ||
221 | if (getuid() == child_uid) | ||
222 | exit(EXIT_SUCCESS); | ||
223 | else | ||
224 | exit(EXIT_FAILURE); | ||
225 | } else { /* Code executed by parent */ | ||
226 | do { | ||
227 | w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED); | ||
228 | if (w == -1) { | ||
229 | die("waitpid\n"); | ||
230 | } | ||
231 | |||
232 | if (WIFEXITED(wstatus)) { | ||
233 | if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) { | ||
234 | if (expect_success) { | ||
235 | return; | ||
236 | } else { | ||
237 | die("unexpected success\n"); | ||
238 | } | ||
239 | } else { | ||
240 | if (expect_success) { | ||
241 | die("unexpected failure\n"); | ||
242 | } else { | ||
243 | return; | ||
244 | } | ||
245 | } | ||
246 | } else if (WIFSIGNALED(wstatus)) { | ||
247 | if (WTERMSIG(wstatus) == 9) { | ||
248 | if (expect_success) | ||
249 | die("killed unexpectedly\n"); | ||
250 | else | ||
251 | return; | ||
252 | } else { | ||
253 | die("unexpected signal: %d\n", wstatus); | ||
254 | } | ||
255 | } else { | ||
256 | die("unexpected status: %d\n", wstatus); | ||
257 | } | ||
258 | } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus)); | ||
259 | } | ||
260 | |||
261 | die("should not reach here\n"); | ||
262 | } | ||
263 | |||
264 | static void ensure_users_exist(void) | ||
265 | { | ||
266 | ensure_user_exists(ROOT_USER); | ||
267 | ensure_user_exists(RESTRICTED_PARENT); | ||
268 | ensure_user_exists(ALLOWED_CHILD1); | ||
269 | ensure_user_exists(ALLOWED_CHILD2); | ||
270 | ensure_user_exists(NO_POLICY_USER); | ||
271 | } | ||
272 | |||
273 | static void drop_caps(bool setid_retained) | ||
274 | { | ||
275 | cap_value_t cap_values[] = {CAP_SETUID, CAP_SETGID}; | ||
276 | cap_t caps; | ||
277 | |||
278 | caps = cap_get_proc(); | ||
279 | if (setid_retained) | ||
280 | cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_values, CAP_SET); | ||
281 | else | ||
282 | cap_clear(caps); | ||
283 | cap_set_proc(caps); | ||
284 | cap_free(caps); | ||
285 | } | ||
286 | |||
287 | int main(int argc, char **argv) | ||
288 | { | ||
289 | ensure_users_exist(); | ||
290 | ensure_securityfs_mounted(); | ||
291 | write_policies(); | ||
292 | |||
293 | if (prctl(PR_SET_KEEPCAPS, 1L)) | ||
294 | die("Error with set keepcaps\n"); | ||
295 | |||
296 | // First test to make sure we can write userns mappings from a user | ||
297 | // that doesn't have any restrictions (as long as it has CAP_SETUID); | ||
298 | setuid(NO_POLICY_USER); | ||
299 | setgid(NO_POLICY_USER); | ||
300 | |||
301 | // Take away all but setid caps | ||
302 | drop_caps(true); | ||
303 | |||
304 | // Need PR_SET_DUMPABLE flag set so we can write /proc/[pid]/uid_map | ||
305 | // from non-root parent process. | ||
306 | if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) | ||
307 | die("Error with set dumpable\n"); | ||
308 | |||
309 | if (!test_userns(true)) { | ||
310 | die("test_userns failed when it should work\n"); | ||
311 | } | ||
312 | |||
313 | setuid(RESTRICTED_PARENT); | ||
314 | setgid(RESTRICTED_PARENT); | ||
315 | |||
316 | test_setuid(ROOT_USER, false); | ||
317 | test_setuid(ALLOWED_CHILD1, true); | ||
318 | test_setuid(ALLOWED_CHILD2, true); | ||
319 | test_setuid(NO_POLICY_USER, false); | ||
320 | |||
321 | if (!test_userns(false)) { | ||
322 | die("test_userns worked when it should fail\n"); | ||
323 | } | ||
324 | |||
325 | // Now take away all caps | ||
326 | drop_caps(false); | ||
327 | test_setuid(2, false); | ||
328 | test_setuid(3, false); | ||
329 | test_setuid(4, false); | ||
330 | |||
331 | // NOTE: this test doesn't clean up users that were created in | ||
332 | // /etc/passwd or flush policies that were added to the LSM. | ||
333 | return EXIT_SUCCESS; | ||
334 | } | ||
diff --git a/tools/testing/selftests/safesetid/safesetid-test.sh b/tools/testing/selftests/safesetid/safesetid-test.sh new file mode 100755 index 000000000000..e4fdce675c54 --- /dev/null +++ b/tools/testing/selftests/safesetid/safesetid-test.sh | |||
@@ -0,0 +1,26 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | TCID="safesetid-test.sh" | ||
4 | errcode=0 | ||
5 | |||
6 | # Kselftest framework requirement - SKIP code is 4. | ||
7 | ksft_skip=4 | ||
8 | |||
9 | check_root() | ||
10 | { | ||
11 | uid=$(id -u) | ||
12 | if [ $uid -ne 0 ]; then | ||
13 | echo $TCID: must be run as root >&2 | ||
14 | exit $ksft_skip | ||
15 | fi | ||
16 | } | ||
17 | |||
18 | main_function() | ||
19 | { | ||
20 | check_root | ||
21 | ./safesetid-test | ||
22 | } | ||
23 | |||
24 | main_function | ||
25 | echo "$TCID: done" | ||
26 | exit $errcode | ||