Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * security/tomoyo/realpath.c
0004  *
0005  * Copyright (C) 2005-2011  NTT DATA CORPORATION
0006  */
0007 
0008 #include "common.h"
0009 #include <linux/magic.h>
0010 #include <linux/proc_fs.h>
0011 
0012 /**
0013  * tomoyo_encode2 - Encode binary string to ascii string.
0014  *
0015  * @str:     String in binary format.
0016  * @str_len: Size of @str in byte.
0017  *
0018  * Returns pointer to @str in ascii format on success, NULL otherwise.
0019  *
0020  * This function uses kzalloc(), so caller must kfree() if this function
0021  * didn't return NULL.
0022  */
0023 char *tomoyo_encode2(const char *str, int str_len)
0024 {
0025     int i;
0026     int len = 0;
0027     const char *p = str;
0028     char *cp;
0029     char *cp0;
0030 
0031     if (!p)
0032         return NULL;
0033     for (i = 0; i < str_len; i++) {
0034         const unsigned char c = p[i];
0035 
0036         if (c == '\\')
0037             len += 2;
0038         else if (c > ' ' && c < 127)
0039             len++;
0040         else
0041             len += 4;
0042     }
0043     len++;
0044     /* Reserve space for appending "/". */
0045     cp = kzalloc(len + 10, GFP_NOFS);
0046     if (!cp)
0047         return NULL;
0048     cp0 = cp;
0049     p = str;
0050     for (i = 0; i < str_len; i++) {
0051         const unsigned char c = p[i];
0052 
0053         if (c == '\\') {
0054             *cp++ = '\\';
0055             *cp++ = '\\';
0056         } else if (c > ' ' && c < 127) {
0057             *cp++ = c;
0058         } else {
0059             *cp++ = '\\';
0060             *cp++ = (c >> 6) + '0';
0061             *cp++ = ((c >> 3) & 7) + '0';
0062             *cp++ = (c & 7) + '0';
0063         }
0064     }
0065     return cp0;
0066 }
0067 
0068 /**
0069  * tomoyo_encode - Encode binary string to ascii string.
0070  *
0071  * @str: String in binary format.
0072  *
0073  * Returns pointer to @str in ascii format on success, NULL otherwise.
0074  *
0075  * This function uses kzalloc(), so caller must kfree() if this function
0076  * didn't return NULL.
0077  */
0078 char *tomoyo_encode(const char *str)
0079 {
0080     return str ? tomoyo_encode2(str, strlen(str)) : NULL;
0081 }
0082 
0083 /**
0084  * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
0085  *
0086  * @path:   Pointer to "struct path".
0087  * @buffer: Pointer to buffer to return value in.
0088  * @buflen: Sizeof @buffer.
0089  *
0090  * Returns the buffer on success, an error code otherwise.
0091  *
0092  * If dentry is a directory, trailing '/' is appended.
0093  */
0094 static char *tomoyo_get_absolute_path(const struct path *path, char * const buffer,
0095                       const int buflen)
0096 {
0097     char *pos = ERR_PTR(-ENOMEM);
0098 
0099     if (buflen >= 256) {
0100         /* go to whatever namespace root we are under */
0101         pos = d_absolute_path(path, buffer, buflen - 1);
0102         if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
0103             struct inode *inode = d_backing_inode(path->dentry);
0104 
0105             if (inode && S_ISDIR(inode->i_mode)) {
0106                 buffer[buflen - 2] = '/';
0107                 buffer[buflen - 1] = '\0';
0108             }
0109         }
0110     }
0111     return pos;
0112 }
0113 
0114 /**
0115  * tomoyo_get_dentry_path - Get the path of a dentry.
0116  *
0117  * @dentry: Pointer to "struct dentry".
0118  * @buffer: Pointer to buffer to return value in.
0119  * @buflen: Sizeof @buffer.
0120  *
0121  * Returns the buffer on success, an error code otherwise.
0122  *
0123  * If dentry is a directory, trailing '/' is appended.
0124  */
0125 static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
0126                     const int buflen)
0127 {
0128     char *pos = ERR_PTR(-ENOMEM);
0129 
0130     if (buflen >= 256) {
0131         pos = dentry_path_raw(dentry, buffer, buflen - 1);
0132         if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
0133             struct inode *inode = d_backing_inode(dentry);
0134 
0135             if (inode && S_ISDIR(inode->i_mode)) {
0136                 buffer[buflen - 2] = '/';
0137                 buffer[buflen - 1] = '\0';
0138             }
0139         }
0140     }
0141     return pos;
0142 }
0143 
0144 /**
0145  * tomoyo_get_local_path - Get the path of a dentry.
0146  *
0147  * @dentry: Pointer to "struct dentry".
0148  * @buffer: Pointer to buffer to return value in.
0149  * @buflen: Sizeof @buffer.
0150  *
0151  * Returns the buffer on success, an error code otherwise.
0152  */
0153 static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
0154                    const int buflen)
0155 {
0156     struct super_block *sb = dentry->d_sb;
0157     char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
0158 
0159     if (IS_ERR(pos))
0160         return pos;
0161     /* Convert from $PID to self if $PID is current thread. */
0162     if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
0163         char *ep;
0164         const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
0165         struct pid_namespace *proc_pidns = proc_pid_ns(sb);
0166 
0167         if (*ep == '/' && pid && pid ==
0168             task_tgid_nr_ns(current, proc_pidns)) {
0169             pos = ep - 5;
0170             if (pos < buffer)
0171                 goto out;
0172             memmove(pos, "/self", 5);
0173         }
0174         goto prepend_filesystem_name;
0175     }
0176     /* Use filesystem name for unnamed devices. */
0177     if (!MAJOR(sb->s_dev))
0178         goto prepend_filesystem_name;
0179     {
0180         struct inode *inode = d_backing_inode(sb->s_root);
0181 
0182         /*
0183          * Use filesystem name if filesystem does not support rename()
0184          * operation.
0185          */
0186         if (!inode->i_op->rename)
0187             goto prepend_filesystem_name;
0188     }
0189     /* Prepend device name. */
0190     {
0191         char name[64];
0192         int name_len;
0193         const dev_t dev = sb->s_dev;
0194 
0195         name[sizeof(name) - 1] = '\0';
0196         snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
0197              MINOR(dev));
0198         name_len = strlen(name);
0199         pos -= name_len;
0200         if (pos < buffer)
0201             goto out;
0202         memmove(pos, name, name_len);
0203         return pos;
0204     }
0205     /* Prepend filesystem name. */
0206 prepend_filesystem_name:
0207     {
0208         const char *name = sb->s_type->name;
0209         const int name_len = strlen(name);
0210 
0211         pos -= name_len + 1;
0212         if (pos < buffer)
0213             goto out;
0214         memmove(pos, name, name_len);
0215         pos[name_len] = ':';
0216     }
0217     return pos;
0218 out:
0219     return ERR_PTR(-ENOMEM);
0220 }
0221 
0222 /**
0223  * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
0224  *
0225  * @path: Pointer to "struct path".
0226  *
0227  * Returns the realpath of the given @path on success, NULL otherwise.
0228  *
0229  * If dentry is a directory, trailing '/' is appended.
0230  * Characters out of 0x20 < c < 0x7F range are converted to
0231  * \ooo style octal string.
0232  * Character \ is converted to \\ string.
0233  *
0234  * These functions use kzalloc(), so the caller must call kfree()
0235  * if these functions didn't return NULL.
0236  */
0237 char *tomoyo_realpath_from_path(const struct path *path)
0238 {
0239     char *buf = NULL;
0240     char *name = NULL;
0241     unsigned int buf_len = PAGE_SIZE / 2;
0242     struct dentry *dentry = path->dentry;
0243     struct super_block *sb;
0244 
0245     if (!dentry)
0246         return NULL;
0247     sb = dentry->d_sb;
0248     while (1) {
0249         char *pos;
0250         struct inode *inode;
0251 
0252         buf_len <<= 1;
0253         kfree(buf);
0254         buf = kmalloc(buf_len, GFP_NOFS);
0255         if (!buf)
0256             break;
0257         /* To make sure that pos is '\0' terminated. */
0258         buf[buf_len - 1] = '\0';
0259         /* For "pipe:[\$]" and "socket:[\$]". */
0260         if (dentry->d_op && dentry->d_op->d_dname) {
0261             pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
0262             goto encode;
0263         }
0264         inode = d_backing_inode(sb->s_root);
0265         /*
0266          * Get local name for filesystems without rename() operation
0267          * or dentry without vfsmount.
0268          */
0269         if (!path->mnt ||
0270             (!inode->i_op->rename &&
0271              !(sb->s_type->fs_flags & FS_REQUIRES_DEV)))
0272             pos = tomoyo_get_local_path(path->dentry, buf,
0273                             buf_len - 1);
0274         /* Get absolute name for the rest. */
0275         else {
0276             pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
0277             /*
0278              * Fall back to local name if absolute name is not
0279              * available.
0280              */
0281             if (pos == ERR_PTR(-EINVAL))
0282                 pos = tomoyo_get_local_path(path->dentry, buf,
0283                                 buf_len - 1);
0284         }
0285 encode:
0286         if (IS_ERR(pos))
0287             continue;
0288         name = tomoyo_encode(pos);
0289         break;
0290     }
0291     kfree(buf);
0292     if (!name)
0293         tomoyo_warn_oom(__func__);
0294     return name;
0295 }
0296 
0297 /**
0298  * tomoyo_realpath_nofollow - Get realpath of a pathname.
0299  *
0300  * @pathname: The pathname to solve.
0301  *
0302  * Returns the realpath of @pathname on success, NULL otherwise.
0303  */
0304 char *tomoyo_realpath_nofollow(const char *pathname)
0305 {
0306     struct path path;
0307 
0308     if (pathname && kern_path(pathname, 0, &path) == 0) {
0309         char *buf = tomoyo_realpath_from_path(&path);
0310 
0311         path_put(&path);
0312         return buf;
0313     }
0314     return NULL;
0315 }