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