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