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