diff options
-rw-r--r-- | fs/f2fs/Kconfig | 12 | ||||
-rw-r--r-- | fs/f2fs/acl.c | 2 | ||||
-rw-r--r-- | fs/f2fs/dir.c | 5 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 2 | ||||
-rw-r--r-- | fs/f2fs/node.c | 12 | ||||
-rw-r--r-- | fs/f2fs/xattr.c | 64 | ||||
-rw-r--r-- | fs/f2fs/xattr.h | 24 |
7 files changed, 100 insertions, 21 deletions
diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index fd27e7e6326e..e06e0995e00f 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig | |||
@@ -51,3 +51,15 @@ config F2FS_FS_POSIX_ACL | |||
51 | Linux website <http://acl.bestbits.at/>. | 51 | Linux website <http://acl.bestbits.at/>. |
52 | 52 | ||
53 | If you don't know what Access Control Lists are, say N | 53 | If you don't know what Access Control Lists are, say N |
54 | |||
55 | config F2FS_FS_SECURITY | ||
56 | bool "F2FS Security Labels" | ||
57 | depends on F2FS_FS_XATTR | ||
58 | help | ||
59 | Security labels provide an access control facility to support Linux | ||
60 | Security Models (LSMs) accepted by AppArmor, SELinux, Smack and TOMOYO | ||
61 | Linux. This option enables an extended attribute handler for file | ||
62 | security labels in the f2fs filesystem, so that it requires enabling | ||
63 | the extended attribute support in advance. | ||
64 | |||
65 | If you are not using a security module, say N. | ||
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 44abc2f286e0..b7826ec1b470 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c | |||
@@ -250,7 +250,7 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
250 | } | 250 | } |
251 | } | 251 | } |
252 | 252 | ||
253 | error = f2fs_setxattr(inode, name_index, "", value, size); | 253 | error = f2fs_setxattr(inode, name_index, "", value, size, NULL); |
254 | 254 | ||
255 | kfree(value); | 255 | kfree(value); |
256 | if (!error) | 256 | if (!error) |
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 67e2d1361fa2..eaea5b50d9c1 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "f2fs.h" | 13 | #include "f2fs.h" |
14 | #include "node.h" | 14 | #include "node.h" |
15 | #include "acl.h" | 15 | #include "acl.h" |
16 | #include "xattr.h" | ||
16 | 17 | ||
17 | static unsigned long dir_blocks(struct inode *inode) | 18 | static unsigned long dir_blocks(struct inode *inode) |
18 | { | 19 | { |
@@ -334,6 +335,10 @@ static struct page *init_inode_metadata(struct inode *inode, | |||
334 | if (err) | 335 | if (err) |
335 | goto error; | 336 | goto error; |
336 | 337 | ||
338 | err = f2fs_init_security(inode, dir, name, page); | ||
339 | if (err) | ||
340 | goto error; | ||
341 | |||
337 | wait_on_page_writeback(page); | 342 | wait_on_page_writeback(page); |
338 | } else { | 343 | } else { |
339 | page = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); | 344 | page = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d6e63da513cf..4f2c209ae8c1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -968,7 +968,7 @@ int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); | |||
968 | int truncate_inode_blocks(struct inode *, pgoff_t); | 968 | int truncate_inode_blocks(struct inode *, pgoff_t); |
969 | int remove_inode_page(struct inode *); | 969 | int remove_inode_page(struct inode *); |
970 | struct page *new_inode_page(struct inode *, const struct qstr *); | 970 | struct page *new_inode_page(struct inode *, const struct qstr *); |
971 | struct page *new_node_page(struct dnode_of_data *, unsigned int); | 971 | struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *); |
972 | void ra_node_page(struct f2fs_sb_info *, nid_t); | 972 | void ra_node_page(struct f2fs_sb_info *, nid_t); |
973 | struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); | 973 | struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); |
974 | struct page *get_node_page_ra(struct page *, int); | 974 | struct page *get_node_page_ra(struct page *, int); |
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 5a59780b22d0..b02440c5b2eb 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c | |||
@@ -433,7 +433,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) | |||
433 | } | 433 | } |
434 | 434 | ||
435 | dn->nid = nids[i]; | 435 | dn->nid = nids[i]; |
436 | npage[i] = new_node_page(dn, noffset[i]); | 436 | npage[i] = new_node_page(dn, noffset[i], NULL); |
437 | if (IS_ERR(npage[i])) { | 437 | if (IS_ERR(npage[i])) { |
438 | alloc_nid_failed(sbi, nids[i]); | 438 | alloc_nid_failed(sbi, nids[i]); |
439 | err = PTR_ERR(npage[i]); | 439 | err = PTR_ERR(npage[i]); |
@@ -814,10 +814,11 @@ struct page *new_inode_page(struct inode *inode, const struct qstr *name) | |||
814 | set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); | 814 | set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); |
815 | 815 | ||
816 | /* caller should f2fs_put_page(page, 1); */ | 816 | /* caller should f2fs_put_page(page, 1); */ |
817 | return new_node_page(&dn, 0); | 817 | return new_node_page(&dn, 0, NULL); |
818 | } | 818 | } |
819 | 819 | ||
820 | struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) | 820 | struct page *new_node_page(struct dnode_of_data *dn, |
821 | unsigned int ofs, struct page *ipage) | ||
821 | { | 822 | { |
822 | struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); | 823 | struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); |
823 | struct address_space *mapping = sbi->node_inode->i_mapping; | 824 | struct address_space *mapping = sbi->node_inode->i_mapping; |
@@ -850,7 +851,10 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) | |||
850 | set_cold_node(dn->inode, page); | 851 | set_cold_node(dn->inode, page); |
851 | 852 | ||
852 | dn->node_page = page; | 853 | dn->node_page = page; |
853 | sync_inode_page(dn); | 854 | if (ipage) |
855 | update_inode(dn->inode, ipage); | ||
856 | else | ||
857 | sync_inode_page(dn); | ||
854 | set_page_dirty(page); | 858 | set_page_dirty(page); |
855 | if (ofs == 0) | 859 | if (ofs == 0) |
856 | inc_valid_inode_count(sbi); | 860 | inc_valid_inode_count(sbi); |
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index ae61f359554f..3ab07ecd86ca 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | #include <linux/rwsem.h> | 21 | #include <linux/rwsem.h> |
22 | #include <linux/f2fs_fs.h> | 22 | #include <linux/f2fs_fs.h> |
23 | #include <linux/security.h> | ||
23 | #include "f2fs.h" | 24 | #include "f2fs.h" |
24 | #include "xattr.h" | 25 | #include "xattr.h" |
25 | 26 | ||
@@ -43,6 +44,10 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, | |||
43 | prefix = XATTR_TRUSTED_PREFIX; | 44 | prefix = XATTR_TRUSTED_PREFIX; |
44 | prefix_len = XATTR_TRUSTED_PREFIX_LEN; | 45 | prefix_len = XATTR_TRUSTED_PREFIX_LEN; |
45 | break; | 46 | break; |
47 | case F2FS_XATTR_INDEX_SECURITY: | ||
48 | prefix = XATTR_SECURITY_PREFIX; | ||
49 | prefix_len = XATTR_SECURITY_PREFIX_LEN; | ||
50 | break; | ||
46 | default: | 51 | default: |
47 | return -EINVAL; | 52 | return -EINVAL; |
48 | } | 53 | } |
@@ -50,7 +55,7 @@ static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, | |||
50 | total_len = prefix_len + name_len + 1; | 55 | total_len = prefix_len + name_len + 1; |
51 | if (list && total_len <= list_size) { | 56 | if (list && total_len <= list_size) { |
52 | memcpy(list, prefix, prefix_len); | 57 | memcpy(list, prefix, prefix_len); |
53 | memcpy(list+prefix_len, name, name_len); | 58 | memcpy(list + prefix_len, name, name_len); |
54 | list[prefix_len + name_len] = '\0'; | 59 | list[prefix_len + name_len] = '\0'; |
55 | } | 60 | } |
56 | return total_len; | 61 | return total_len; |
@@ -70,13 +75,14 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name, | |||
70 | if (!capable(CAP_SYS_ADMIN)) | 75 | if (!capable(CAP_SYS_ADMIN)) |
71 | return -EPERM; | 76 | return -EPERM; |
72 | break; | 77 | break; |
78 | case F2FS_XATTR_INDEX_SECURITY: | ||
79 | break; | ||
73 | default: | 80 | default: |
74 | return -EINVAL; | 81 | return -EINVAL; |
75 | } | 82 | } |
76 | if (strcmp(name, "") == 0) | 83 | if (strcmp(name, "") == 0) |
77 | return -EINVAL; | 84 | return -EINVAL; |
78 | return f2fs_getxattr(dentry->d_inode, type, name, | 85 | return f2fs_getxattr(dentry->d_inode, type, name, buffer, size); |
79 | buffer, size); | ||
80 | } | 86 | } |
81 | 87 | ||
82 | static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, | 88 | static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, |
@@ -93,13 +99,15 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, | |||
93 | if (!capable(CAP_SYS_ADMIN)) | 99 | if (!capable(CAP_SYS_ADMIN)) |
94 | return -EPERM; | 100 | return -EPERM; |
95 | break; | 101 | break; |
102 | case F2FS_XATTR_INDEX_SECURITY: | ||
103 | break; | ||
96 | default: | 104 | default: |
97 | return -EINVAL; | 105 | return -EINVAL; |
98 | } | 106 | } |
99 | if (strcmp(name, "") == 0) | 107 | if (strcmp(name, "") == 0) |
100 | return -EINVAL; | 108 | return -EINVAL; |
101 | 109 | ||
102 | return f2fs_setxattr(dentry->d_inode, type, name, value, size); | 110 | return f2fs_setxattr(dentry->d_inode, type, name, value, size, NULL); |
103 | } | 111 | } |
104 | 112 | ||
105 | static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, | 113 | static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, |
@@ -145,6 +153,31 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, | |||
145 | return 0; | 153 | return 0; |
146 | } | 154 | } |
147 | 155 | ||
156 | #ifdef CONFIG_F2FS_FS_SECURITY | ||
157 | static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, | ||
158 | void *page) | ||
159 | { | ||
160 | const struct xattr *xattr; | ||
161 | int err = 0; | ||
162 | |||
163 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { | ||
164 | err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY, | ||
165 | xattr->name, xattr->value, | ||
166 | xattr->value_len, (struct page *)page); | ||
167 | if (err < 0) | ||
168 | break; | ||
169 | } | ||
170 | return err; | ||
171 | } | ||
172 | |||
173 | int f2fs_init_security(struct inode *inode, struct inode *dir, | ||
174 | const struct qstr *qstr, struct page *ipage) | ||
175 | { | ||
176 | return security_inode_init_security(inode, dir, qstr, | ||
177 | &f2fs_initxattrs, ipage); | ||
178 | } | ||
179 | #endif | ||
180 | |||
148 | const struct xattr_handler f2fs_xattr_user_handler = { | 181 | const struct xattr_handler f2fs_xattr_user_handler = { |
149 | .prefix = XATTR_USER_PREFIX, | 182 | .prefix = XATTR_USER_PREFIX, |
150 | .flags = F2FS_XATTR_INDEX_USER, | 183 | .flags = F2FS_XATTR_INDEX_USER, |
@@ -169,6 +202,14 @@ const struct xattr_handler f2fs_xattr_advise_handler = { | |||
169 | .set = f2fs_xattr_advise_set, | 202 | .set = f2fs_xattr_advise_set, |
170 | }; | 203 | }; |
171 | 204 | ||
205 | const struct xattr_handler f2fs_xattr_security_handler = { | ||
206 | .prefix = XATTR_SECURITY_PREFIX, | ||
207 | .flags = F2FS_XATTR_INDEX_SECURITY, | ||
208 | .list = f2fs_xattr_generic_list, | ||
209 | .get = f2fs_xattr_generic_get, | ||
210 | .set = f2fs_xattr_generic_set, | ||
211 | }; | ||
212 | |||
172 | static const struct xattr_handler *f2fs_xattr_handler_map[] = { | 213 | static const struct xattr_handler *f2fs_xattr_handler_map[] = { |
173 | [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, | 214 | [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, |
174 | #ifdef CONFIG_F2FS_FS_POSIX_ACL | 215 | #ifdef CONFIG_F2FS_FS_POSIX_ACL |
@@ -176,6 +217,9 @@ static const struct xattr_handler *f2fs_xattr_handler_map[] = { | |||
176 | [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, | 217 | [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, |
177 | #endif | 218 | #endif |
178 | [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, | 219 | [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, |
220 | #ifdef CONFIG_F2FS_FS_SECURITY | ||
221 | [F2FS_XATTR_INDEX_SECURITY] = &f2fs_xattr_security_handler, | ||
222 | #endif | ||
179 | [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler, | 223 | [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler, |
180 | }; | 224 | }; |
181 | 225 | ||
@@ -186,6 +230,9 @@ const struct xattr_handler *f2fs_xattr_handlers[] = { | |||
186 | &f2fs_xattr_acl_default_handler, | 230 | &f2fs_xattr_acl_default_handler, |
187 | #endif | 231 | #endif |
188 | &f2fs_xattr_trusted_handler, | 232 | &f2fs_xattr_trusted_handler, |
233 | #ifdef CONFIG_F2FS_FS_SECURITY | ||
234 | &f2fs_xattr_security_handler, | ||
235 | #endif | ||
189 | &f2fs_xattr_advise_handler, | 236 | &f2fs_xattr_advise_handler, |
190 | NULL, | 237 | NULL, |
191 | }; | 238 | }; |
@@ -300,7 +347,7 @@ cleanup: | |||
300 | } | 347 | } |
301 | 348 | ||
302 | int f2fs_setxattr(struct inode *inode, int name_index, const char *name, | 349 | int f2fs_setxattr(struct inode *inode, int name_index, const char *name, |
303 | const void *value, size_t value_len) | 350 | const void *value, size_t value_len, struct page *ipage) |
304 | { | 351 | { |
305 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); | 352 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); |
306 | struct f2fs_inode_info *fi = F2FS_I(inode); | 353 | struct f2fs_inode_info *fi = F2FS_I(inode); |
@@ -339,7 +386,7 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, | |||
339 | set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); | 386 | set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); |
340 | mark_inode_dirty(inode); | 387 | mark_inode_dirty(inode); |
341 | 388 | ||
342 | page = new_node_page(&dn, XATTR_NODE_OFFSET); | 389 | page = new_node_page(&dn, XATTR_NODE_OFFSET, ipage); |
343 | if (IS_ERR(page)) { | 390 | if (IS_ERR(page)) { |
344 | alloc_nid_failed(sbi, fi->i_xattr_nid); | 391 | alloc_nid_failed(sbi, fi->i_xattr_nid); |
345 | fi->i_xattr_nid = 0; | 392 | fi->i_xattr_nid = 0; |
@@ -439,7 +486,10 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name, | |||
439 | inode->i_ctime = CURRENT_TIME; | 486 | inode->i_ctime = CURRENT_TIME; |
440 | clear_inode_flag(fi, FI_ACL_MODE); | 487 | clear_inode_flag(fi, FI_ACL_MODE); |
441 | } | 488 | } |
442 | update_inode_page(inode); | 489 | if (ipage) |
490 | update_inode(inode, ipage); | ||
491 | else | ||
492 | update_inode_page(inode); | ||
443 | mutex_unlock_op(sbi, ilock); | 493 | mutex_unlock_op(sbi, ilock); |
444 | 494 | ||
445 | return 0; | 495 | return 0; |
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 49c9558305e3..3c0817bef25d 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h | |||
@@ -112,21 +112,19 @@ extern const struct xattr_handler f2fs_xattr_trusted_handler; | |||
112 | extern const struct xattr_handler f2fs_xattr_acl_access_handler; | 112 | extern const struct xattr_handler f2fs_xattr_acl_access_handler; |
113 | extern const struct xattr_handler f2fs_xattr_acl_default_handler; | 113 | extern const struct xattr_handler f2fs_xattr_acl_default_handler; |
114 | extern const struct xattr_handler f2fs_xattr_advise_handler; | 114 | extern const struct xattr_handler f2fs_xattr_advise_handler; |
115 | extern const struct xattr_handler f2fs_xattr_security_handler; | ||
115 | 116 | ||
116 | extern const struct xattr_handler *f2fs_xattr_handlers[]; | 117 | extern const struct xattr_handler *f2fs_xattr_handlers[]; |
117 | 118 | ||
118 | extern int f2fs_setxattr(struct inode *inode, int name_index, const char *name, | 119 | extern int f2fs_setxattr(struct inode *, int, const char *, |
119 | const void *value, size_t value_len); | 120 | const void *, size_t, struct page *); |
120 | extern int f2fs_getxattr(struct inode *inode, int name_index, const char *name, | 121 | extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t); |
121 | void *buffer, size_t buffer_size); | 122 | extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); |
122 | extern ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, | ||
123 | size_t buffer_size); | ||
124 | |||
125 | #else | 123 | #else |
126 | 124 | ||
127 | #define f2fs_xattr_handlers NULL | 125 | #define f2fs_xattr_handlers NULL |
128 | static inline int f2fs_setxattr(struct inode *inode, int name_index, | 126 | static inline int f2fs_setxattr(struct inode *inode, int name_index, |
129 | const char *name, const void *value, size_t value_len) | 127 | const char *name, const void *value, size_t value_len) |
130 | { | 128 | { |
131 | return -EOPNOTSUPP; | 129 | return -EOPNOTSUPP; |
132 | } | 130 | } |
@@ -142,4 +140,14 @@ static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, | |||
142 | } | 140 | } |
143 | #endif | 141 | #endif |
144 | 142 | ||
143 | #ifdef CONFIG_F2FS_FS_SECURITY | ||
144 | extern int f2fs_init_security(struct inode *, struct inode *, | ||
145 | const struct qstr *, struct page *); | ||
146 | #else | ||
147 | static inline int f2fs_init_security(struct inode *inode, struct inode *dir, | ||
148 | const struct qstr *qstr, struct page *ipage) | ||
149 | { | ||
150 | return 0; | ||
151 | } | ||
152 | #endif | ||
145 | #endif /* __F2FS_XATTR_H__ */ | 153 | #endif /* __F2FS_XATTR_H__ */ |