xref: /openbmc/linux/security/tomoyo/realpath.c (revision b8bb76713ec50df2f11efee386e16f93d51e1076)
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-pre   2009/02/01
9  *
10  */
11 
12 #include <linux/types.h>
13 #include <linux/mount.h>
14 #include <linux/mnt_namespace.h>
15 #include "common.h"
16 #include "realpath.h"
17 
18 /**
19  * tomoyo_encode: Convert binary string to ascii string.
20  *
21  * @buffer:  Buffer for ASCII string.
22  * @buflen:  Size of @buffer.
23  * @str:     Binary string.
24  *
25  * Returns 0 on success, -ENOMEM otherwise.
26  */
27 int tomoyo_encode(char *buffer, int buflen, const char *str)
28 {
29 	while (1) {
30 		const unsigned char c = *(unsigned char *) str++;
31 
32 		if (tomoyo_is_valid(c)) {
33 			if (--buflen <= 0)
34 				break;
35 			*buffer++ = (char) c;
36 			if (c != '\\')
37 				continue;
38 			if (--buflen <= 0)
39 				break;
40 			*buffer++ = (char) c;
41 			continue;
42 		}
43 		if (!c) {
44 			if (--buflen <= 0)
45 				break;
46 			*buffer = '\0';
47 			return 0;
48 		}
49 		buflen -= 4;
50 		if (buflen <= 0)
51 			break;
52 		*buffer++ = '\\';
53 		*buffer++ = (c >> 6) + '0';
54 		*buffer++ = ((c >> 3) & 7) + '0';
55 		*buffer++ = (c & 7) + '0';
56 	}
57 	return -ENOMEM;
58 }
59 
60 /**
61  * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
62  *
63  * @path:        Pointer to "struct path".
64  * @newname:     Pointer to buffer to return value in.
65  * @newname_len: Size of @newname.
66  *
67  * Returns 0 on success, negative value otherwise.
68  *
69  * If dentry is a directory, trailing '/' is appended.
70  * Characters out of 0x20 < c < 0x7F range are converted to
71  * \ooo style octal string.
72  * Character \ is converted to \\ string.
73  */
74 int tomoyo_realpath_from_path2(struct path *path, char *newname,
75 			       int newname_len)
76 {
77 	int error = -ENOMEM;
78 	struct dentry *dentry = path->dentry;
79 	char *sp;
80 
81 	if (!dentry || !path->mnt || !newname || newname_len <= 2048)
82 		return -EINVAL;
83 	if (dentry->d_op && dentry->d_op->d_dname) {
84 		/* For "socket:[\$]" and "pipe:[\$]". */
85 		static const int offset = 1536;
86 		sp = dentry->d_op->d_dname(dentry, newname + offset,
87 					   newname_len - offset);
88 	} else {
89 		/* Taken from d_namespace_path(). */
90 		struct path root;
91 		struct path ns_root = { };
92 		struct path tmp;
93 
94 		read_lock(&current->fs->lock);
95 		root = current->fs->root;
96 		path_get(&root);
97 		read_unlock(&current->fs->lock);
98 		spin_lock(&vfsmount_lock);
99 		if (root.mnt && root.mnt->mnt_ns)
100 			ns_root.mnt = mntget(root.mnt->mnt_ns->root);
101 		if (ns_root.mnt)
102 			ns_root.dentry = dget(ns_root.mnt->mnt_root);
103 		spin_unlock(&vfsmount_lock);
104 		spin_lock(&dcache_lock);
105 		tmp = ns_root;
106 		sp = __d_path(path, &tmp, newname, newname_len);
107 		spin_unlock(&dcache_lock);
108 		path_put(&root);
109 		path_put(&ns_root);
110 	}
111 	if (IS_ERR(sp))
112 		error = PTR_ERR(sp);
113 	else
114 		error = tomoyo_encode(newname, sp - newname, sp);
115 	/* Append trailing '/' if dentry is a directory. */
116 	if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
117 	    && *newname) {
118 		sp = newname + strlen(newname);
119 		if (*(sp - 1) != '/') {
120 			if (sp < newname + newname_len - 4) {
121 				*sp++ = '/';
122 				*sp = '\0';
123 			} else {
124 				error = -ENOMEM;
125 			}
126 		}
127 	}
128 	if (error)
129 		printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n");
130 	return error;
131 }
132 
133 /**
134  * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
135  *
136  * @path: Pointer to "struct path".
137  *
138  * Returns the realpath of the given @path on success, NULL otherwise.
139  *
140  * These functions use tomoyo_alloc(), so the caller must call tomoyo_free()
141  * if these functions didn't return NULL.
142  */
143 char *tomoyo_realpath_from_path(struct path *path)
144 {
145 	char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer));
146 
147 	BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
148 		     <= TOMOYO_MAX_PATHNAME_LEN - 1);
149 	if (!buf)
150 		return NULL;
151 	if (tomoyo_realpath_from_path2(path, buf,
152 				       TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
153 		return buf;
154 	tomoyo_free(buf);
155 	return NULL;
156 }
157 
158 /**
159  * tomoyo_realpath - Get realpath of a pathname.
160  *
161  * @pathname: The pathname to solve.
162  *
163  * Returns the realpath of @pathname on success, NULL otherwise.
164  */
165 char *tomoyo_realpath(const char *pathname)
166 {
167 	struct nameidata nd;
168 
169 	if (pathname && path_lookup(pathname, LOOKUP_FOLLOW, &nd) == 0) {
170 		char *buf = tomoyo_realpath_from_path(&nd.path);
171 		path_put(&nd.path);
172 		return buf;
173 	}
174 	return NULL;
175 }
176 
177 /**
178  * tomoyo_realpath_nofollow - Get realpath of a pathname.
179  *
180  * @pathname: The pathname to solve.
181  *
182  * Returns the realpath of @pathname on success, NULL otherwise.
183  */
184 char *tomoyo_realpath_nofollow(const char *pathname)
185 {
186 	struct nameidata nd;
187 
188 	if (pathname && path_lookup(pathname, 0, &nd) == 0) {
189 		char *buf = tomoyo_realpath_from_path(&nd.path);
190 		path_put(&nd.path);
191 		return buf;
192 	}
193 	return NULL;
194 }
195 
196 /* Memory allocated for non-string data. */
197 static unsigned int tomoyo_allocated_memory_for_elements;
198 /* Quota for holding non-string data. */
199 static unsigned int tomoyo_quota_for_elements;
200 
201 /**
202  * tomoyo_alloc_element - Allocate permanent memory for structures.
203  *
204  * @size: Size in bytes.
205  *
206  * Returns pointer to allocated memory on success, NULL otherwise.
207  *
208  * Memory has to be zeroed.
209  * The RAM is chunked, so NEVER try to kfree() the returned pointer.
210  */
211 void *tomoyo_alloc_element(const unsigned int size)
212 {
213 	static char *buf;
214 	static DEFINE_MUTEX(lock);
215 	static unsigned int buf_used_len = PATH_MAX;
216 	char *ptr = NULL;
217 	/*Assumes sizeof(void *) >= sizeof(long) is true. */
218 	const unsigned int word_aligned_size
219 		= roundup(size, max(sizeof(void *), sizeof(long)));
220 	if (word_aligned_size > PATH_MAX)
221 		return NULL;
222 	/***** EXCLUSIVE SECTION START *****/
223 	mutex_lock(&lock);
224 	if (buf_used_len + word_aligned_size > PATH_MAX) {
225 		if (!tomoyo_quota_for_elements ||
226 		    tomoyo_allocated_memory_for_elements
227 		    + PATH_MAX <= tomoyo_quota_for_elements)
228 			ptr = kzalloc(PATH_MAX, GFP_KERNEL);
229 		if (!ptr) {
230 			printk(KERN_WARNING "ERROR: Out of memory "
231 			       "for tomoyo_alloc_element().\n");
232 			if (!tomoyo_policy_loaded)
233 				panic("MAC Initialization failed.\n");
234 		} else {
235 			buf = ptr;
236 			tomoyo_allocated_memory_for_elements += PATH_MAX;
237 			buf_used_len = word_aligned_size;
238 			ptr = buf;
239 		}
240 	} else if (word_aligned_size) {
241 		int i;
242 		ptr = buf + buf_used_len;
243 		buf_used_len += word_aligned_size;
244 		for (i = 0; i < word_aligned_size; i++) {
245 			if (!ptr[i])
246 				continue;
247 			printk(KERN_ERR "WARNING: Reserved memory was tainted! "
248 			       "The system might go wrong.\n");
249 			ptr[i] = '\0';
250 		}
251 	}
252 	mutex_unlock(&lock);
253 	/***** EXCLUSIVE SECTION END *****/
254 	return ptr;
255 }
256 
257 /* Memory allocated for string data in bytes. */
258 static unsigned int tomoyo_allocated_memory_for_savename;
259 /* Quota for holding string data in bytes. */
260 static unsigned int tomoyo_quota_for_savename;
261 
262 /*
263  * TOMOYO uses this hash only when appending a string into the string
264  * table. Frequency of appending strings is very low. So we don't need
265  * large (e.g. 64k) hash size. 256 will be sufficient.
266  */
267 #define TOMOYO_MAX_HASH 256
268 
269 /* Structure for string data. */
270 struct tomoyo_name_entry {
271 	struct list_head list;
272 	struct tomoyo_path_info entry;
273 };
274 
275 /* Structure for available memory region. */
276 struct tomoyo_free_memory_block_list {
277 	struct list_head list;
278 	char *ptr;             /* Pointer to a free area. */
279 	int len;               /* Length of the area.     */
280 };
281 
282 /*
283  * The list for "struct tomoyo_name_entry".
284  *
285  * This list is updated only inside tomoyo_save_name(), thus
286  * no global mutex exists.
287  */
288 static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
289 
290 /**
291  * tomoyo_save_name - Allocate permanent memory for string data.
292  *
293  * @name: The string to store into the permernent memory.
294  *
295  * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
296  *
297  * The RAM is shared, so NEVER try to modify or kfree() the returned name.
298  */
299 const struct tomoyo_path_info *tomoyo_save_name(const char *name)
300 {
301 	static LIST_HEAD(fmb_list);
302 	static DEFINE_MUTEX(lock);
303 	struct tomoyo_name_entry *ptr;
304 	unsigned int hash;
305 	/* fmb contains available size in bytes.
306 	   fmb is removed from the fmb_list when fmb->len becomes 0. */
307 	struct tomoyo_free_memory_block_list *fmb;
308 	int len;
309 	char *cp;
310 
311 	if (!name)
312 		return NULL;
313 	len = strlen(name) + 1;
314 	if (len > TOMOYO_MAX_PATHNAME_LEN) {
315 		printk(KERN_WARNING "ERROR: Name too long "
316 		       "for tomoyo_save_name().\n");
317 		return NULL;
318 	}
319 	hash = full_name_hash((const unsigned char *) name, len - 1);
320 	/***** EXCLUSIVE SECTION START *****/
321 	mutex_lock(&lock);
322 	list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
323 			     list) {
324 		if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
325 			goto out;
326 	}
327 	list_for_each_entry(fmb, &fmb_list, list) {
328 		if (len <= fmb->len)
329 			goto ready;
330 	}
331 	if (!tomoyo_quota_for_savename ||
332 	    tomoyo_allocated_memory_for_savename + PATH_MAX
333 	    <= tomoyo_quota_for_savename)
334 		cp = kzalloc(PATH_MAX, GFP_KERNEL);
335 	else
336 		cp = NULL;
337 	fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
338 	if (!cp || !fmb) {
339 		kfree(cp);
340 		kfree(fmb);
341 		printk(KERN_WARNING "ERROR: Out of memory "
342 		       "for tomoyo_save_name().\n");
343 		if (!tomoyo_policy_loaded)
344 			panic("MAC Initialization failed.\n");
345 		ptr = NULL;
346 		goto out;
347 	}
348 	tomoyo_allocated_memory_for_savename += PATH_MAX;
349 	list_add(&fmb->list, &fmb_list);
350 	fmb->ptr = cp;
351 	fmb->len = PATH_MAX;
352  ready:
353 	ptr = tomoyo_alloc_element(sizeof(*ptr));
354 	if (!ptr)
355 		goto out;
356 	ptr->entry.name = fmb->ptr;
357 	memmove(fmb->ptr, name, len);
358 	tomoyo_fill_path_info(&ptr->entry);
359 	fmb->ptr += len;
360 	fmb->len -= len;
361 	list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
362 	if (fmb->len == 0) {
363 		list_del(&fmb->list);
364 		kfree(fmb);
365 	}
366  out:
367 	mutex_unlock(&lock);
368 	/***** EXCLUSIVE SECTION END *****/
369 	return ptr ? &ptr->entry : NULL;
370 }
371 
372 /**
373  * tomoyo_realpath_init - Initialize realpath related code.
374  */
375 void __init tomoyo_realpath_init(void)
376 {
377 	int i;
378 
379 	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
380 	for (i = 0; i < TOMOYO_MAX_HASH; i++)
381 		INIT_LIST_HEAD(&tomoyo_name_list[i]);
382 	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
383 	tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
384 	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
385 	down_read(&tomoyo_domain_list_lock);
386 	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
387 		panic("Can't register tomoyo_kernel_domain");
388 	up_read(&tomoyo_domain_list_lock);
389 }
390 
391 /* Memory allocated for temporary purpose. */
392 static atomic_t tomoyo_dynamic_memory_size;
393 
394 /**
395  * tomoyo_alloc - Allocate memory for temporary purpose.
396  *
397  * @size: Size in bytes.
398  *
399  * Returns pointer to allocated memory on success, NULL otherwise.
400  */
401 void *tomoyo_alloc(const size_t size)
402 {
403 	void *p = kzalloc(size, GFP_KERNEL);
404 	if (p)
405 		atomic_add(ksize(p), &tomoyo_dynamic_memory_size);
406 	return p;
407 }
408 
409 /**
410  * tomoyo_free - Release memory allocated by tomoyo_alloc().
411  *
412  * @p: Pointer returned by tomoyo_alloc(). May be NULL.
413  *
414  * Returns nothing.
415  */
416 void tomoyo_free(const void *p)
417 {
418 	if (p) {
419 		atomic_sub(ksize(p), &tomoyo_dynamic_memory_size);
420 		kfree(p);
421 	}
422 }
423 
424 /**
425  * tomoyo_read_memory_counter - Check for memory usage in bytes.
426  *
427  * @head: Pointer to "struct tomoyo_io_buffer".
428  *
429  * Returns memory usage.
430  */
431 int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
432 {
433 	if (!head->read_eof) {
434 		const unsigned int shared
435 			= tomoyo_allocated_memory_for_savename;
436 		const unsigned int private
437 			= tomoyo_allocated_memory_for_elements;
438 		const unsigned int dynamic
439 			= atomic_read(&tomoyo_dynamic_memory_size);
440 		char buffer[64];
441 
442 		memset(buffer, 0, sizeof(buffer));
443 		if (tomoyo_quota_for_savename)
444 			snprintf(buffer, sizeof(buffer) - 1,
445 				 "   (Quota: %10u)",
446 				 tomoyo_quota_for_savename);
447 		else
448 			buffer[0] = '\0';
449 		tomoyo_io_printf(head, "Shared:  %10u%s\n", shared, buffer);
450 		if (tomoyo_quota_for_elements)
451 			snprintf(buffer, sizeof(buffer) - 1,
452 				 "   (Quota: %10u)",
453 				 tomoyo_quota_for_elements);
454 		else
455 			buffer[0] = '\0';
456 		tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer);
457 		tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic);
458 		tomoyo_io_printf(head, "Total:   %10u\n",
459 				 shared + private + dynamic);
460 		head->read_eof = true;
461 	}
462 	return 0;
463 }
464 
465 /**
466  * tomoyo_write_memory_quota - Set memory quota.
467  *
468  * @head: Pointer to "struct tomoyo_io_buffer".
469  *
470  * Returns 0.
471  */
472 int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
473 {
474 	char *data = head->write_buf;
475 	unsigned int size;
476 
477 	if (sscanf(data, "Shared: %u", &size) == 1)
478 		tomoyo_quota_for_savename = size;
479 	else if (sscanf(data, "Private: %u", &size) == 1)
480 		tomoyo_quota_for_elements = size;
481 	return 0;
482 }
483