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