~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/tomoyo/realpath.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 10 /**
 11  * tomoyo_encode2 - Encode binary string to ascii string.
 12  *
 13  * @str:     String in binary format.
 14  * @str_len: Size of @str in byte.
 15  *
 16  * Returns pointer to @str in ascii format on success, NULL otherwise.
 17  *
 18  * This function uses kzalloc(), so caller must kfree() if this function
 19  * didn't return NULL.
 20  */
 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) + '';
 59                         *cp++ = ((c >> 3) & 7) + '';
 60                         *cp++ = (c & 7) + '';
 61                 }
 62         }
 63         return cp0;
 64 }
 65 
 66 /**
 67  * tomoyo_encode - Encode binary string to ascii string.
 68  *
 69  * @str: String in binary format.
 70  *
 71  * Returns pointer to @str in ascii format on success, NULL otherwise.
 72  *
 73  * This function uses kzalloc(), so caller must kfree() if this function
 74  * didn't return NULL.
 75  */
 76 char *tomoyo_encode(const char *str)
 77 {
 78         return str ? tomoyo_encode2(str, strlen(str)) : NULL;
 79 }
 80 
 81 /**
 82  * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
 83  *
 84  * @path:   Pointer to "struct path".
 85  * @buffer: Pointer to buffer to return value in.
 86  * @buflen: Sizeof @buffer.
 87  *
 88  * Returns the buffer on success, an error code otherwise.
 89  *
 90  * If dentry is a directory, trailing '/' is appended.
 91  */
 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 
110 /**
111  * tomoyo_get_dentry_path - Get the path of a dentry.
112  *
113  * @dentry: Pointer to "struct dentry".
114  * @buffer: Pointer to buffer to return value in.
115  * @buflen: Sizeof @buffer.
116  *
117  * Returns the buffer on success, an error code otherwise.
118  *
119  * If dentry is a directory, trailing '/' is appended.
120  */
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 
138 /**
139  * tomoyo_get_local_path - Get the path of a dentry.
140  *
141  * @dentry: Pointer to "struct dentry".
142  * @buffer: Pointer to buffer to return value in.
143  * @buflen: Sizeof @buffer.
144  *
145  * Returns the buffer on success, an error code otherwise.
146  */
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 ==
159                     task_tgid_nr_ns(current, sb->s_fs_info)) {
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 
210 /**
211  * tomoyo_get_socket_name - Get the name of a socket.
212  *
213  * @path:   Pointer to "struct path".
214  * @buffer: Pointer to buffer to return value in.
215  * @buflen: Sizeof @buffer.
216  *
217  * Returns the buffer.
218  */
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 
235 /**
236  * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
237  *
238  * @path: Pointer to "struct path".
239  *
240  * Returns the realpath of the given @path on success, NULL otherwise.
241  *
242  * If dentry is a directory, trailing '/' is appended.
243  * Characters out of 0x20 < c < 0x7F range are converted to
244  * \ooo style octal string.
245  * Character \ is converted to \\ string.
246  *
247  * These functions use kzalloc(), so the caller must call kfree()
248  * if these functions didn't return NULL.
249  */
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 
311 /**
312  * tomoyo_realpath_nofollow - Get realpath of a pathname.
313  *
314  * @pathname: The pathname to solve.
315  *
316  * Returns the realpath of @pathname on success, NULL otherwise.
317  */
318 char *tomoyo_realpath_nofollow(const char *pathname)
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 }
329 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp