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