Merge branch 'for-next' of master.kernel.org:/pub/scm/linux/kernel/git/balbi/usb...
[zen-stable.git] / security / tomoyo / realpath.c
blobd1e05b0477154447ce7cb75dcdb3cb8e2ed94259
1 /*
2 * security/tomoyo/realpath.c
4 * Pathname calculation functions for TOMOYO.
6 * Copyright (C) 2005-2010 NTT DATA CORPORATION
7 */
9 #include <linux/types.h>
10 #include <linux/mount.h>
11 #include <linux/mnt_namespace.h>
12 #include <linux/fs_struct.h>
13 #include <linux/magic.h>
14 #include <linux/slab.h>
15 #include <net/sock.h>
16 #include "common.h"
17 #include "../../fs/internal.h"
19 /**
20 * tomoyo_encode: Convert binary string to ascii string.
22 * @str: String in binary format.
24 * Returns pointer to @str in ascii format on success, NULL otherwise.
26 * This function uses kzalloc(), so caller must kfree() if this function
27 * didn't return NULL.
29 char *tomoyo_encode(const char *str)
31 int len = 0;
32 const char *p = str;
33 char *cp;
34 char *cp0;
36 if (!p)
37 return NULL;
38 while (*p) {
39 const unsigned char c = *p++;
40 if (c == '\\')
41 len += 2;
42 else if (c > ' ' && c < 127)
43 len++;
44 else
45 len += 4;
47 len++;
48 /* Reserve space for appending "/". */
49 cp = kzalloc(len + 10, GFP_NOFS);
50 if (!cp)
51 return NULL;
52 cp0 = cp;
53 p = str;
54 while (*p) {
55 const unsigned char c = *p++;
57 if (c == '\\') {
58 *cp++ = '\\';
59 *cp++ = '\\';
60 } else if (c > ' ' && c < 127) {
61 *cp++ = c;
62 } else {
63 *cp++ = '\\';
64 *cp++ = (c >> 6) + '0';
65 *cp++ = ((c >> 3) & 7) + '0';
66 *cp++ = (c & 7) + '0';
69 return cp0;
72 /**
73 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
75 * @path: Pointer to "struct path".
77 * Returns the realpath of the given @path on success, NULL otherwise.
79 * If dentry is a directory, trailing '/' is appended.
80 * Characters out of 0x20 < c < 0x7F range are converted to
81 * \ooo style octal string.
82 * Character \ is converted to \\ string.
84 * These functions use kzalloc(), so the caller must call kfree()
85 * if these functions didn't return NULL.
87 char *tomoyo_realpath_from_path(struct path *path)
89 char *buf = NULL;
90 char *name = NULL;
91 unsigned int buf_len = PAGE_SIZE / 2;
92 struct dentry *dentry = path->dentry;
93 bool is_dir;
94 if (!dentry)
95 return NULL;
96 is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
97 while (1) {
98 struct path ns_root = { .mnt = NULL, .dentry = NULL };
99 char *pos;
100 buf_len <<= 1;
101 kfree(buf);
102 buf = kmalloc(buf_len, GFP_NOFS);
103 if (!buf)
104 break;
105 /* Get better name for socket. */
106 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
107 struct inode *inode = dentry->d_inode;
108 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
109 struct sock *sk = sock ? sock->sk : NULL;
110 if (sk) {
111 snprintf(buf, buf_len - 1, "socket:[family=%u:"
112 "type=%u:protocol=%u]", sk->sk_family,
113 sk->sk_type, sk->sk_protocol);
114 } else {
115 snprintf(buf, buf_len - 1, "socket:[unknown]");
117 name = tomoyo_encode(buf);
118 break;
120 /* For "socket:[\$]" and "pipe:[\$]". */
121 if (dentry->d_op && dentry->d_op->d_dname) {
122 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
123 if (IS_ERR(pos))
124 continue;
125 name = tomoyo_encode(pos);
126 break;
128 /* If we don't have a vfsmount, we can't calculate. */
129 if (!path->mnt)
130 break;
131 /* go to whatever namespace root we are under */
132 pos = __d_path(path, &ns_root, buf, buf_len);
133 /* Prepend "/proc" prefix if using internal proc vfs mount. */
134 if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
135 (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
136 pos -= 5;
137 if (pos >= buf)
138 memcpy(pos, "/proc", 5);
139 else
140 pos = ERR_PTR(-ENOMEM);
142 if (IS_ERR(pos))
143 continue;
144 name = tomoyo_encode(pos);
145 break;
147 kfree(buf);
148 if (!name)
149 tomoyo_warn_oom(__func__);
150 else if (is_dir && *name) {
151 /* Append trailing '/' if dentry is a directory. */
152 char *pos = name + strlen(name) - 1;
153 if (*pos != '/')
155 * This is OK because tomoyo_encode() reserves space
156 * for appending "/".
158 *++pos = '/';
160 return name;
164 * tomoyo_realpath_nofollow - Get realpath of a pathname.
166 * @pathname: The pathname to solve.
168 * Returns the realpath of @pathname on success, NULL otherwise.
170 char *tomoyo_realpath_nofollow(const char *pathname)
172 struct path path;
174 if (pathname && kern_path(pathname, 0, &path) == 0) {
175 char *buf = tomoyo_realpath_from_path(&path);
176 path_put(&path);
177 return buf;
179 return NULL;