Blame view
security/apparmor/path.c
6.33 KB
cdff26426 AppArmor: misc. b... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * AppArmor security module * * This file contains AppArmor function for pathnames * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the * License. */ #include <linux/magic.h> |
cdff26426 AppArmor: misc. b... |
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include <linux/mount.h> #include <linux/namei.h> #include <linux/nsproxy.h> #include <linux/path.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/fs_struct.h> #include "include/apparmor.h" #include "include/path.h" #include "include/policy.h" /* modified from dcache.c */ static int prepend(char **buffer, int buflen, const char *str, int namelen) { buflen -= namelen; if (buflen < 0) return -ENAMETOOLONG; *buffer -= namelen; memcpy(*buffer, str, namelen); return 0; } #define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT) /** * d_namespace_path - lookup a name associated with a given path * @path: path to lookup (NOT NULL) * @buf: buffer to store path to (NOT NULL) * @buflen: length of @buf * @name: Returns - pointer for start of path name with in @buf (NOT NULL) * @flags: flags controlling path lookup * * Handle path name lookup. * * Returns: %0 else error code if path lookup fails * When no error the path name is returned in @name which points to * to a position in @buf */ static int d_namespace_path(struct path *path, char *buf, int buflen, char **name, int flags) { |
cdff26426 AppArmor: misc. b... |
59 |
char *res; |
02125a826 fix apparmor dere... |
60 61 |
int error = 0; int connected = 1; |
cdff26426 AppArmor: misc. b... |
62 |
|
02125a826 fix apparmor dere... |
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
if (path->mnt->mnt_flags & MNT_INTERNAL) { /* it's not mounted anywhere */ res = dentry_path(path->dentry, buf, buflen); *name = res; if (IS_ERR(res)) { *name = buf; return PTR_ERR(res); } if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC && strncmp(*name, "/sys/", 5) == 0) { /* TODO: convert over to using a per namespace * control instead of hard coded /proc */ return prepend(name, *name - buf, "/proc", 5); } return 0; } /* resolve paths relative to chroot?*/ |
cdff26426 AppArmor: misc. b... |
82 |
if (flags & PATH_CHROOT_REL) { |
02125a826 fix apparmor dere... |
83 |
struct path root; |
44672e4fb apparmor: use tas... |
84 |
get_fs_root(current->fs, &root); |
02125a826 fix apparmor dere... |
85 |
res = __d_path(path, &root, buf, buflen); |
02125a826 fix apparmor dere... |
86 |
path_put(&root); |
3372b68a3 AppArmor: Minor c... |
87 |
} else { |
28042fabf AppArmor: Fix the... |
88 |
res = d_absolute_path(path, buf, buflen); |
3372b68a3 AppArmor: Minor c... |
89 90 91 |
if (!our_mnt(path->mnt)) connected = 0; } |
cdff26426 AppArmor: misc. b... |
92 |
|
cdff26426 AppArmor: misc. b... |
93 94 95 |
/* handle error conditions - and still allow a partial path to * be returned. */ |
3372b68a3 AppArmor: Minor c... |
96 |
if (!res || IS_ERR(res)) { |
cffee16e8 apparmor: fix lon... |
97 98 |
if (PTR_ERR(res) == -ENAMETOOLONG) return -ENAMETOOLONG; |
3372b68a3 AppArmor: Minor c... |
99 |
connected = 0; |
fbba8d89a AppArmor: Retriev... |
100 101 102 103 104 105 106 |
res = dentry_path_raw(path->dentry, buf, buflen); if (IS_ERR(res)) { error = PTR_ERR(res); *name = buf; goto out; }; } else if (!our_mnt(path->mnt)) |
02125a826 fix apparmor dere... |
107 |
connected = 0; |
cdff26426 AppArmor: misc. b... |
108 |
|
fbba8d89a AppArmor: Retriev... |
109 |
*name = res; |
e819ff519 AppArmor: Drop ha... |
110 111 112 113 114 115 |
/* Handle two cases: * 1. A deleted dentry && profile is not allowing mediation of deleted * 2. On some filesystems, newly allocated dentries appear to the * security_path hooks as a deleted dentry except without an inode * allocated. */ |
729b8a3de Apparmor: Use d_i... |
116 |
if (d_unlinked(path->dentry) && d_is_positive(path->dentry) && |
e819ff519 AppArmor: Drop ha... |
117 |
!(flags & PATH_MEDIATE_DELETED)) { |
cdff26426 AppArmor: misc. b... |
118 119 |
error = -ENOENT; goto out; |
cdff26426 AppArmor: misc. b... |
120 |
} |
02125a826 fix apparmor dere... |
121 |
/* If the path is not connected to the expected root, |
cdff26426 AppArmor: misc. b... |
122 123 124 125 126 127 128 129 130 131 132 |
* check if it is a sysctl and handle specially else remove any * leading / that __d_path may have returned. * Unless * specifically directed to connect the path, * OR * if in a chroot and doing chroot relative paths and the path * resolves to the namespace root (would be connected outside * of chroot) and specifically directed to connect paths to * namespace root. */ if (!connected) { |
02125a826 fix apparmor dere... |
133 |
if (!(flags & PATH_CONNECT_PATH) && |
cdff26426 AppArmor: misc. b... |
134 |
!(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) && |
02125a826 fix apparmor dere... |
135 |
our_mnt(path->mnt))) { |
cdff26426 AppArmor: misc. b... |
136 137 138 |
/* disconnected path, don't return pathname starting * with '/' */ |
ef9a76227 AppArmor: Fix err... |
139 |
error = -EACCES; |
cdff26426 AppArmor: misc. b... |
140 141 142 143 144 145 |
if (*res == '/') *name = res + 1; } } out: |
cdff26426 AppArmor: misc. b... |
146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
return error; } /** * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended * @path: path to get name for (NOT NULL) * @flags: flags controlling path lookup * @buffer: buffer to put name in (NOT NULL) * @size: size of buffer * @name: Returns - contains position of path name in @buffer (NOT NULL) * * Returns: %0 else error on failure */ static int get_name_to_buffer(struct path *path, int flags, char *buffer, |
57fa1e180 AppArmor: Move pa... |
160 |
int size, char **name, const char **info) |
cdff26426 AppArmor: misc. b... |
161 162 163 164 165 166 167 168 169 170 |
{ int adjust = (flags & PATH_IS_DIR) ? 1 : 0; int error = d_namespace_path(path, buffer, size - adjust, name, flags); if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0') /* * Append "/" to the pathname. The root directory is a special * case; it already ends in slash. */ strcpy(&buffer[size - 2], "/"); |
57fa1e180 AppArmor: Move pa... |
171 172 173 |
if (info && error) { if (error == -ENOENT) *info = "Failed name lookup - deleted entry"; |
e573cc30b apparmor: fix err... |
174 |
else if (error == -EACCES) |
57fa1e180 AppArmor: Move pa... |
175 176 177 178 179 180 |
*info = "Failed name lookup - disconnected path"; else if (error == -ENAMETOOLONG) *info = "Failed name lookup - name too long"; else *info = "Failed name lookup"; } |
cdff26426 AppArmor: misc. b... |
181 182 183 184 |
return error; } /** |
57fa1e180 AppArmor: Move pa... |
185 |
* aa_path_name - compute the pathname of a file |
cdff26426 AppArmor: misc. b... |
186 187 188 189 |
* @path: path the file (NOT NULL) * @flags: flags controlling path name generation * @buffer: buffer that aa_get_name() allocated (NOT NULL) * @name: Returns - the generated path name if !error (NOT NULL) |
57fa1e180 AppArmor: Move pa... |
190 |
* @info: Returns - information on why the path lookup failed (MAYBE NULL) |
cdff26426 AppArmor: misc. b... |
191 192 193 194 195 196 197 198 199 200 201 202 |
* * @name is a pointer to the beginning of the pathname (which usually differs * from the beginning of the buffer), or NULL. If there is an error @name * may contain a partial or invalid name that can be used for audit purposes, * but it can not be used for mediation. * * We need PATH_IS_DIR to indicate whether the file is a directory or not * because the file may not yet exist, and so we cannot check the inode's * file type. * * Returns: %0 else error code if could retrieve name */ |
57fa1e180 AppArmor: Move pa... |
203 204 |
int aa_path_name(struct path *path, int flags, char **buffer, const char **name, const char **info) |
cdff26426 AppArmor: misc. b... |
205 206 207 208 209 210 211 212 213 214 215 216 |
{ char *buf, *str = NULL; int size = 256; int error; *name = NULL; *buffer = NULL; for (;;) { /* freed by caller */ buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; |
57fa1e180 AppArmor: Move pa... |
217 |
error = get_name_to_buffer(path, flags, buf, size, &str, info); |
cdff26426 AppArmor: misc. b... |
218 219 220 221 222 223 224 |
if (error != -ENAMETOOLONG) break; kfree(buf); size <<= 1; if (size > aa_g_path_max) return -ENAMETOOLONG; |
57fa1e180 AppArmor: Move pa... |
225 |
*info = NULL; |
cdff26426 AppArmor: misc. b... |
226 227 228 229 230 231 |
} *buffer = buf; *name = str; return error; } |