1
Directory rename bugfix
3
Up until now, the profile permission checks for directory rename only
4
worked in most cases, and mostly be coincidence: when we did permission
5
checks, we ignored requests for MAY_WRITE and MAY_EXEC on directories
6
because else we would have to include x access on each directory that
7
should be accessed, and w access on each directory that files can be
8
created in or removed from.
10
We also ignored MAY_WRITE and MAY_EXEC for directory renames, and it was
11
only by sheer luck that most directory renames failed -- the only reason
12
why most they failed was because in most cases, the target file will
13
either not exist, or be a non-directory. If the target file exists and
14
is a directory, then it is sufficient to have r profile access in order
15
to rename directories, though.
17
Test case: create two empty directories d1 and d2 somewhere. Give a
18
process r access to that directory. Do a rename("d1", "d2") syscall, and
19
d2 will disappear. This will also fail with ENOTEMPTY if d2 is
20
non-empty. The expected result of course would be EPERM.
22
This issue may have been noticed before. Anyway, a fix is attached;
23
there are now also comments in the code that explain what's going on.
25
Caveat: there still is no way to to tell a directory traversal from the
26
access(2) system call, and so access("d1", W_OK) will still return 0
27
even if the profile does not allow w access to d1. This is mildly
28
annoying, but using access(2) for permission checking is insecure,
31
Index: b/security/apparmor/lsm.c
32
===================================================================
33
--- a/security/apparmor/lsm.c
34
+++ b/security/apparmor/lsm.c
35
@@ -278,7 +278,7 @@ out:
38
static int aa_permission(struct inode *inode, struct dentry *dentry,
39
- struct vfsmount *mnt, int mask)
40
+ struct vfsmount *mnt, int mask, int leaf)
44
@@ -286,7 +286,7 @@ static int aa_permission(struct inode *i
45
struct aa_profile *active = get_active_aa_profile();
48
- error = aa_perm(active, dentry, mnt, mask);
49
+ error = aa_perm(active, dentry, mnt, mask, leaf);
50
put_aa_profile(active);
53
@@ -295,7 +295,7 @@ static int aa_permission(struct inode *i
54
static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
55
struct vfsmount *mnt, int mask)
57
- return aa_permission(dir, dentry, mnt, MAY_WRITE);
58
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
61
static int apparmor_inode_link(struct dentry *old_dentry,
62
@@ -325,19 +325,19 @@ static int apparmor_inode_unlink(struct
63
struct dentry *dentry,
66
- return aa_permission(dir, dentry, mnt, MAY_WRITE);
67
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
70
static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
71
struct vfsmount *mnt, const char *old_name)
73
- return aa_permission(dir, dentry, mnt, MAY_WRITE);
74
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
77
static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
78
struct vfsmount *mnt, int mode, dev_t dev)
80
- return aa_permission(dir, dentry, mnt, MAY_WRITE);
81
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
84
static int apparmor_inode_rename(struct inode *old_dir,
85
@@ -358,11 +358,11 @@ static int apparmor_inode_rename(struct
88
error = aa_perm(active, old_dentry, old_mnt,
89
- MAY_READ|MAY_WRITE);
90
+ MAY_READ | MAY_WRITE, 1);
92
if (!error && new_mnt)
93
error = aa_perm(active, new_dentry, new_mnt,
98
put_aa_profile(active);
99
@@ -376,8 +376,22 @@ static int apparmor_inode_permission(str
104
+ * Assume we are /not/ checking a leaf directory. We do not
105
+ * require profile access to non-leaf directories in order to
106
+ * traverse them, create or remove files in them. We do require
107
+ * MAY_WRITE profile access on the actual file or directory
108
+ * being created or removed, though, which makes the model safe
111
+ * For the access(2) system call this means that when used on a
112
+ * leaf directory, we may return 0 even though the requesting
113
+ * process doesn't actually have MAY_WRITE nor MAY_EXEC access
114
+ * in the profile. This is nothing but an inconvenience; using
115
+ * access(2) for permission checking is invalid, anyways.
117
return aa_permission(inode, nd->dentry, nd->mnt,
118
- mask & (MAY_READ | MAY_WRITE | MAY_EXEC));
119
+ mask & (MAY_READ | MAY_WRITE | MAY_EXEC), 0);
122
static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
123
@@ -454,6 +468,7 @@ static int apparmor_inode_removexattr(st
124
static inline int aa_mmap(struct file *file, unsigned long prot,
127
+ struct dentry *dentry;
131
@@ -468,8 +483,8 @@ static inline int aa_mmap(struct file *f
132
if (prot & PROT_EXEC)
133
mask |= AA_EXEC_MMAP;
135
- return aa_permission(file->f_dentry->d_inode, file->f_dentry,
136
- file->f_vfsmnt, mask);
137
+ dentry = file->f_dentry;
138
+ return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask, 1);
141
static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
142
Index: b/security/apparmor/main.c
143
===================================================================
144
--- a/security/apparmor/main.c
145
+++ b/security/apparmor/main.c
146
@@ -80,32 +80,6 @@ out:
152
- * @mask: requested mask
153
- * @inode: potential directory inode
155
- * This fn performs pre-verification of the requested mask
156
- * We ignore append. Previously we required 'w' on a dir to add a file.
157
- * No longer. Now we require 'w' on just the file itself. Traversal 'x' is
158
- * also ignored for directories.
160
- * Returned value of %0 indicates no need to perform a perm check.
162
-static inline int aa_filter_mask(int mask, struct inode *inode)
165
- int elim = MAY_APPEND;
167
- if (inode && S_ISDIR(inode->i_mode))
168
- elim |= (MAY_EXEC | MAY_WRITE);
176
static inline void aa_permerror2result(int perm_result, struct aa_audit *sa)
178
if (perm_result == 0) { /* success */
179
@@ -599,17 +573,30 @@ int aa_perm_xattr(struct aa_profile *act
182
* @mask: access mode requested
183
+ * @leaf: are we checking a leaf node?
185
* Determine if access (mask) for dentry is authorized by active
186
* profile. Result, %0 (success), -ve (error)
188
int aa_perm(struct aa_profile *active, struct dentry *dentry,
189
- struct vfsmount *mnt, int mask)
190
+ struct vfsmount *mnt, int mask, int leaf)
193
+ struct inode *inode = dentry->d_inode;
197
- if ((mask = aa_filter_mask(mask, dentry->d_inode)) == 0)
198
+ if (!leaf && inode && S_ISDIR(inode->i_mode)) {
200
+ * If checking a non-leaf directory, allow traverse and
201
+ * write access: we do not require profile access to
202
+ * non-leaf directories in order to traverse them,
203
+ * create or remove files in them. We do require
204
+ * MAY_WRITE profile access on the actual file or
205
+ * directory being created or removed, though.
207
+ mask &= ~(MAY_EXEC | MAY_WRITE);
212
sa.type = AA_AUDITTYPE_FILE;
213
Index: b/security/apparmor/apparmor.h
214
===================================================================
215
--- a/security/apparmor/apparmor.h
216
+++ b/security/apparmor/apparmor.h
217
@@ -209,7 +209,7 @@ extern int aa_perm_xattr(struct aa_profi
218
const char *xattr_xattr, int mask);
219
extern int aa_capability(struct aa_profile *active, int cap);
220
extern int aa_perm(struct aa_profile *active, struct dentry *dentry,
221
- struct vfsmount *mnt, int mask);
222
+ struct vfsmount *mnt, int mask, int leaf);
223
extern int aa_perm_dir(struct aa_profile *active, struct dentry *dentry,
224
struct vfsmount *mnt, const char *operation, int mask);
225
extern int aa_link(struct aa_profile *active,