aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/path.c')
-rw-r--r--security/apparmor/path.c130
1 files changed, 52 insertions, 78 deletions
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index a8fc7d08c144..9d5de1d05be4 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -50,7 +50,7 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen)
50 * namespace root. 50 * namespace root.
51 */ 51 */
52static int disconnect(const struct path *path, char *buf, char **name, 52static int disconnect(const struct path *path, char *buf, char **name,
53 int flags) 53 int flags, const char *disconnected)
54{ 54{
55 int error = 0; 55 int error = 0;
56 56
@@ -63,9 +63,14 @@ static int disconnect(const struct path *path, char *buf, char **name,
63 error = -EACCES; 63 error = -EACCES;
64 if (**name == '/') 64 if (**name == '/')
65 *name = *name + 1; 65 *name = *name + 1;
66 } else if (**name != '/') 66 } else {
67 /* CONNECT_PATH with missing root */ 67 if (**name != '/')
68 error = prepend(name, *name - buf, "/", 1); 68 /* CONNECT_PATH with missing root */
69 error = prepend(name, *name - buf, "/", 1);
70 if (!error && disconnected)
71 error = prepend(name, *name - buf, disconnected,
72 strlen(disconnected));
73 }
69 74
70 return error; 75 return error;
71} 76}
@@ -74,9 +79,9 @@ static int disconnect(const struct path *path, char *buf, char **name,
74 * d_namespace_path - lookup a name associated with a given path 79 * d_namespace_path - lookup a name associated with a given path
75 * @path: path to lookup (NOT NULL) 80 * @path: path to lookup (NOT NULL)
76 * @buf: buffer to store path to (NOT NULL) 81 * @buf: buffer to store path to (NOT NULL)
77 * @buflen: length of @buf
78 * @name: Returns - pointer for start of path name with in @buf (NOT NULL) 82 * @name: Returns - pointer for start of path name with in @buf (NOT NULL)
79 * @flags: flags controlling path lookup 83 * @flags: flags controlling path lookup
84 * @disconnected: string to prefix to disconnected paths
80 * 85 *
81 * Handle path name lookup. 86 * Handle path name lookup.
82 * 87 *
@@ -84,12 +89,14 @@ static int disconnect(const struct path *path, char *buf, char **name,
84 * When no error the path name is returned in @name which points to 89 * When no error the path name is returned in @name which points to
85 * to a position in @buf 90 * to a position in @buf
86 */ 91 */
87static int d_namespace_path(const struct path *path, char *buf, int buflen, 92static int d_namespace_path(const struct path *path, char *buf, char **name,
88 char **name, int flags) 93 int flags, const char *disconnected)
89{ 94{
90 char *res; 95 char *res;
91 int error = 0; 96 int error = 0;
92 int connected = 1; 97 int connected = 1;
98 int isdir = (flags & PATH_IS_DIR) ? 1 : 0;
99 int buflen = aa_g_path_max - isdir;
93 100
94 if (path->mnt->mnt_flags & MNT_INTERNAL) { 101 if (path->mnt->mnt_flags & MNT_INTERNAL) {
95 /* it's not mounted anywhere */ 102 /* it's not mounted anywhere */
@@ -104,10 +111,12 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
104 /* TODO: convert over to using a per namespace 111 /* TODO: convert over to using a per namespace
105 * control instead of hard coded /proc 112 * control instead of hard coded /proc
106 */ 113 */
107 return prepend(name, *name - buf, "/proc", 5); 114 error = prepend(name, *name - buf, "/proc", 5);
115 goto out;
108 } else 116 } else
109 return disconnect(path, buf, name, flags); 117 error = disconnect(path, buf, name, flags,
110 return 0; 118 disconnected);
119 goto out;
111 } 120 }
112 121
113 /* resolve paths relative to chroot?*/ 122 /* resolve paths relative to chroot?*/
@@ -126,8 +135,11 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
126 * be returned. 135 * be returned.
127 */ 136 */
128 if (!res || IS_ERR(res)) { 137 if (!res || IS_ERR(res)) {
129 if (PTR_ERR(res) == -ENAMETOOLONG) 138 if (PTR_ERR(res) == -ENAMETOOLONG) {
130 return -ENAMETOOLONG; 139 error = -ENAMETOOLONG;
140 *name = buf;
141 goto out;
142 }
131 connected = 0; 143 connected = 0;
132 res = dentry_path_raw(path->dentry, buf, buflen); 144 res = dentry_path_raw(path->dentry, buf, buflen);
133 if (IS_ERR(res)) { 145 if (IS_ERR(res)) {
@@ -140,6 +152,9 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
140 152
141 *name = res; 153 *name = res;
142 154
155 if (!connected)
156 error = disconnect(path, buf, name, flags, disconnected);
157
143 /* Handle two cases: 158 /* Handle two cases:
144 * 1. A deleted dentry && profile is not allowing mediation of deleted 159 * 1. A deleted dentry && profile is not allowing mediation of deleted
145 * 2. On some filesystems, newly allocated dentries appear to the 160 * 2. On some filesystems, newly allocated dentries appear to the
@@ -147,62 +162,30 @@ static int d_namespace_path(const struct path *path, char *buf, int buflen,
147 * allocated. 162 * allocated.
148 */ 163 */
149 if (d_unlinked(path->dentry) && d_is_positive(path->dentry) && 164 if (d_unlinked(path->dentry) && d_is_positive(path->dentry) &&
150 !(flags & PATH_MEDIATE_DELETED)) { 165 !(flags & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))) {
151 error = -ENOENT; 166 error = -ENOENT;
152 goto out; 167 goto out;
153 } 168 }
154 169
155 if (!connected)
156 error = disconnect(path, buf, name, flags);
157
158out: 170out:
159 return error; 171 /*
160} 172 * Append "/" to the pathname. The root directory is a special
161 173 * case; it already ends in slash.
162/** 174 */
163 * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended 175 if (!error && isdir && ((*name)[1] != '\0' || (*name)[0] != '/'))
164 * @path: path to get name for (NOT NULL) 176 strcpy(&buf[aa_g_path_max - 2], "/");
165 * @flags: flags controlling path lookup
166 * @buffer: buffer to put name in (NOT NULL)
167 * @size: size of buffer
168 * @name: Returns - contains position of path name in @buffer (NOT NULL)
169 *
170 * Returns: %0 else error on failure
171 */
172static int get_name_to_buffer(const struct path *path, int flags, char *buffer,
173 int size, char **name, const char **info)
174{
175 int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
176 int error = d_namespace_path(path, buffer, size - adjust, name, flags);
177
178 if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')
179 /*
180 * Append "/" to the pathname. The root directory is a special
181 * case; it already ends in slash.
182 */
183 strcpy(&buffer[size - 2], "/");
184
185 if (info && error) {
186 if (error == -ENOENT)
187 *info = "Failed name lookup - deleted entry";
188 else if (error == -EACCES)
189 *info = "Failed name lookup - disconnected path";
190 else if (error == -ENAMETOOLONG)
191 *info = "Failed name lookup - name too long";
192 else
193 *info = "Failed name lookup";
194 }
195 177
196 return error; 178 return error;
197} 179}
198 180
199/** 181/**
200 * aa_path_name - compute the pathname of a file 182 * aa_path_name - get the pathname to a buffer ensure dir / is appended
201 * @path: path the file (NOT NULL) 183 * @path: path the file (NOT NULL)
202 * @flags: flags controlling path name generation 184 * @flags: flags controlling path name generation
203 * @buffer: buffer that aa_get_name() allocated (NOT NULL) 185 * @buffer: buffer to put name in (NOT NULL)
204 * @name: Returns - the generated path name if !error (NOT NULL) 186 * @name: Returns - the generated path name if !error (NOT NULL)
205 * @info: Returns - information on why the path lookup failed (MAYBE NULL) 187 * @info: Returns - information on why the path lookup failed (MAYBE NULL)
188 * @disconnected: string to prepend to disconnected paths
206 * 189 *
207 * @name is a pointer to the beginning of the pathname (which usually differs 190 * @name is a pointer to the beginning of the pathname (which usually differs
208 * from the beginning of the buffer), or NULL. If there is an error @name 191 * from the beginning of the buffer), or NULL. If there is an error @name
@@ -215,32 +198,23 @@ static int get_name_to_buffer(const struct path *path, int flags, char *buffer,
215 * 198 *
216 * Returns: %0 else error code if could retrieve name 199 * Returns: %0 else error code if could retrieve name
217 */ 200 */
218int aa_path_name(const struct path *path, int flags, char **buffer, 201int aa_path_name(const struct path *path, int flags, char *buffer,
219 const char **name, const char **info) 202 const char **name, const char **info, const char *disconnected)
220{ 203{
221 char *buf, *str = NULL; 204 char *str = NULL;
222 int size = 256; 205 int error = d_namespace_path(path, buffer, &str, flags, disconnected);
223 int error; 206
224 207 if (info && error) {
225 *name = NULL; 208 if (error == -ENOENT)
226 *buffer = NULL; 209 *info = "Failed name lookup - deleted entry";
227 for (;;) { 210 else if (error == -EACCES)
228 /* freed by caller */ 211 *info = "Failed name lookup - disconnected path";
229 buf = kmalloc(size, GFP_KERNEL); 212 else if (error == -ENAMETOOLONG)
230 if (!buf) 213 *info = "Failed name lookup - name too long";
231 return -ENOMEM; 214 else
232 215 *info = "Failed name lookup";
233 error = get_name_to_buffer(path, flags, buf, size, &str, info);
234 if (error != -ENAMETOOLONG)
235 break;
236
237 kfree(buf);
238 size <<= 1;
239 if (size > aa_g_path_max)
240 return -ENAMETOOLONG;
241 *info = NULL;
242 } 216 }
243 *buffer = buf; 217
244 *name = str; 218 *name = str;
245 219
246 return error; 220 return error;