Updated and re-enabled richacl support.
[opensuse:kernel-source.git] / patches.suse / 0001-vfs-Hooks-for-more-fine-grained-directory-permission.patch
1 From: Andreas Gruenbacher <agruen@suse.de>
2 Date: Fri, 11 Jun 2010 16:12:44 +0530
3 Subject: [PATCH 01/16] vfs: Hooks for more fine-grained directory permission checking
4 Patch-mainline: not yet
5
6 Add iop->may_create and iop->may_delete for overriding the POSIX file
7 permission checks when creating and deleting files.  File systems can
8 implement these hooks to support permission models which use different
9 rules for file creation and deletion.
10
11 When these hooks are not used, the vfs behavior remains unchanged.
12
13 Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
14 Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
15 ---
16  fs/namei.c         |   82 ++++++++++++++++++++++++++++++++++++++++++-----------
17  include/linux/fs.h |    4 ++
18  2 files changed, 69 insertions(+), 17 deletions(-)
19
20 --- a/fs/namei.c
21 +++ b/fs/namei.c
22 @@ -2156,6 +2156,26 @@ static inline int check_sticky(struct in
23  }
24  
25  /*
26 + * Do the directory specific tests of inode_permission() and call the
27 + * may_delete inode operation.  The may_delete inode operation must do the
28 + * sticky check when needed.
29 + */
30 +static int may_delete_iop(struct inode *dir, struct inode *inode, int replace)
31 +{
32 +       int error;
33 +
34 +       if (IS_RDONLY(dir))
35 +               return -EROFS;
36 +       if (IS_IMMUTABLE(dir))
37 +               return -EACCES;
38 +       error = dir->i_op->may_delete(dir, inode, replace);
39 +       if (!error)
40 +               error = security_inode_permission(dir, MAY_WRITE | MAY_EXEC);
41 +
42 +       return error;
43 +}
44 +
45 +/*
46   *     Check whether we can remove a link victim from directory dir, check
47   *  whether the type of victim is right.
48   *  1. We can't do it if dir is read-only (done in permission())
49 @@ -2174,7 +2194,8 @@ static inline int check_sticky(struct in
50   * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
51   *     nfs_async_unlink().
52   */
53 -static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
54 +static int may_delete(struct inode *dir, struct dentry *victim,
55 +                     int isdir, int replace)
56  {
57         int error;
58  
59 @@ -2183,14 +2204,19 @@ static int may_delete(struct inode *dir,
60  
61         BUG_ON(victim->d_parent->d_inode != dir);
62         audit_inode_child(victim, dir);
63 -
64 -       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
65 +       if (dir->i_op->may_delete)
66 +               error = may_delete_iop(dir, victim->d_inode, replace);
67 +       else {
68 +               error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
69 +               if (!error && check_sticky(dir, victim->d_inode))
70 +                       error = -EPERM;
71 +       }
72         if (error)
73                 return error;
74         if (IS_APPEND(dir))
75                 return -EPERM;
76 -       if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
77 -           IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
78 +       if (IS_APPEND(victim->d_inode) || IS_IMMUTABLE(victim->d_inode) ||
79 +               IS_SWAPFILE(victim->d_inode))
80                 return -EPERM;
81         if (isdir) {
82                 if (!S_ISDIR(victim->d_inode->i_mode))
83 @@ -2206,6 +2232,25 @@ static int may_delete(struct inode *dir,
84         return 0;
85  }
86  
87 +/*
88 + * Do the directory specific tests of inode_permission() and call the
89 + * may_create inode operation.
90 + */
91 +static int may_create_iop(struct inode *dir, int isdir)
92 +{
93 +       int error;
94 +
95 +       if (IS_RDONLY(dir))
96 +               return -EROFS;
97 +       if (IS_IMMUTABLE(dir))
98 +               return -EACCES;
99 +       error = dir->i_op->may_create(dir, isdir);
100 +       if (!error)
101 +               error = security_inode_permission(dir, MAY_WRITE | MAY_EXEC);
102 +
103 +       return error;
104 +}
105 +
106  /*     Check whether we can create an object with dentry child in directory
107   *  dir.
108   *  1. We can't do it if child already exists (open has special treatment for
109 @@ -2214,13 +2259,16 @@ static int may_delete(struct inode *dir,
110   *  3. We should have write and exec permissions on dir
111   *  4. We can't do it if dir is immutable (done in permission())
112   */
113 -static inline int may_create(struct inode *dir, struct dentry *child)
114 +static inline int may_create(struct inode *dir, struct dentry *child, int isdir)
115  {
116         if (child->d_inode)
117                 return -EEXIST;
118         if (IS_DEADDIR(dir))
119                 return -ENOENT;
120 -       return inode_permission(dir, MAY_WRITE | MAY_EXEC);
121 +       if (dir->i_op->may_create)
122 +               return may_create_iop(dir, isdir);
123 +       else
124 +               return inode_permission(dir, MAY_WRITE | MAY_EXEC);
125  }
126  
127  /*
128 @@ -2268,7 +2316,7 @@ void unlock_rename(struct dentry *p1, st
129  int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
130                 bool want_excl)
131  {
132 -       int error = may_create(dir, dentry);
133 +       int error = may_create(dir, dentry, 0);
134         if (error)
135                 return error;
136  
137 @@ -3054,7 +3102,7 @@ EXPORT_SYMBOL(user_path_create);
138  
139  int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
140  {
141 -       int error = may_create(dir, dentry);
142 +       int error = may_create(dir, dentry, 0);
143  
144         if (error)
145                 return error;
146 @@ -3140,7 +3188,7 @@ SYSCALL_DEFINE3(mknod, const char __user
147  
148  int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
149  {
150 -       int error = may_create(dir, dentry);
151 +       int error = may_create(dir, dentry, 1);
152         unsigned max_links = dir->i_sb->s_max_links;
153  
154         if (error)
155 @@ -3213,7 +3261,7 @@ void dentry_unhash(struct dentry *dentry
156  
157  int vfs_rmdir(struct inode *dir, struct dentry *dentry)
158  {
159 -       int error = may_delete(dir, dentry, 1);
160 +       int error = may_delete(dir, dentry, 1, 0);
161  
162         if (error)
163                 return error;
164 @@ -3307,7 +3355,7 @@ SYSCALL_DEFINE1(rmdir, const char __user
165  
166  int vfs_unlink(struct inode *dir, struct dentry *dentry)
167  {
168 -       int error = may_delete(dir, dentry, 0);
169 +       int error = may_delete(dir, dentry, 0, 0);
170  
171         if (error)
172                 return error;
173 @@ -3415,7 +3463,7 @@ SYSCALL_DEFINE1(unlink, const char __use
174  
175  int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
176  {
177 -       int error = may_create(dir, dentry);
178 +       int error = may_create(dir, dentry, 0);
179  
180         if (error)
181                 return error;
182 @@ -3473,7 +3521,7 @@ int vfs_link(struct dentry *old_dentry,
183         if (!inode)
184                 return -ENOENT;
185  
186 -       error = may_create(dir, new_dentry);
187 +       error = may_create(dir, new_dentry, S_ISDIR(inode->i_mode));
188         if (error)
189                 return error;
190  
191 @@ -3697,14 +3745,14 @@ int vfs_rename(struct inode *old_dir, st
192         if (old_dentry->d_inode == new_dentry->d_inode)
193                 return 0;
194   
195 -       error = may_delete(old_dir, old_dentry, is_dir);
196 +       error = may_delete(old_dir, old_dentry, is_dir, 0);
197         if (error)
198                 return error;
199  
200         if (!new_dentry->d_inode)
201 -               error = may_create(new_dir, new_dentry);
202 +               error = may_create(new_dir, new_dentry, is_dir);
203         else
204 -               error = may_delete(new_dir, new_dentry, is_dir);
205 +               error = may_delete(new_dir, new_dentry, is_dir, 1);
206         if (error)
207                 return error;
208  
209 --- a/include/linux/fs.h
210 +++ b/include/linux/fs.h
211 @@ -1836,6 +1836,10 @@ struct inode_operations {
212         int (*atomic_open)(struct inode *, struct dentry *,
213                            struct file *, unsigned open_flag,
214                            umode_t create_mode, int *opened);
215 +       int (*may_create) (struct inode *, int);
216 +       int (*may_delete) (struct inode *, struct inode *, int);
217 +
218 +
219  } ____cacheline_aligned;
220  
221  struct seq_file;