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