slub: fix a possible memleak in __slab_alloc()
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / security / tomoyo / realpath.c
blobd46922db0540b8185845ae5b2fdb52a8696eb361
1 /*
2 * security/tomoyo/realpath.c
4 * Copyright (C) 2005-2011 NTT DATA CORPORATION
5 */
7 #include <linux/types.h>
8 #include <linux/mount.h>
9 #include <linux/mnt_namespace.h>
10 #include <linux/fs_struct.h>
11 #include <linux/magic.h>
12 #include <linux/slab.h>
13 #include <net/sock.h>
14 #include "common.h"
15 #include "../../fs/internal.h"
17 /**
18 * tomoyo_encode: Convert binary string to ascii string.
20 * @str: String in binary format.
22 * Returns pointer to @str in ascii format on success, NULL otherwise.
24 * This function uses kzalloc(), so caller must kfree() if this function
25 * didn't return NULL.
27 char *tomoyo_encode(const char *str)
29 int len = 0;
30 const char *p = str;
31 char *cp;
32 char *cp0;
34 if (!p)
35 return NULL;
36 while (*p) {
37 const unsigned char c = *p++;
38 if (c == '\\')
39 len += 2;
40 else if (c > ' ' && c < 127)
41 len++;
42 else
43 len += 4;
45 len++;
46 /* Reserve space for appending "/". */
47 cp = kzalloc(len + 10, GFP_NOFS);
48 if (!cp)
49 return NULL;
50 cp0 = cp;
51 p = str;
52 while (*p) {
53 const unsigned char c = *p++;
55 if (c == '\\') {
56 *cp++ = '\\';
57 *cp++ = '\\';
58 } else if (c > ' ' && c < 127) {
59 *cp++ = c;
60 } else {
61 *cp++ = '\\';
62 *cp++ = (c >> 6) + '0';
63 *cp++ = ((c >> 3) & 7) + '0';
64 *cp++ = (c & 7) + '0';
67 return cp0;
70 /**
71 * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
73 * @path: Pointer to "struct path".
74 * @buffer: Pointer to buffer to return value in.
75 * @buflen: Sizeof @buffer.
77 * Returns the buffer on success, an error code otherwise.
79 * If dentry is a directory, trailing '/' is appended.
81 static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
82 const int buflen)
84 char *pos = ERR_PTR(-ENOMEM);
85 if (buflen >= 256) {
86 /* go to whatever namespace root we are under */
87 pos = d_absolute_path(path, buffer, buflen - 1);
88 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
89 struct inode *inode = path->dentry->d_inode;
90 if (inode && S_ISDIR(inode->i_mode)) {
91 buffer[buflen - 2] = '/';
92 buffer[buflen - 1] = '\0';
96 return pos;
99 /**
100 * tomoyo_get_dentry_path - Get the path of a dentry.
102 * @dentry: Pointer to "struct dentry".
103 * @buffer: Pointer to buffer to return value in.
104 * @buflen: Sizeof @buffer.
106 * Returns the buffer on success, an error code otherwise.
108 * If dentry is a directory, trailing '/' is appended.
110 static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
111 const int buflen)
113 char *pos = ERR_PTR(-ENOMEM);
114 if (buflen >= 256) {
115 pos = dentry_path_raw(dentry, buffer, buflen - 1);
116 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
117 struct inode *inode = dentry->d_inode;
118 if (inode && S_ISDIR(inode->i_mode)) {
119 buffer[buflen - 2] = '/';
120 buffer[buflen - 1] = '\0';
124 return pos;
128 * tomoyo_get_local_path - Get the path of a dentry.
130 * @dentry: Pointer to "struct dentry".
131 * @buffer: Pointer to buffer to return value in.
132 * @buflen: Sizeof @buffer.
134 * Returns the buffer on success, an error code otherwise.
136 static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
137 const int buflen)
139 struct super_block *sb = dentry->d_sb;
140 char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
141 if (IS_ERR(pos))
142 return pos;
143 /* Convert from $PID to self if $PID is current thread. */
144 if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
145 char *ep;
146 const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
147 if (*ep == '/' && pid && pid ==
148 task_tgid_nr_ns(current, sb->s_fs_info)) {
149 pos = ep - 5;
150 if (pos < buffer)
151 goto out;
152 memmove(pos, "/self", 5);
154 goto prepend_filesystem_name;
156 /* Use filesystem name for unnamed devices. */
157 if (!MAJOR(sb->s_dev))
158 goto prepend_filesystem_name;
160 struct inode *inode = sb->s_root->d_inode;
162 * Use filesystem name if filesystem does not support rename()
163 * operation.
165 if (inode->i_op && !inode->i_op->rename)
166 goto prepend_filesystem_name;
168 /* Prepend device name. */
170 char name[64];
171 int name_len;
172 const dev_t dev = sb->s_dev;
173 name[sizeof(name) - 1] = '\0';
174 snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
175 MINOR(dev));
176 name_len = strlen(name);
177 pos -= name_len;
178 if (pos < buffer)
179 goto out;
180 memmove(pos, name, name_len);
181 return pos;
183 /* Prepend filesystem name. */
184 prepend_filesystem_name:
186 const char *name = sb->s_type->name;
187 const int name_len = strlen(name);
188 pos -= name_len + 1;
189 if (pos < buffer)
190 goto out;
191 memmove(pos, name, name_len);
192 pos[name_len] = ':';
194 return pos;
195 out:
196 return ERR_PTR(-ENOMEM);
200 * tomoyo_get_socket_name - Get the name of a socket.
202 * @path: Pointer to "struct path".
203 * @buffer: Pointer to buffer to return value in.
204 * @buflen: Sizeof @buffer.
206 * Returns the buffer.
208 static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
209 const int buflen)
211 struct inode *inode = path->dentry->d_inode;
212 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
213 struct sock *sk = sock ? sock->sk : NULL;
214 if (sk) {
215 snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
216 "protocol=%u]", sk->sk_family, sk->sk_type,
217 sk->sk_protocol);
218 } else {
219 snprintf(buffer, buflen, "socket:[unknown]");
221 return buffer;
225 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
227 * @path: Pointer to "struct path".
229 * Returns the realpath of the given @path on success, NULL otherwise.
231 * If dentry is a directory, trailing '/' is appended.
232 * Characters out of 0x20 < c < 0x7F range are converted to
233 * \ooo style octal string.
234 * Character \ is converted to \\ string.
236 * These functions use kzalloc(), so the caller must call kfree()
237 * if these functions didn't return NULL.
239 char *tomoyo_realpath_from_path(struct path *path)
241 char *buf = NULL;
242 char *name = NULL;
243 unsigned int buf_len = PAGE_SIZE / 2;
244 struct dentry *dentry = path->dentry;
245 struct super_block *sb;
246 if (!dentry)
247 return NULL;
248 sb = dentry->d_sb;
249 while (1) {
250 char *pos;
251 struct inode *inode;
252 buf_len <<= 1;
253 kfree(buf);
254 buf = kmalloc(buf_len, GFP_NOFS);
255 if (!buf)
256 break;
257 /* To make sure that pos is '\0' terminated. */
258 buf[buf_len - 1] = '\0';
259 /* Get better name for socket. */
260 if (sb->s_magic == SOCKFS_MAGIC) {
261 pos = tomoyo_get_socket_name(path, buf, buf_len - 1);
262 goto encode;
264 /* For "pipe:[\$]". */
265 if (dentry->d_op && dentry->d_op->d_dname) {
266 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
267 goto encode;
269 inode = sb->s_root->d_inode;
271 * Get local name for filesystems without rename() operation
272 * or dentry without vfsmount.
274 if (!path->mnt || (inode->i_op && !inode->i_op->rename))
275 pos = tomoyo_get_local_path(path->dentry, buf,
276 buf_len - 1);
277 /* Get absolute name for the rest. */
278 else {
279 pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
281 * Fall back to local name if absolute name is not
282 * available.
284 if (pos == ERR_PTR(-EINVAL))
285 pos = tomoyo_get_local_path(path->dentry, buf,
286 buf_len - 1);
288 encode:
289 if (IS_ERR(pos))
290 continue;
291 name = tomoyo_encode(pos);
292 break;
294 kfree(buf);
295 if (!name)
296 tomoyo_warn_oom(__func__);
297 return name;
301 * tomoyo_realpath_nofollow - Get realpath of a pathname.
303 * @pathname: The pathname to solve.
305 * Returns the realpath of @pathname on success, NULL otherwise.
307 char *tomoyo_realpath_nofollow(const char *pathname)
309 struct path path;
311 if (pathname && kern_path(pathname, 0, &path) == 0) {
312 char *buf = tomoyo_realpath_from_path(&path);
313 path_put(&path);
314 return buf;
316 return NULL;