Root/
1 | /* |
2 | * security/tomoyo/realpath.c |
3 | * |
4 | * Get the canonicalized absolute pathnames. The basis for TOMOYO. |
5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * |
8 | * Version: 2.2.0 2009/04/01 |
9 | * |
10 | */ |
11 | |
12 | #include <linux/types.h> |
13 | #include <linux/mount.h> |
14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> |
16 | #include <linux/hash.h> |
17 | #include <linux/magic.h> |
18 | #include <linux/slab.h> |
19 | #include "common.h" |
20 | |
21 | /** |
22 | * tomoyo_encode: Convert binary string to ascii string. |
23 | * |
24 | * @buffer: Buffer for ASCII string. |
25 | * @buflen: Size of @buffer. |
26 | * @str: Binary string. |
27 | * |
28 | * Returns 0 on success, -ENOMEM otherwise. |
29 | */ |
30 | int tomoyo_encode(char *buffer, int buflen, const char *str) |
31 | { |
32 | while (1) { |
33 | const unsigned char c = *(unsigned char *) str++; |
34 | |
35 | if (tomoyo_is_valid(c)) { |
36 | if (--buflen <= 0) |
37 | break; |
38 | *buffer++ = (char) c; |
39 | if (c != '\\') |
40 | continue; |
41 | if (--buflen <= 0) |
42 | break; |
43 | *buffer++ = (char) c; |
44 | continue; |
45 | } |
46 | if (!c) { |
47 | if (--buflen <= 0) |
48 | break; |
49 | *buffer = '\0'; |
50 | return 0; |
51 | } |
52 | buflen -= 4; |
53 | if (buflen <= 0) |
54 | break; |
55 | *buffer++ = '\\'; |
56 | *buffer++ = (c >> 6) + '0'; |
57 | *buffer++ = ((c >> 3) & 7) + '0'; |
58 | *buffer++ = (c & 7) + '0'; |
59 | } |
60 | return -ENOMEM; |
61 | } |
62 | |
63 | /** |
64 | * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root. |
65 | * |
66 | * @path: Pointer to "struct path". |
67 | * @newname: Pointer to buffer to return value in. |
68 | * @newname_len: Size of @newname. |
69 | * |
70 | * Returns 0 on success, negative value otherwise. |
71 | * |
72 | * If dentry is a directory, trailing '/' is appended. |
73 | * Characters out of 0x20 < c < 0x7F range are converted to |
74 | * \ooo style octal string. |
75 | * Character \ is converted to \\ string. |
76 | */ |
77 | int tomoyo_realpath_from_path2(struct path *path, char *newname, |
78 | int newname_len) |
79 | { |
80 | int error = -ENOMEM; |
81 | struct dentry *dentry = path->dentry; |
82 | char *sp; |
83 | |
84 | if (!dentry || !path->mnt || !newname || newname_len <= 2048) |
85 | return -EINVAL; |
86 | if (dentry->d_op && dentry->d_op->d_dname) { |
87 | /* For "socket:[\$]" and "pipe:[\$]". */ |
88 | static const int offset = 1536; |
89 | sp = dentry->d_op->d_dname(dentry, newname + offset, |
90 | newname_len - offset); |
91 | } else { |
92 | struct path ns_root = {.mnt = NULL, .dentry = NULL}; |
93 | |
94 | spin_lock(&dcache_lock); |
95 | /* go to whatever namespace root we are under */ |
96 | sp = __d_path(path, &ns_root, newname, newname_len); |
97 | spin_unlock(&dcache_lock); |
98 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ |
99 | if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) && |
100 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { |
101 | sp -= 5; |
102 | if (sp >= newname) |
103 | memcpy(sp, "/proc", 5); |
104 | else |
105 | sp = ERR_PTR(-ENOMEM); |
106 | } |
107 | } |
108 | if (IS_ERR(sp)) |
109 | error = PTR_ERR(sp); |
110 | else |
111 | error = tomoyo_encode(newname, sp - newname, sp); |
112 | /* Append trailing '/' if dentry is a directory. */ |
113 | if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) |
114 | && *newname) { |
115 | sp = newname + strlen(newname); |
116 | if (*(sp - 1) != '/') { |
117 | if (sp < newname + newname_len - 4) { |
118 | *sp++ = '/'; |
119 | *sp = '\0'; |
120 | } else { |
121 | error = -ENOMEM; |
122 | } |
123 | } |
124 | } |
125 | if (error) |
126 | printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); |
127 | return error; |
128 | } |
129 | |
130 | /** |
131 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. |
132 | * |
133 | * @path: Pointer to "struct path". |
134 | * |
135 | * Returns the realpath of the given @path on success, NULL otherwise. |
136 | * |
137 | * These functions use kzalloc(), so the caller must call kfree() |
138 | * if these functions didn't return NULL. |
139 | */ |
140 | char *tomoyo_realpath_from_path(struct path *path) |
141 | { |
142 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); |
143 | |
144 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
145 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
146 | if (!buf) |
147 | return NULL; |
148 | if (tomoyo_realpath_from_path2(path, buf, |
149 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) |
150 | return buf; |
151 | kfree(buf); |
152 | return NULL; |
153 | } |
154 | |
155 | /** |
156 | * tomoyo_realpath - Get realpath of a pathname. |
157 | * |
158 | * @pathname: The pathname to solve. |
159 | * |
160 | * Returns the realpath of @pathname on success, NULL otherwise. |
161 | */ |
162 | char *tomoyo_realpath(const char *pathname) |
163 | { |
164 | struct path path; |
165 | |
166 | if (pathname && kern_path(pathname, LOOKUP_FOLLOW, &path) == 0) { |
167 | char *buf = tomoyo_realpath_from_path(&path); |
168 | path_put(&path); |
169 | return buf; |
170 | } |
171 | return NULL; |
172 | } |
173 | |
174 | /** |
175 | * tomoyo_realpath_nofollow - Get realpath of a pathname. |
176 | * |
177 | * @pathname: The pathname to solve. |
178 | * |
179 | * Returns the realpath of @pathname on success, NULL otherwise. |
180 | */ |
181 | char *tomoyo_realpath_nofollow(const char *pathname) |
182 | { |
183 | struct path path; |
184 | |
185 | if (pathname && kern_path(pathname, 0, &path) == 0) { |
186 | char *buf = tomoyo_realpath_from_path(&path); |
187 | path_put(&path); |
188 | return buf; |
189 | } |
190 | return NULL; |
191 | } |
192 | |
193 | /* Memory allocated for non-string data. */ |
194 | static atomic_t tomoyo_policy_memory_size; |
195 | /* Quota for holding policy. */ |
196 | static unsigned int tomoyo_quota_for_policy; |
197 | |
198 | /** |
199 | * tomoyo_memory_ok - Check memory quota. |
200 | * |
201 | * @ptr: Pointer to allocated memory. |
202 | * |
203 | * Returns true on success, false otherwise. |
204 | * |
205 | * Caller holds tomoyo_policy_lock. |
206 | * Memory pointed by @ptr will be zeroed on success. |
207 | */ |
208 | bool tomoyo_memory_ok(void *ptr) |
209 | { |
210 | int allocated_len = ptr ? ksize(ptr) : 0; |
211 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
212 | if (ptr && (!tomoyo_quota_for_policy || |
213 | atomic_read(&tomoyo_policy_memory_size) |
214 | <= tomoyo_quota_for_policy)) { |
215 | memset(ptr, 0, allocated_len); |
216 | return true; |
217 | } |
218 | printk(KERN_WARNING "ERROR: Out of memory " |
219 | "for tomoyo_alloc_element().\n"); |
220 | if (!tomoyo_policy_loaded) |
221 | panic("MAC Initialization failed.\n"); |
222 | return false; |
223 | } |
224 | |
225 | /** |
226 | * tomoyo_memory_free - Free memory for elements. |
227 | * |
228 | * @ptr: Pointer to allocated memory. |
229 | */ |
230 | void tomoyo_memory_free(void *ptr) |
231 | { |
232 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); |
233 | kfree(ptr); |
234 | } |
235 | |
236 | /* |
237 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
238 | * Since same string data is likely used for multiple times (e.g. |
239 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
240 | * "const struct tomoyo_path_info *". |
241 | */ |
242 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
243 | /* Lock for protecting tomoyo_name_list . */ |
244 | DEFINE_MUTEX(tomoyo_name_list_lock); |
245 | |
246 | /** |
247 | * tomoyo_get_name - Allocate permanent memory for string data. |
248 | * |
249 | * @name: The string to store into the permernent memory. |
250 | * |
251 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
252 | */ |
253 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
254 | { |
255 | struct tomoyo_name_entry *ptr; |
256 | unsigned int hash; |
257 | int len; |
258 | int allocated_len; |
259 | struct list_head *head; |
260 | |
261 | if (!name) |
262 | return NULL; |
263 | len = strlen(name) + 1; |
264 | hash = full_name_hash((const unsigned char *) name, len - 1); |
265 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
266 | mutex_lock(&tomoyo_name_list_lock); |
267 | list_for_each_entry(ptr, head, list) { |
268 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
269 | continue; |
270 | atomic_inc(&ptr->users); |
271 | goto out; |
272 | } |
273 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); |
274 | allocated_len = ptr ? ksize(ptr) : 0; |
275 | if (!ptr || (tomoyo_quota_for_policy && |
276 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
277 | > tomoyo_quota_for_policy)) { |
278 | kfree(ptr); |
279 | printk(KERN_WARNING "ERROR: Out of memory " |
280 | "for tomoyo_get_name().\n"); |
281 | if (!tomoyo_policy_loaded) |
282 | panic("MAC Initialization failed.\n"); |
283 | ptr = NULL; |
284 | goto out; |
285 | } |
286 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
287 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
288 | memmove((char *) ptr->entry.name, name, len); |
289 | atomic_set(&ptr->users, 1); |
290 | tomoyo_fill_path_info(&ptr->entry); |
291 | list_add_tail(&ptr->list, head); |
292 | out: |
293 | mutex_unlock(&tomoyo_name_list_lock); |
294 | return ptr ? &ptr->entry : NULL; |
295 | } |
296 | |
297 | /** |
298 | * tomoyo_realpath_init - Initialize realpath related code. |
299 | */ |
300 | void __init tomoyo_realpath_init(void) |
301 | { |
302 | int i; |
303 | |
304 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); |
305 | for (i = 0; i < TOMOYO_MAX_HASH; i++) |
306 | INIT_LIST_HEAD(&tomoyo_name_list[i]); |
307 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
308 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); |
309 | /* |
310 | * tomoyo_read_lock() is not needed because this function is |
311 | * called before the first "delete" request. |
312 | */ |
313 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); |
314 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) |
315 | panic("Can't register tomoyo_kernel_domain"); |
316 | } |
317 | |
318 | /** |
319 | * tomoyo_read_memory_counter - Check for memory usage in bytes. |
320 | * |
321 | * @head: Pointer to "struct tomoyo_io_buffer". |
322 | * |
323 | * Returns memory usage. |
324 | */ |
325 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
326 | { |
327 | if (!head->read_eof) { |
328 | const unsigned int policy |
329 | = atomic_read(&tomoyo_policy_memory_size); |
330 | char buffer[64]; |
331 | |
332 | memset(buffer, 0, sizeof(buffer)); |
333 | if (tomoyo_quota_for_policy) |
334 | snprintf(buffer, sizeof(buffer) - 1, |
335 | " (Quota: %10u)", |
336 | tomoyo_quota_for_policy); |
337 | else |
338 | buffer[0] = '\0'; |
339 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); |
340 | tomoyo_io_printf(head, "Total: %10u\n", policy); |
341 | head->read_eof = true; |
342 | } |
343 | return 0; |
344 | } |
345 | |
346 | /** |
347 | * tomoyo_write_memory_quota - Set memory quota. |
348 | * |
349 | * @head: Pointer to "struct tomoyo_io_buffer". |
350 | * |
351 | * Returns 0. |
352 | */ |
353 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) |
354 | { |
355 | char *data = head->write_buf; |
356 | unsigned int size; |
357 | |
358 | if (sscanf(data, "Policy: %u", &size) == 1) |
359 | tomoyo_quota_for_policy = size; |
360 | return 0; |
361 | } |
362 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9