aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo/realpath.c
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-06-26 10:20:23 -0400
committerJames Morris <jmorris@namei.org>2011-06-28 19:31:21 -0400
commit5625f2e3266319fd29fe4f1c76ccd3f550c79ac4 (patch)
tree190e96d956213b22da705872094ebdf5272af972 /security/tomoyo/realpath.c
parentbd03a3e4c9a9df0c6b007045fa7fc8889111a478 (diff)
TOMOYO: Change pathname for non-rename()able filesystems.
TOMOYO wants to use /proc/self/ rather than /proc/$PID/ if $PID matches current thread's process ID in order to prevent current thread from accessing other process's information unless needed. But since procfs can be mounted on various locations (e.g. /proc/ /proc2/ /p/ /tmp/foo/100/p/ ), TOMOYO cannot tell that whether the numeric part in the string returned by __d_path() represents process ID or not. Therefore, to be able to convert from $PID to self no matter where procfs is mounted, this patch changes pathname representations for filesystems which do not support rename() operation (e.g. proc, sysfs, securityfs). Examples: /proc/self/mounts => proc:/self/mounts /sys/kernel/security/ => sys:/kernel/security/ /dev/pts/0 => devpts:/0 Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/realpath.c')
-rw-r--r--security/tomoyo/realpath.c222
1 files changed, 177 insertions, 45 deletions
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index d1e05b047715..1a785777118b 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -70,6 +70,161 @@ char *tomoyo_encode(const char *str)
70} 70}
71 71
72/** 72/**
73 * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
74 *
75 * @path: Pointer to "struct path".
76 * @buffer: Pointer to buffer to return value in.
77 * @buflen: Sizeof @buffer.
78 *
79 * Returns the buffer on success, an error code otherwise.
80 *
81 * If dentry is a directory, trailing '/' is appended.
82 */
83static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
84 const int buflen)
85{
86 char *pos = ERR_PTR(-ENOMEM);
87 if (buflen >= 256) {
88 struct path ns_root = { };
89 /* go to whatever namespace root we are under */
90 pos = __d_path(path, &ns_root, buffer, buflen - 1);
91 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
92 struct inode *inode = path->dentry->d_inode;
93 if (inode && S_ISDIR(inode->i_mode)) {
94 buffer[buflen - 2] = '/';
95 buffer[buflen - 1] = '\0';
96 }
97 }
98 }
99 return pos;
100}
101
102/**
103 * tomoyo_get_dentry_path - Get the path of a dentry.
104 *
105 * @dentry: Pointer to "struct dentry".
106 * @buffer: Pointer to buffer to return value in.
107 * @buflen: Sizeof @buffer.
108 *
109 * Returns the buffer on success, an error code otherwise.
110 *
111 * If dentry is a directory, trailing '/' is appended.
112 */
113static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
114 const int buflen)
115{
116 char *pos = ERR_PTR(-ENOMEM);
117 if (buflen >= 256) {
118 pos = dentry_path_raw(dentry, buffer, buflen - 1);
119 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
120 struct inode *inode = dentry->d_inode;
121 if (inode && S_ISDIR(inode->i_mode)) {
122 buffer[buflen - 2] = '/';
123 buffer[buflen - 1] = '\0';
124 }
125 }
126 }
127 return pos;
128}
129
130/**
131 * tomoyo_get_local_path - Get the path of a dentry.
132 *
133 * @dentry: Pointer to "struct dentry".
134 * @buffer: Pointer to buffer to return value in.
135 * @buflen: Sizeof @buffer.
136 *
137 * Returns the buffer on success, an error code otherwise.
138 */
139static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
140 const int buflen)
141{
142 struct super_block *sb = dentry->d_sb;
143 char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
144 if (IS_ERR(pos))
145 return pos;
146 /* Convert from $PID to self if $PID is current thread. */
147 if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
148 char *ep;
149 const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
150 if (*ep == '/' && pid && pid ==
151 task_tgid_nr_ns(current, sb->s_fs_info)) {
152 pos = ep - 5;
153 if (pos < buffer)
154 goto out;
155 memmove(pos, "/self", 5);
156 }
157 goto prepend_filesystem_name;
158 }
159 /* Use filesystem name for unnamed devices. */
160 if (!MAJOR(sb->s_dev))
161 goto prepend_filesystem_name;
162 {
163 struct inode *inode = sb->s_root->d_inode;
164 /*
165 * Use filesystem name if filesystem does not support rename()
166 * operation.
167 */
168 if (inode->i_op && !inode->i_op->rename)
169 goto prepend_filesystem_name;
170 }
171 /* Prepend device name. */
172 {
173 char name[64];
174 int name_len;
175 const dev_t dev = sb->s_dev;
176 name[sizeof(name) - 1] = '\0';
177 snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
178 MINOR(dev));
179 name_len = strlen(name);
180 pos -= name_len;
181 if (pos < buffer)
182 goto out;
183 memmove(pos, name, name_len);
184 return pos;
185 }
186 /* Prepend filesystem name. */
187prepend_filesystem_name:
188 {
189 const char *name = sb->s_type->name;
190 const int name_len = strlen(name);
191 pos -= name_len + 1;
192 if (pos < buffer)
193 goto out;
194 memmove(pos, name, name_len);
195 pos[name_len] = ':';
196 }
197 return pos;
198out:
199 return ERR_PTR(-ENOMEM);
200}
201
202/**
203 * tomoyo_get_socket_name - Get the name of a socket.
204 *
205 * @path: Pointer to "struct path".
206 * @buffer: Pointer to buffer to return value in.
207 * @buflen: Sizeof @buffer.
208 *
209 * Returns the buffer.
210 */
211static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
212 const int buflen)
213{
214 struct inode *inode = path->dentry->d_inode;
215 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
216 struct sock *sk = sock ? sock->sk : NULL;
217 if (sk) {
218 snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
219 "protocol=%u]", sk->sk_family, sk->sk_type,
220 sk->sk_protocol);
221 } else {
222 snprintf(buffer, buflen, "socket:[unknown]");
223 }
224 return buffer;
225}
226
227/**
73 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. 228 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
74 * 229 *
75 * @path: Pointer to "struct path". 230 * @path: Pointer to "struct path".
@@ -90,55 +245,42 @@ char *tomoyo_realpath_from_path(struct path *path)
90 char *name = NULL; 245 char *name = NULL;
91 unsigned int buf_len = PAGE_SIZE / 2; 246 unsigned int buf_len = PAGE_SIZE / 2;
92 struct dentry *dentry = path->dentry; 247 struct dentry *dentry = path->dentry;
93 bool is_dir; 248 struct super_block *sb;
94 if (!dentry) 249 if (!dentry)
95 return NULL; 250 return NULL;
96 is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode); 251 sb = dentry->d_sb;
97 while (1) { 252 while (1) {
98 struct path ns_root = { .mnt = NULL, .dentry = NULL };
99 char *pos; 253 char *pos;
254 struct inode *inode;
100 buf_len <<= 1; 255 buf_len <<= 1;
101 kfree(buf); 256 kfree(buf);
102 buf = kmalloc(buf_len, GFP_NOFS); 257 buf = kmalloc(buf_len, GFP_NOFS);
103 if (!buf) 258 if (!buf)
104 break; 259 break;
260 /* To make sure that pos is '\0' terminated. */
261 buf[buf_len - 1] = '\0';
105 /* Get better name for socket. */ 262 /* Get better name for socket. */
106 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) { 263 if (sb->s_magic == SOCKFS_MAGIC) {
107 struct inode *inode = dentry->d_inode; 264 pos = tomoyo_get_socket_name(path, buf, buf_len - 1);
108 struct socket *sock = inode ? SOCKET_I(inode) : NULL; 265 goto encode;
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]");
116 }
117 name = tomoyo_encode(buf);
118 break;
119 } 266 }
120 /* For "socket:[\$]" and "pipe:[\$]". */ 267 /* For "pipe:[\$]". */
121 if (dentry->d_op && dentry->d_op->d_dname) { 268 if (dentry->d_op && dentry->d_op->d_dname) {
122 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); 269 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
123 if (IS_ERR(pos)) 270 goto encode;
124 continue;
125 name = tomoyo_encode(pos);
126 break;
127 }
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);
141 } 271 }
272 inode = sb->s_root->d_inode;
273 /*
274 * Get local name for filesystems without rename() operation
275 * or dentry without vfsmount.
276 */
277 if (!path->mnt || (inode->i_op && !inode->i_op->rename))
278 pos = tomoyo_get_local_path(path->dentry, buf,
279 buf_len - 1);
280 /* Get absolute name for the rest. */
281 else
282 pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
283encode:
142 if (IS_ERR(pos)) 284 if (IS_ERR(pos))
143 continue; 285 continue;
144 name = tomoyo_encode(pos); 286 name = tomoyo_encode(pos);
@@ -147,16 +289,6 @@ char *tomoyo_realpath_from_path(struct path *path)
147 kfree(buf); 289 kfree(buf);
148 if (!name) 290 if (!name)
149 tomoyo_warn_oom(__func__); 291 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 != '/')
154 /*
155 * This is OK because tomoyo_encode() reserves space
156 * for appending "/".
157 */
158 *++pos = '/';
159 }
160 return name; 292 return name;
161} 293}
162 294