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