diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2015-05-09 23:09:14 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-21 13:10:00 -0400 |
commit | bdbdf7ee9d561da7b4b840435c963344061953d6 (patch) | |
tree | b28ada9ded70b0e552f65f674e3b08f58a2a453a /fs/proc | |
parent | c2f633b99857d27333de18f53d123a180672c52b (diff) |
sysctl: Allow creating permanently empty directories that serve as mountpoints.
commit f9bd6733d3f11e24f3949becf277507d422ee1eb upstream.
Add a magic sysctl table sysctl_mount_point that when used to
create a directory forces that directory to be permanently empty.
Update the code to use make_empty_dir_inode when accessing permanently
empty directories.
Update the code to not allow adding to permanently empty directories.
Update /proc/sys/fs/binfmt_misc to be a permanently empty directory.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/proc_sysctl.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fea2561d773b..fdda62e6115e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations; | |||
19 | static const struct file_operations proc_sys_dir_file_operations; | 19 | static const struct file_operations proc_sys_dir_file_operations; |
20 | static const struct inode_operations proc_sys_dir_operations; | 20 | static const struct inode_operations proc_sys_dir_operations; |
21 | 21 | ||
22 | /* Support for permanently empty directories */ | ||
23 | |||
24 | struct ctl_table sysctl_mount_point[] = { | ||
25 | { } | ||
26 | }; | ||
27 | |||
28 | static bool is_empty_dir(struct ctl_table_header *head) | ||
29 | { | ||
30 | return head->ctl_table[0].child == sysctl_mount_point; | ||
31 | } | ||
32 | |||
33 | static void set_empty_dir(struct ctl_dir *dir) | ||
34 | { | ||
35 | dir->header.ctl_table[0].child = sysctl_mount_point; | ||
36 | } | ||
37 | |||
38 | static void clear_empty_dir(struct ctl_dir *dir) | ||
39 | |||
40 | { | ||
41 | dir->header.ctl_table[0].child = NULL; | ||
42 | } | ||
43 | |||
22 | void proc_sys_poll_notify(struct ctl_table_poll *poll) | 44 | void proc_sys_poll_notify(struct ctl_table_poll *poll) |
23 | { | 45 | { |
24 | if (!poll) | 46 | if (!poll) |
@@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) | |||
187 | struct ctl_table *entry; | 209 | struct ctl_table *entry; |
188 | int err; | 210 | int err; |
189 | 211 | ||
212 | /* Is this a permanently empty directory? */ | ||
213 | if (is_empty_dir(&dir->header)) | ||
214 | return -EROFS; | ||
215 | |||
216 | /* Am I creating a permanently empty directory? */ | ||
217 | if (header->ctl_table == sysctl_mount_point) { | ||
218 | if (!RB_EMPTY_ROOT(&dir->root)) | ||
219 | return -EINVAL; | ||
220 | set_empty_dir(dir); | ||
221 | } | ||
222 | |||
190 | dir->header.nreg++; | 223 | dir->header.nreg++; |
191 | header->parent = dir; | 224 | header->parent = dir; |
192 | err = insert_links(header); | 225 | err = insert_links(header); |
@@ -202,6 +235,8 @@ fail: | |||
202 | erase_header(header); | 235 | erase_header(header); |
203 | put_links(header); | 236 | put_links(header); |
204 | fail_links: | 237 | fail_links: |
238 | if (header->ctl_table == sysctl_mount_point) | ||
239 | clear_empty_dir(dir); | ||
205 | header->parent = NULL; | 240 | header->parent = NULL; |
206 | drop_sysctl_table(&dir->header); | 241 | drop_sysctl_table(&dir->header); |
207 | return err; | 242 | return err; |
@@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, | |||
419 | inode->i_mode |= S_IFDIR; | 454 | inode->i_mode |= S_IFDIR; |
420 | inode->i_op = &proc_sys_dir_operations; | 455 | inode->i_op = &proc_sys_dir_operations; |
421 | inode->i_fop = &proc_sys_dir_file_operations; | 456 | inode->i_fop = &proc_sys_dir_file_operations; |
457 | if (is_empty_dir(head)) | ||
458 | make_empty_dir_inode(inode); | ||
422 | } | 459 | } |
423 | out: | 460 | out: |
424 | return inode; | 461 | return inode; |