Blame view

security/tomoyo/realpath.c 7.88 KB
c73bd6d47   Kentaro Takeda   Memory and pathna...
1
2
3
  /*
   * security/tomoyo/realpath.c
   *
0f2a55d5b   Tetsuo Handa   TOMOYO: Update ke...
4
   * Copyright (C) 2005-2011  NTT DATA CORPORATION
c73bd6d47   Kentaro Takeda   Memory and pathna...
5
   */
c73bd6d47   Kentaro Takeda   Memory and pathna...
6
  #include "common.h"
d10577a8d   Al Viro   vfs: trim include...
7
  #include <linux/magic.h>
c73bd6d47   Kentaro Takeda   Memory and pathna...
8
9
  
  /**
059d84dbb   Tetsuo Handa   TOMOYO: Add socke...
10
   * tomoyo_encode2 - Encode binary string to ascii string.
c73bd6d47   Kentaro Takeda   Memory and pathna...
11
   *
059d84dbb   Tetsuo Handa   TOMOYO: Add socke...
12
13
   * @str:     String in binary format.
   * @str_len: Size of @str in byte.
c73bd6d47   Kentaro Takeda   Memory and pathna...
14
   *
c8c57e842   Tetsuo Handa   TOMOYO: Support l...
15
16
17
18
   * Returns pointer to @str in ascii format on success, NULL otherwise.
   *
   * This function uses kzalloc(), so caller must kfree() if this function
   * didn't return NULL.
c73bd6d47   Kentaro Takeda   Memory and pathna...
19
   */
059d84dbb   Tetsuo Handa   TOMOYO: Add socke...
20
  char *tomoyo_encode2(const char *str, int str_len)
c73bd6d47   Kentaro Takeda   Memory and pathna...
21
  {
059d84dbb   Tetsuo Handa   TOMOYO: Add socke...
22
  	int i;
c8c57e842   Tetsuo Handa   TOMOYO: Support l...
23
24
25
26
  	int len = 0;
  	const char *p = str;
  	char *cp;
  	char *cp0;
c73bd6d47   Kentaro Takeda   Memory and pathna...
27

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

e24977d45   Al Viro   Reduce path_looku...
321
322
323
  	if (pathname && kern_path(pathname, 0, &path) == 0) {
  		char *buf = tomoyo_realpath_from_path(&path);
  		path_put(&path);
c73bd6d47   Kentaro Takeda   Memory and pathna...
324
325
326
327
  		return buf;
  	}
  	return NULL;
  }