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