]>
Commit | Line | Data |
---|---|---|
4d1e5b62 AF |
1 | From: Jeff Mahoney <jeffm@suse.com> |
2 | Subject: reiserfs: add atomic addition of selinux attributes during inode creation | |
3 | ||
4 | Some time ago, some changes were made to make security inode attributes | |
5 | be atomically written during inode creation. ReiserFS fell behind in this | |
6 | area, but with the reworking of the xattr code, it's now fairly easy to add. | |
7 | ||
8 | The following patch adds the ability for security attributes to be added | |
9 | automatically during inode creation. | |
10 | ||
11 | Signed-off-by: Jeff Mahoney <jeffm@suse.com> | |
12 | ||
13 | -- | |
14 | fs/reiserfs/inode.c | 16 +++++++++++- | |
15 | fs/reiserfs/namei.c | 37 +++++++++++++++++++++++++--- | |
16 | fs/reiserfs/xattr_security.c | 54 +++++++++++++++++++++++++++++++++++++++++ | |
17 | include/linux/reiserfs_fs.h | 4 ++- | |
18 | include/linux/reiserfs_xattr.h | 32 ++++++++++++++++++++++++ | |
19 | 5 files changed, 137 insertions(+), 6 deletions(-) | |
20 | ||
21 | --- a/fs/reiserfs/inode.c | |
22 | +++ b/fs/reiserfs/inode.c | |
23 | @@ -1756,7 +1756,8 @@ int reiserfs_new_inode(struct reiserfs_t | |
24 | /* 0 for regular, EMTRY_DIR_SIZE for dirs, | |
25 | strlen (symname) for symlinks) */ | |
26 | loff_t i_size, struct dentry *dentry, | |
27 | - struct inode *inode) | |
28 | + struct inode *inode, | |
29 | + struct reiserfs_security_handle *security) | |
30 | { | |
31 | struct super_block *sb; | |
32 | INITIALIZE_PATH(path_to_key); | |
33 | @@ -1934,6 +1935,19 @@ int reiserfs_new_inode(struct reiserfs_t | |
34 | } else if (IS_PRIVATE(dir)) | |
35 | inode->i_flags |= S_PRIVATE; | |
36 | ||
37 | + if (security->name) { | |
38 | + retval = reiserfs_security_write(th, inode, security); | |
39 | + if (retval) { | |
40 | + err = retval; | |
41 | + reiserfs_check_path(&path_to_key); | |
42 | + retval = journal_end(th, th->t_super, | |
43 | + th->t_blocks_allocated); | |
44 | + if (retval) | |
45 | + err = retval; | |
46 | + goto out_inserted_sd; | |
47 | + } | |
48 | + } | |
49 | + | |
50 | insert_inode_hash(inode); | |
51 | reiserfs_update_sd(th, inode); | |
52 | reiserfs_check_path(&path_to_key); | |
53 | --- a/fs/reiserfs/namei.c | |
54 | +++ b/fs/reiserfs/namei.c | |
55 | @@ -607,6 +607,7 @@ static int reiserfs_create(struct inode | |
56 | 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + | |
57 | REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); | |
58 | struct reiserfs_transaction_handle th; | |
59 | + struct reiserfs_security_handle security; | |
60 | ||
61 | if (!(inode = new_inode(dir->i_sb))) { | |
62 | return -ENOMEM; | |
63 | @@ -614,6 +615,12 @@ static int reiserfs_create(struct inode | |
64 | new_inode_init(inode, dir, mode); | |
65 | ||
66 | jbegin_count += reiserfs_cache_default_acl(dir); | |
67 | + retval = reiserfs_security_init(dir, inode, &security); | |
68 | + if (retval < 0) { | |
69 | + drop_new_inode(inode); | |
70 | + return retval; | |
71 | + } | |
72 | + jbegin_count += retval; | |
73 | reiserfs_write_lock(dir->i_sb); | |
74 | ||
75 | retval = journal_begin(&th, dir->i_sb, jbegin_count); | |
76 | @@ -624,7 +631,7 @@ static int reiserfs_create(struct inode | |
77 | ||
78 | retval = | |
79 | reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, | |
80 | - inode); | |
81 | + inode, &security); | |
82 | if (retval) | |
83 | goto out_failed; | |
84 | ||
85 | @@ -662,6 +669,7 @@ static int reiserfs_mknod(struct inode * | |
86 | int retval; | |
87 | struct inode *inode; | |
88 | struct reiserfs_transaction_handle th; | |
89 | + struct reiserfs_security_handle security; | |
90 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | |
91 | int jbegin_count = | |
92 | JOURNAL_PER_BALANCE_CNT * 3 + | |
93 | @@ -677,6 +685,12 @@ static int reiserfs_mknod(struct inode * | |
94 | new_inode_init(inode, dir, mode); | |
95 | ||
96 | jbegin_count += reiserfs_cache_default_acl(dir); | |
97 | + retval = reiserfs_security_init(dir, inode, &security); | |
98 | + if (retval < 0) { | |
99 | + drop_new_inode(inode); | |
100 | + return retval; | |
101 | + } | |
102 | + jbegin_count += retval; | |
103 | reiserfs_write_lock(dir->i_sb); | |
104 | ||
105 | retval = journal_begin(&th, dir->i_sb, jbegin_count); | |
106 | @@ -687,7 +701,7 @@ static int reiserfs_mknod(struct inode * | |
107 | ||
108 | retval = | |
109 | reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, | |
110 | - inode); | |
111 | + inode, &security); | |
112 | if (retval) { | |
113 | goto out_failed; | |
114 | } | |
115 | @@ -728,6 +742,7 @@ static int reiserfs_mkdir(struct inode * | |
116 | int retval; | |
117 | struct inode *inode; | |
118 | struct reiserfs_transaction_handle th; | |
119 | + struct reiserfs_security_handle security; | |
120 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | |
121 | int jbegin_count = | |
122 | JOURNAL_PER_BALANCE_CNT * 3 + | |
123 | @@ -745,6 +760,12 @@ static int reiserfs_mkdir(struct inode * | |
124 | new_inode_init(inode, dir, mode); | |
125 | ||
126 | jbegin_count += reiserfs_cache_default_acl(dir); | |
127 | + retval = reiserfs_security_init(dir, inode, &security); | |
128 | + if (retval < 0) { | |
129 | + drop_new_inode(inode); | |
130 | + return retval; | |
131 | + } | |
132 | + jbegin_count += retval; | |
133 | reiserfs_write_lock(dir->i_sb); | |
134 | ||
135 | retval = journal_begin(&th, dir->i_sb, jbegin_count); | |
136 | @@ -761,7 +782,7 @@ static int reiserfs_mkdir(struct inode * | |
137 | retval = reiserfs_new_inode(&th, dir, mode, NULL /*symlink */ , | |
138 | old_format_only(dir->i_sb) ? | |
139 | EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE, | |
140 | - dentry, inode); | |
141 | + dentry, inode, &security); | |
142 | if (retval) { | |
143 | dir->i_nlink--; | |
144 | goto out_failed; | |
145 | @@ -1002,6 +1023,7 @@ static int reiserfs_symlink(struct inode | |
146 | char *name; | |
147 | int item_len; | |
148 | struct reiserfs_transaction_handle th; | |
149 | + struct reiserfs_security_handle security; | |
150 | int mode = S_IFLNK | S_IRWXUGO; | |
151 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | |
152 | int jbegin_count = | |
153 | @@ -1014,6 +1036,13 @@ static int reiserfs_symlink(struct inode | |
154 | } | |
155 | new_inode_init(inode, parent_dir, mode); | |
156 | ||
157 | + retval = reiserfs_security_init(parent_dir, inode, &security); | |
158 | + if (retval < 0) { | |
159 | + drop_new_inode(inode); | |
160 | + return retval; | |
161 | + } | |
162 | + jbegin_count += retval; | |
163 | + | |
164 | reiserfs_write_lock(parent_dir->i_sb); | |
165 | item_len = ROUND_UP(strlen(symname)); | |
166 | if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) { | |
167 | @@ -1040,7 +1069,7 @@ static int reiserfs_symlink(struct inode | |
168 | ||
169 | retval = | |
170 | reiserfs_new_inode(&th, parent_dir, mode, name, strlen(symname), | |
171 | - dentry, inode); | |
172 | + dentry, inode, &security); | |
173 | kfree(name); | |
174 | if (retval) { /* reiserfs_new_inode iputs for us */ | |
175 | goto out_failed; | |
176 | --- a/fs/reiserfs/xattr_security.c | |
177 | +++ b/fs/reiserfs/xattr_security.c | |
178 | @@ -4,6 +4,7 @@ | |
179 | #include <linux/pagemap.h> | |
180 | #include <linux/xattr.h> | |
181 | #include <linux/reiserfs_xattr.h> | |
182 | +#include <linux/security.h> | |
183 | #include <asm/uaccess.h> | |
184 | ||
185 | static int | |
186 | @@ -47,6 +48,59 @@ static size_t security_list(struct inode | |
187 | return len; | |
188 | } | |
189 | ||
190 | +/* Initializes the security context for a new inode and returns the number | |
191 | + * of blocks needed for the transaction. If successful, reiserfs_security | |
192 | + * must be released using reiserfs_security_free when the caller is done. */ | |
193 | +int reiserfs_security_init(struct inode *dir, struct inode *inode, | |
194 | + struct reiserfs_security_handle *sec) | |
195 | +{ | |
196 | + int blocks = 0; | |
197 | + int error = security_inode_init_security(inode, dir, &sec->name, | |
198 | + &sec->value, &sec->length); | |
199 | + if (error) { | |
200 | + if (error == -EOPNOTSUPP) | |
201 | + error = 0; | |
202 | + | |
203 | + sec->name = NULL; | |
204 | + sec->value = NULL; | |
205 | + sec->length = 0; | |
206 | + return error; | |
207 | + } | |
208 | + | |
209 | + if (sec->length) { | |
210 | + blocks = reiserfs_xattr_jcreate_nblocks(inode) + | |
211 | + reiserfs_xattr_nblocks(inode, sec->length); | |
212 | + /* We don't want to count the directories twice if we have | |
213 | + * a default ACL. */ | |
214 | + REISERFS_I(inode)->i_flags |= i_has_xattr_dir; | |
215 | + } | |
216 | + return blocks; | |
217 | +} | |
218 | + | |
219 | +int reiserfs_security_write(struct reiserfs_transaction_handle *th, | |
220 | + struct inode *inode, | |
221 | + struct reiserfs_security_handle *sec) | |
222 | +{ | |
223 | + int error; | |
224 | + if (strlen(sec->name) < sizeof(XATTR_SECURITY_PREFIX)) | |
225 | + return -EINVAL; | |
226 | + | |
227 | + error = reiserfs_xattr_set_handle(th, inode, sec->name, sec->value, | |
228 | + sec->length, XATTR_CREATE); | |
229 | + if (error == -ENODATA || error == -EOPNOTSUPP) | |
230 | + error = 0; | |
231 | + | |
232 | + return error; | |
233 | +} | |
234 | + | |
235 | +void reiserfs_security_free(struct reiserfs_security_handle *sec) | |
236 | +{ | |
237 | + kfree(sec->name); | |
238 | + kfree(sec->value); | |
239 | + sec->name = NULL; | |
240 | + sec->value = NULL; | |
241 | +} | |
242 | + | |
243 | struct xattr_handler reiserfs_xattr_security_handler = { | |
244 | .prefix = XATTR_SECURITY_PREFIX, | |
245 | .get = security_get, | |
246 | --- a/include/linux/reiserfs_fs.h | |
247 | +++ b/include/linux/reiserfs_fs.h | |
248 | @@ -1915,10 +1915,12 @@ void make_le_item_head(struct item_head | |
249 | loff_t offset, int type, int length, int entry_count); | |
250 | struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key); | |
251 | ||
252 | +struct reiserfs_security_handle; | |
253 | int reiserfs_new_inode(struct reiserfs_transaction_handle *th, | |
254 | struct inode *dir, int mode, | |
255 | const char *symname, loff_t i_size, | |
256 | - struct dentry *dentry, struct inode *inode); | |
257 | + struct dentry *dentry, struct inode *inode, | |
258 | + struct reiserfs_security_handle *security); | |
259 | ||
260 | void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, | |
261 | struct inode *inode, loff_t size); | |
262 | --- a/include/linux/reiserfs_xattr.h | |
263 | +++ b/include/linux/reiserfs_xattr.h | |
264 | @@ -15,6 +15,12 @@ struct reiserfs_xattr_header { | |
265 | __le32 h_hash; /* hash of the value */ | |
266 | }; | |
267 | ||
268 | +struct reiserfs_security_handle { | |
269 | + char *name; | |
270 | + void *value; | |
271 | + size_t length; | |
272 | +}; | |
273 | + | |
274 | #ifdef __KERNEL__ | |
275 | ||
276 | #include <linux/init.h> | |
277 | @@ -54,6 +60,14 @@ int reiserfs_xattr_set_handle(struct rei | |
278 | extern struct xattr_handler reiserfs_xattr_user_handler; | |
279 | extern struct xattr_handler reiserfs_xattr_trusted_handler; | |
280 | extern struct xattr_handler reiserfs_xattr_security_handler; | |
281 | +#ifdef CONFIG_REISERFS_FS_SECURITY | |
282 | +int reiserfs_security_init(struct inode *dir, struct inode *inode, | |
283 | + struct reiserfs_security_handle *sec); | |
284 | +int reiserfs_security_write(struct reiserfs_transaction_handle *th, | |
285 | + struct inode *inode, | |
286 | + struct reiserfs_security_handle *sec); | |
287 | +void reiserfs_security_free(struct reiserfs_security_handle *sec); | |
288 | +#endif | |
289 | ||
290 | #define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header)) | |
291 | static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size) | |
292 | @@ -109,6 +123,24 @@ static inline void reiserfs_init_xattr_r | |
293 | } | |
294 | #endif /* CONFIG_REISERFS_FS_XATTR */ | |
295 | ||
296 | +#ifndef CONFIG_REISERFS_FS_SECURITY | |
297 | +static inline int reiserfs_security_init(struct inode *dir, | |
298 | + struct inode *inode, | |
299 | + struct reiserfs_security_handle *sec) | |
300 | +{ | |
301 | + return 0; | |
302 | +} | |
303 | +static inline int | |
304 | +reiserfs_security_write(struct reiserfs_transaction_handle *th, | |
305 | + struct inode *inode, | |
306 | + struct reiserfs_security_handle *sec) | |
307 | +{ | |
308 | + return 0; | |
309 | +} | |
310 | +static inline void reiserfs_security_free(struct reiserfs_security_handle *sec) | |
311 | +{} | |
312 | +#endif | |
313 | + | |
314 | #endif /* __KERNEL__ */ | |
315 | ||
316 | #endif /* _LINUX_REISERFS_XATTR_H */ |