linux/security/tomoyo/realpath.c
<<
>>
Prefs
   1/*
   2 * security/tomoyo/realpath.c
   3 *
   4 * Pathname calculation functions for TOMOYO.
   5 *
   6 * Copyright (C) 2005-2010  NTT DATA CORPORATION
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/mount.h>
  11#include <linux/mnt_namespace.h>
  12#include <linux/fs_struct.h>
  13#include <linux/magic.h>
  14#include <linux/slab.h>
  15#include <net/sock.h>
  16#include "common.h"
  17
  18/**
  19 * tomoyo_encode: Convert binary string to ascii string.
  20 *
  21 * @str: String in binary format.
  22 *
  23 * Returns pointer to @str in ascii format on success, NULL otherwise.
  24 *
  25 * This function uses kzalloc(), so caller must kfree() if this function
  26 * didn't return NULL.
  27 */
  28char *tomoyo_encode(const char *str)
  29{
  30        int len = 0;
  31        const char *p = str;
  32        char *cp;
  33        char *cp0;
  34
  35        if (!p)
  36                return NULL;
  37        while (*p) {
  38                const unsigned char c = *p++;
  39                if (c == '\\')
  40                        len += 2;
  41                else if (c > ' ' && c < 127)
  42                        len++;
  43                else
  44                        len += 4;
  45        }
  46        len++;
  47        /* Reserve space for appending "/". */
  48        cp = kzalloc(len + 10, GFP_NOFS);
  49        if (!cp)
  50                return NULL;
  51        cp0 = cp;
  52        p = str;
  53        while (*p) {
  54                const unsigned char c = *p++;
  55
  56                if (c == '\\') {
  57                        *cp++ = '\\';
  58                        *cp++ = '\\';
  59                } else if (c > ' ' && c < 127) {
  60                        *cp++ = c;
  61                } else {
  62                        *cp++ = '\\';
  63                        *cp++ = (c >> 6) + '0';
  64                        *cp++ = ((c >> 3) & 7) + '0';
  65                        *cp++ = (c & 7) + '0';
  66                }
  67        }
  68        return cp0;
  69}
  70
  71/**
  72 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
  73 *
  74 * @path: Pointer to "struct path".
  75 *
  76 * Returns the realpath of the given @path on success, NULL otherwise.
  77 *
  78 * If dentry is a directory, trailing '/' is appended.
  79 * Characters out of 0x20 < c < 0x7F range are converted to
  80 * \ooo style octal string.
  81 * Character \ is converted to \\ string.
  82 *
  83 * These functions use kzalloc(), so the caller must call kfree()
  84 * if these functions didn't return NULL.
  85 */
  86char *tomoyo_realpath_from_path(struct path *path)
  87{
  88        char *buf = NULL;
  89        char *name = NULL;
  90        unsigned int buf_len = PAGE_SIZE / 2;
  91        struct dentry *dentry = path->dentry;
  92        bool is_dir;
  93        if (!dentry)
  94                return NULL;
  95        is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
  96        while (1) {
  97                struct path ns_root = { .mnt = NULL, .dentry = NULL };
  98                char *pos;
  99                buf_len <<= 1;
 100                kfree(buf);
 101                buf = kmalloc(buf_len, GFP_NOFS);
 102                if (!buf)
 103                        break;
 104                /* Get better name for socket. */
 105                if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
 106                        struct inode *inode = dentry->d_inode;
 107                        struct socket *sock = inode ? SOCKET_I(inode) : NULL;
 108                        struct sock *sk = sock ? sock->sk : NULL;
 109                        if (sk) {
 110                                snprintf(buf, buf_len - 1, "socket:[family=%u:"
 111                                         "type=%u:protocol=%u]", sk->sk_family,
 112                                         sk->sk_type, sk->sk_protocol);
 113                        } else {
 114                                snprintf(buf, buf_len - 1, "socket:[unknown]");
 115                        }
 116                        name = tomoyo_encode(buf);
 117                        break;
 118                }
 119                /* For "socket:[\$]" and "pipe:[\$]". */
 120                if (dentry->d_op && dentry->d_op->d_dname) {
 121                        pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
 122                        if (IS_ERR(pos))
 123                                continue;
 124                        name = tomoyo_encode(pos);
 125                        break;
 126                }
 127                /* If we don't have a vfsmount, we can't calculate. */
 128                if (!path->mnt)
 129                        break;
 130                /* go to whatever namespace root we are under */
 131                pos = __d_path(path, &ns_root, buf, buf_len);
 132                /* Prepend "/proc" prefix if using internal proc vfs mount. */
 133                if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
 134                    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
 135                        pos -= 5;
 136                        if (pos >= buf)
 137                                memcpy(pos, "/proc", 5);
 138                        else
 139                                pos = ERR_PTR(-ENOMEM);
 140                }
 141                if (IS_ERR(pos))
 142                        continue;
 143                name = tomoyo_encode(pos);
 144                break;
 145        }
 146        kfree(buf);
 147        if (!name)
 148                tomoyo_warn_oom(__func__);
 149        else if (is_dir && *name) {
 150                /* Append trailing '/' if dentry is a directory. */
 151                char *pos = name + strlen(name) - 1;
 152                if (*pos != '/')
 153                        /*
 154                         * This is OK because tomoyo_encode() reserves space
 155                         * for appending "/".
 156                         */
 157                        *++pos = '/';
 158        }
 159        return name;
 160}
 161
 162/**
 163 * tomoyo_realpath_nofollow - Get realpath of a pathname.
 164 *
 165 * @pathname: The pathname to solve.
 166 *
 167 * Returns the realpath of @pathname on success, NULL otherwise.
 168 */
 169char *tomoyo_realpath_nofollow(const char *pathname)
 170{
 171        struct path path;
 172
 173        if (pathname && kern_path(pathname, 0, &path) == 0) {
 174                char *buf = tomoyo_realpath_from_path(&path);
 175                path_put(&path);
 176                return buf;
 177        }
 178        return NULL;
 179}
 180
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.