1 |
/* |
2 |
* fs/tomoyo_capability.c |
3 |
* |
4 |
* Implementation of the Domain-Based Mandatory Access Control. |
5 |
* |
6 |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 |
* |
8 |
* Version: 1.7.0-pre 2009/07/03 |
9 |
* |
10 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
11 |
* See README.ccs for ChangeLog. |
12 |
* |
13 |
*/ |
14 |
|
15 |
#include <linux/ccs_common.h> |
16 |
#include <linux/tomoyo.h> |
17 |
|
18 |
/** |
19 |
* ccs_cap2name - Convert capability operation to capability message. |
20 |
* |
21 |
* @operation: Type of operation. |
22 |
* |
23 |
* Returns the name of capability. |
24 |
*/ |
25 |
static const char *ccs_cap2name(const u8 operation) |
26 |
{ |
27 |
static const char *ccs_capability_name[CCS_MAX_CAPABILITY_INDEX] = { |
28 |
[CCS_INET_STREAM_SOCKET_CREATE] = |
29 |
"socket(PF_INET, SOCK_STREAM)", |
30 |
[CCS_INET_STREAM_SOCKET_LISTEN] = |
31 |
"listen(PF_INET, SOCK_STREAM)", |
32 |
[CCS_INET_STREAM_SOCKET_CONNECT] = |
33 |
"connect(PF_INET, SOCK_STREAM)", |
34 |
[CCS_USE_INET_DGRAM_SOCKET] = |
35 |
"socket(PF_INET, SOCK_DGRAM)", |
36 |
[CCS_USE_INET_RAW_SOCKET] = |
37 |
"socket(PF_INET, SOCK_RAW)", |
38 |
[CCS_USE_ROUTE_SOCKET] = "socket(PF_ROUTE)", |
39 |
[CCS_USE_PACKET_SOCKET] = "socket(PF_PACKET)", |
40 |
[CCS_SYS_MOUNT] = "sys_mount()", |
41 |
[CCS_SYS_UMOUNT] = "sys_umount()", |
42 |
[CCS_SYS_REBOOT] = "sys_reboot()", |
43 |
[CCS_SYS_CHROOT] = "sys_chroot()", |
44 |
[CCS_SYS_KILL] = "sys_kill()", |
45 |
[CCS_SYS_VHANGUP] = "sys_vhangup()", |
46 |
[CCS_SYS_SETTIME] = "sys_settimeofday()", |
47 |
[CCS_SYS_NICE] = "sys_nice()", |
48 |
[CCS_SYS_SETHOSTNAME] = "sys_sethostname()", |
49 |
[CCS_USE_KERNEL_MODULE] = "kernel_module", |
50 |
[CCS_CREATE_FIFO] = "mknod(FIFO)", |
51 |
[CCS_CREATE_BLOCK_DEV] = "mknod(BDEV)", |
52 |
[CCS_CREATE_CHAR_DEV] = "mknod(CDEV)", |
53 |
[CCS_CREATE_UNIX_SOCKET] = "mknod(SOCKET)", |
54 |
[CCS_SYS_LINK] = "sys_link()", |
55 |
[CCS_SYS_SYMLINK] = "sys_symlink()", |
56 |
[CCS_SYS_RENAME] = "sys_rename()", |
57 |
[CCS_SYS_UNLINK] = "sys_unlink()", |
58 |
[CCS_SYS_CHMOD] = "sys_chmod()", |
59 |
[CCS_SYS_CHOWN] = "sys_chown()", |
60 |
[CCS_SYS_IOCTL] = "sys_ioctl()", |
61 |
[CCS_SYS_KEXEC_LOAD] = "sys_kexec_load()", |
62 |
[CCS_SYS_PIVOT_ROOT] = "sys_pivot_root()", |
63 |
[CCS_SYS_PTRACE] = "sys_ptrace()", |
64 |
[CCS_CONCEAL_MOUNT] = "conceal-mount", |
65 |
}; |
66 |
if (operation < CCS_MAX_CAPABILITY_INDEX) |
67 |
return ccs_capability_name[operation]; |
68 |
return NULL; |
69 |
} |
70 |
|
71 |
/** |
72 |
* ccs_audit_capability_log - Audit capability log. |
73 |
* |
74 |
* @r: Pointer to "struct ccs_request_info". |
75 |
* @operation: Type of operation. |
76 |
* @is_granted: True if this is a granted log. |
77 |
* |
78 |
* Returns 0 on success, negative value otherwise. |
79 |
*/ |
80 |
static int ccs_audit_capability_log(struct ccs_request_info *r, |
81 |
const u8 operation, const bool is_granted) |
82 |
{ |
83 |
return ccs_write_audit_log(is_granted, r, KEYWORD_ALLOW_CAPABILITY |
84 |
"%s\n", ccs_cap2keyword(operation)); |
85 |
} |
86 |
|
87 |
/** |
88 |
* ccs_update_capability_acl - Update "struct ccs_capability_acl_record" list. |
89 |
* |
90 |
* @operation: Type of operation. |
91 |
* @domain: Pointer to "struct ccs_domain_info". |
92 |
* @condition: Pointer to "struct ccs_condition". May be NULL. |
93 |
* @is_delete: True if it is a delete request. |
94 |
* |
95 |
* Returns 0 on success, negative value otherwise. |
96 |
*/ |
97 |
static int ccs_update_capability_acl(const u8 operation, |
98 |
struct ccs_domain_info *domain, |
99 |
struct ccs_condition *condition, |
100 |
const bool is_delete) |
101 |
{ |
102 |
struct ccs_capability_acl_record *entry = NULL; |
103 |
struct ccs_acl_info *ptr; |
104 |
int error = is_delete ? -ENOENT : -ENOMEM; |
105 |
if (!domain) |
106 |
return -EINVAL; |
107 |
if (is_delete) |
108 |
goto delete; |
109 |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
110 |
mutex_lock(&ccs_policy_lock); |
111 |
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
112 |
struct ccs_capability_acl_record *acl; |
113 |
if (ccs_acl_type1(ptr) != TYPE_CAPABILITY_ACL) |
114 |
continue; |
115 |
if (ptr->cond != condition) |
116 |
continue; |
117 |
acl = container_of(ptr, struct ccs_capability_acl_record, head); |
118 |
if (acl->operation != operation) |
119 |
continue; |
120 |
error = ccs_add_domain_acl(NULL, ptr); |
121 |
break; |
122 |
} |
123 |
if (error && ccs_memory_ok(entry, sizeof(*entry))) { |
124 |
entry->head.type = TYPE_CAPABILITY_ACL; |
125 |
entry->head.cond = condition; |
126 |
entry->operation = operation; |
127 |
error = ccs_add_domain_acl(domain, &entry->head); |
128 |
entry = NULL; |
129 |
} |
130 |
mutex_unlock(&ccs_policy_lock); |
131 |
goto out; |
132 |
delete: |
133 |
mutex_lock(&ccs_policy_lock); |
134 |
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
135 |
struct ccs_capability_acl_record *acl; |
136 |
if (ccs_acl_type2(ptr) != TYPE_CAPABILITY_ACL) |
137 |
continue; |
138 |
if (ptr->cond != condition) |
139 |
continue; |
140 |
acl = container_of(ptr, struct ccs_capability_acl_record, head); |
141 |
if (acl->operation != operation) |
142 |
continue; |
143 |
error = ccs_del_domain_acl(ptr); |
144 |
break; |
145 |
} |
146 |
mutex_unlock(&ccs_policy_lock); |
147 |
out: |
148 |
kfree(entry); |
149 |
return error; |
150 |
} |
151 |
|
152 |
/** |
153 |
* ccs_capable - Check permission for capability. |
154 |
* |
155 |
* @operation: Type of operation. |
156 |
* |
157 |
* Returns true on success, false otherwise. |
158 |
* |
159 |
* Caller holds srcu_read_lock(&ccs_ss). |
160 |
*/ |
161 |
static bool ccs_capable2(const u8 operation) |
162 |
{ |
163 |
struct ccs_request_info r; |
164 |
struct ccs_acl_info *ptr; |
165 |
bool is_enforce; |
166 |
bool found = false; |
167 |
if (!ccs_can_sleep()) |
168 |
return true; |
169 |
ccs_init_request_info(&r, NULL, CCS_MAX_CONTROL_INDEX + operation); |
170 |
is_enforce = (r.mode == 3); |
171 |
if (!r.mode) |
172 |
return true; |
173 |
retry: |
174 |
list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) { |
175 |
struct ccs_capability_acl_record *acl; |
176 |
if (ccs_acl_type2(ptr) != TYPE_CAPABILITY_ACL) |
177 |
continue; |
178 |
acl = container_of(ptr, struct ccs_capability_acl_record, head); |
179 |
if (acl->operation != operation || |
180 |
!ccs_check_condition(&r, ptr)) |
181 |
continue; |
182 |
r.cond = ptr->cond; |
183 |
found = true; |
184 |
break; |
185 |
} |
186 |
ccs_audit_capability_log(&r, operation, found); |
187 |
if (found) |
188 |
return true; |
189 |
if (ccs_verbose_mode(r.domain)) |
190 |
printk(KERN_WARNING "TOMOYO-%s: %s denied for %s\n", |
191 |
ccs_get_msg(is_enforce), ccs_cap2name(operation), |
192 |
ccs_get_last_name(r.domain)); |
193 |
if (is_enforce) { |
194 |
int error = ccs_check_supervisor(&r, KEYWORD_ALLOW_CAPABILITY |
195 |
"%s\n", |
196 |
ccs_cap2keyword(operation)); |
197 |
if (error == 1) |
198 |
goto retry; |
199 |
return !error; |
200 |
} |
201 |
if (r.mode == 1 && ccs_domain_quota_ok(r.domain)) { |
202 |
struct ccs_condition *cond = ccs_handler_cond(); |
203 |
ccs_update_capability_acl(operation, r.domain, cond, false); |
204 |
ccs_put_condition(cond); |
205 |
} |
206 |
return true; |
207 |
} |
208 |
|
209 |
/** |
210 |
* ccs_capable - Check permission for capability. |
211 |
* |
212 |
* @operation: Type of operation. |
213 |
* |
214 |
* Returns true on success, false otherwise. |
215 |
* |
216 |
* Caller holds srcu_read_lock(&ccs_ss). |
217 |
*/ |
218 |
bool ccs_capable(const u8 operation) |
219 |
{ |
220 |
const int idx = srcu_read_lock(&ccs_ss); |
221 |
const int error = ccs_capable2(operation); |
222 |
srcu_read_unlock(&ccs_ss, idx); |
223 |
return error; |
224 |
} |
225 |
EXPORT_SYMBOL(ccs_capable); /* for net/unix/af_unix.c */ |
226 |
|
227 |
/** |
228 |
* ccs_write_capability_policy - Write "struct ccs_capability_acl_record" list. |
229 |
* |
230 |
* @data: String to parse. |
231 |
* @domain: Pointer to "struct ccs_domain_info". |
232 |
* @condition: Pointer to "struct ccs_condition". May be NULL. |
233 |
* @is_delete: True if it is a delete request. |
234 |
* |
235 |
* Returns 0 on success, negative value otherwise. |
236 |
*/ |
237 |
int ccs_write_capability_policy(char *data, struct ccs_domain_info *domain, |
238 |
struct ccs_condition *condition, |
239 |
const bool is_delete) |
240 |
{ |
241 |
u8 capability; |
242 |
for (capability = 0; capability < CCS_MAX_CAPABILITY_INDEX; |
243 |
capability++) { |
244 |
if (strcmp(data, ccs_cap2keyword(capability))) |
245 |
continue; |
246 |
return ccs_update_capability_acl(capability, domain, condition, |
247 |
is_delete); |
248 |
} |
249 |
return -EINVAL; |
250 |
} |