Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/security/tomoyo/realpath.c
10814 views
1
/*
2
* security/tomoyo/realpath.c
3
*
4
* Pathname calculation functions for TOMOYO.
5
*
6
* Copyright (C) 2005-2010 NTT DATA CORPORATION
7
*/
8
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"
18
19
/**
20
* tomoyo_encode: Convert binary string to ascii string.
21
*
22
* @str: String in binary format.
23
*
24
* Returns pointer to @str in ascii format on success, NULL otherwise.
25
*
26
* This function uses kzalloc(), so caller must kfree() if this function
27
* didn't return NULL.
28
*/
29
char *tomoyo_encode(const char *str)
30
{
31
int len = 0;
32
const char *p = str;
33
char *cp;
34
char *cp0;
35
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;
46
}
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++;
56
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';
67
}
68
}
69
return cp0;
70
}
71
72
/**
73
* tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
74
*
75
* @path: Pointer to "struct path".
76
*
77
* Returns the realpath of the given @path on success, NULL otherwise.
78
*
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.
83
*
84
* These functions use kzalloc(), so the caller must call kfree()
85
* if these functions didn't return NULL.
86
*/
87
char *tomoyo_realpath_from_path(struct path *path)
88
{
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]");
116
}
117
name = tomoyo_encode(buf);
118
break;
119
}
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;
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
}
142
if (IS_ERR(pos))
143
continue;
144
name = tomoyo_encode(pos);
145
break;
146
}
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 != '/')
154
/*
155
* This is OK because tomoyo_encode() reserves space
156
* for appending "/".
157
*/
158
*++pos = '/';
159
}
160
return name;
161
}
162
163
/**
164
* tomoyo_realpath_nofollow - Get realpath of a pathname.
165
*
166
* @pathname: The pathname to solve.
167
*
168
* Returns the realpath of @pathname on success, NULL otherwise.
169
*/
170
char *tomoyo_realpath_nofollow(const char *pathname)
171
{
172
struct path path;
173
174
if (pathname && kern_path(pathname, 0, &path) == 0) {
175
char *buf = tomoyo_realpath_from_path(&path);
176
path_put(&path);
177
return buf;
178
}
179
return NULL;
180
}
181
182