Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
realpath.c
Go to the documentation of this file.
1 /*
2  * security/tomoyo/realpath.c
3  *
4  * Copyright (C) 2005-2011 NTT DATA CORPORATION
5  */
6 
7 #include "common.h"
8 #include <linux/magic.h>
9 
21 char *tomoyo_encode2(const char *str, int str_len)
22 {
23  int i;
24  int len = 0;
25  const char *p = str;
26  char *cp;
27  char *cp0;
28 
29  if (!p)
30  return NULL;
31  for (i = 0; i < str_len; i++) {
32  const unsigned char c = p[i];
33 
34  if (c == '\\')
35  len += 2;
36  else if (c > ' ' && c < 127)
37  len++;
38  else
39  len += 4;
40  }
41  len++;
42  /* Reserve space for appending "/". */
43  cp = kzalloc(len + 10, GFP_NOFS);
44  if (!cp)
45  return NULL;
46  cp0 = cp;
47  p = str;
48  for (i = 0; i < str_len; i++) {
49  const unsigned char c = p[i];
50 
51  if (c == '\\') {
52  *cp++ = '\\';
53  *cp++ = '\\';
54  } else if (c > ' ' && c < 127) {
55  *cp++ = c;
56  } else {
57  *cp++ = '\\';
58  *cp++ = (c >> 6) + '0';
59  *cp++ = ((c >> 3) & 7) + '0';
60  *cp++ = (c & 7) + '0';
61  }
62  }
63  return cp0;
64 }
65 
76 char *tomoyo_encode(const char *str)
77 {
78  return str ? tomoyo_encode2(str, strlen(str)) : NULL;
79 }
80 
92 static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
93  const int buflen)
94 {
95  char *pos = ERR_PTR(-ENOMEM);
96  if (buflen >= 256) {
97  /* go to whatever namespace root we are under */
98  pos = d_absolute_path(path, buffer, buflen - 1);
99  if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
100  struct inode *inode = path->dentry->d_inode;
101  if (inode && S_ISDIR(inode->i_mode)) {
102  buffer[buflen - 2] = '/';
103  buffer[buflen - 1] = '\0';
104  }
105  }
106  }
107  return pos;
108 }
109 
121 static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
122  const int buflen)
123 {
124  char *pos = ERR_PTR(-ENOMEM);
125  if (buflen >= 256) {
126  pos = dentry_path_raw(dentry, buffer, buflen - 1);
127  if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
128  struct inode *inode = dentry->d_inode;
129  if (inode && S_ISDIR(inode->i_mode)) {
130  buffer[buflen - 2] = '/';
131  buffer[buflen - 1] = '\0';
132  }
133  }
134  }
135  return pos;
136 }
137 
147 static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
148  const int buflen)
149 {
150  struct super_block *sb = dentry->d_sb;
151  char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
152  if (IS_ERR(pos))
153  return pos;
154  /* Convert from $PID to self if $PID is current thread. */
155  if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
156  char *ep;
157  const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
158  if (*ep == '/' && pid && pid ==
160  pos = ep - 5;
161  if (pos < buffer)
162  goto out;
163  memmove(pos, "/self", 5);
164  }
165  goto prepend_filesystem_name;
166  }
167  /* Use filesystem name for unnamed devices. */
168  if (!MAJOR(sb->s_dev))
169  goto prepend_filesystem_name;
170  {
171  struct inode *inode = sb->s_root->d_inode;
172  /*
173  * Use filesystem name if filesystem does not support rename()
174  * operation.
175  */
176  if (inode->i_op && !inode->i_op->rename)
177  goto prepend_filesystem_name;
178  }
179  /* Prepend device name. */
180  {
181  char name[64];
182  int name_len;
183  const dev_t dev = sb->s_dev;
184  name[sizeof(name) - 1] = '\0';
185  snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
186  MINOR(dev));
187  name_len = strlen(name);
188  pos -= name_len;
189  if (pos < buffer)
190  goto out;
191  memmove(pos, name, name_len);
192  return pos;
193  }
194  /* Prepend filesystem name. */
195 prepend_filesystem_name:
196  {
197  const char *name = sb->s_type->name;
198  const int name_len = strlen(name);
199  pos -= name_len + 1;
200  if (pos < buffer)
201  goto out;
202  memmove(pos, name, name_len);
203  pos[name_len] = ':';
204  }
205  return pos;
206 out:
207  return ERR_PTR(-ENOMEM);
208 }
209 
219 static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
220  const int buflen)
221 {
222  struct inode *inode = path->dentry->d_inode;
223  struct socket *sock = inode ? SOCKET_I(inode) : NULL;
224  struct sock *sk = sock ? sock->sk : NULL;
225  if (sk) {
226  snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
227  "protocol=%u]", sk->sk_family, sk->sk_type,
228  sk->sk_protocol);
229  } else {
230  snprintf(buffer, buflen, "socket:[unknown]");
231  }
232  return buffer;
233 }
234 
250 char *tomoyo_realpath_from_path(struct path *path)
251 {
252  char *buf = NULL;
253  char *name = NULL;
254  unsigned int buf_len = PAGE_SIZE / 2;
255  struct dentry *dentry = path->dentry;
256  struct super_block *sb;
257  if (!dentry)
258  return NULL;
259  sb = dentry->d_sb;
260  while (1) {
261  char *pos;
262  struct inode *inode;
263  buf_len <<= 1;
264  kfree(buf);
265  buf = kmalloc(buf_len, GFP_NOFS);
266  if (!buf)
267  break;
268  /* To make sure that pos is '\0' terminated. */
269  buf[buf_len - 1] = '\0';
270  /* Get better name for socket. */
271  if (sb->s_magic == SOCKFS_MAGIC) {
272  pos = tomoyo_get_socket_name(path, buf, buf_len - 1);
273  goto encode;
274  }
275  /* For "pipe:[\$]". */
276  if (dentry->d_op && dentry->d_op->d_dname) {
277  pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
278  goto encode;
279  }
280  inode = sb->s_root->d_inode;
281  /*
282  * Get local name for filesystems without rename() operation
283  * or dentry without vfsmount.
284  */
285  if (!path->mnt || (inode->i_op && !inode->i_op->rename))
286  pos = tomoyo_get_local_path(path->dentry, buf,
287  buf_len - 1);
288  /* Get absolute name for the rest. */
289  else {
290  pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
291  /*
292  * Fall back to local name if absolute name is not
293  * available.
294  */
295  if (pos == ERR_PTR(-EINVAL))
296  pos = tomoyo_get_local_path(path->dentry, buf,
297  buf_len - 1);
298  }
299 encode:
300  if (IS_ERR(pos))
301  continue;
302  name = tomoyo_encode(pos);
303  break;
304  }
305  kfree(buf);
306  if (!name)
307  tomoyo_warn_oom(__func__);
308  return name;
309 }
310 
319 {
320  struct path path;
321 
322  if (pathname && kern_path(pathname, 0, &path) == 0) {
323  char *buf = tomoyo_realpath_from_path(&path);
324  path_put(&path);
325  return buf;
326  }
327  return NULL;
328 }