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