root/security/tomoyo/realpath.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tomoyo_encode2
  2. tomoyo_encode
  3. tomoyo_get_absolute_path
  4. tomoyo_get_dentry_path
  5. tomoyo_get_local_path
  6. tomoyo_realpath_from_path
  7. tomoyo_realpath_nofollow

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

/* [<][>][^][v][top][bottom][index][help] */