1 /**
2 * xattr.c
3 *
4 * Many parts of codes are copied from Linux kernel/fs/f2fs.
5 *
6 * Copyright (C) 2015 Huawei Ltd.
7 * Witten by:
8 * Hou Pengyang <houpengyang@huawei.com>
9 * Liu Shuoran <liushuoran@huawei.com>
10 * Jaegeuk Kim <jaegeuk@kernel.org>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16 #include "fsck.h"
17 #include "node.h"
18 #include "xattr.h"
19
read_all_xattrs(struct f2fs_sb_info * sbi,struct f2fs_node * inode,bool sanity_check)20 void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
21 bool sanity_check)
22 {
23 struct f2fs_xattr_header *header;
24 void *txattr_addr;
25 u64 inline_size = inline_xattr_size(&inode->i);
26 nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
27
28 if (c.func == FSCK && xnid && sanity_check) {
29 struct f2fs_node *node_blk = NULL;
30 struct node_info ni;
31 int ret;
32
33 node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
34 ASSERT(node_blk != NULL);
35
36 ret = fsck_sanity_check_nid(sbi, xnid, node_blk,
37 F2FS_FT_XATTR, TYPE_XATTR, &ni);
38 free(node_blk);
39 if (ret)
40 return NULL;
41 }
42
43 txattr_addr = calloc(inline_size + BLOCK_SZ, 1);
44 ASSERT(txattr_addr);
45
46 if (inline_size)
47 memcpy(txattr_addr, inline_xattr_addr(&inode->i), inline_size);
48
49 /* Read from xattr node block. */
50 if (xnid) {
51 struct node_info ni;
52 int ret;
53
54 get_node_info(sbi, xnid, &ni);
55 ret = dev_read_block(txattr_addr + inline_size, ni.blk_addr);
56 ASSERT(ret >= 0);
57 }
58
59 header = XATTR_HDR(txattr_addr);
60
61 /* Never been allocated xattrs */
62 if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
63 header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
64 header->h_refcount = cpu_to_le32(1);
65 }
66 return txattr_addr;
67 }
68
__find_xattr(void * base_addr,void * last_base_addr,int index,size_t len,const char * name)69 static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
70 void *last_base_addr, int index,
71 size_t len, const char *name)
72 {
73 struct f2fs_xattr_entry *entry;
74
75 list_for_each_xattr(entry, base_addr) {
76 if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
77 (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
78 MSG(0, "xattr entry crosses the end of xattr space\n");
79 return NULL;
80 }
81
82 if (entry->e_name_index != index)
83 continue;
84 if (entry->e_name_len != len)
85 continue;
86 if (!memcmp(entry->e_name, name, len))
87 break;
88 }
89 return entry;
90 }
91
write_all_xattrs(struct f2fs_sb_info * sbi,struct f2fs_node * inode,__u32 hsize,void * txattr_addr)92 void write_all_xattrs(struct f2fs_sb_info *sbi,
93 struct f2fs_node *inode, __u32 hsize, void *txattr_addr)
94 {
95 void *xattr_addr;
96 struct dnode_of_data dn;
97 struct node_info ni;
98 struct f2fs_node *xattr_node;
99 nid_t new_nid = 0;
100 block_t blkaddr;
101 nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
102 u64 inline_size = inline_xattr_size(&inode->i);
103 int ret;
104
105 memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size);
106
107 if (hsize <= inline_size)
108 return;
109
110 if (!xnid) {
111 f2fs_alloc_nid(sbi, &new_nid);
112
113 set_new_dnode(&dn, inode, NULL, new_nid);
114 /* NAT entry would be updated by new_node_page. */
115 blkaddr = new_node_block(sbi, &dn, XATTR_NODE_OFFSET);
116 ASSERT(dn.node_blk);
117 xattr_node = dn.node_blk;
118 inode->i.i_xattr_nid = cpu_to_le32(new_nid);
119 } else {
120 set_new_dnode(&dn, inode, NULL, xnid);
121 get_node_info(sbi, xnid, &ni);
122 blkaddr = ni.blk_addr;
123 xattr_node = calloc(BLOCK_SZ, 1);
124 ASSERT(xattr_node);
125 ret = dev_read_block(xattr_node, ni.blk_addr);
126 if (ret < 0)
127 goto free_xattr_node;
128 }
129
130 /* write to xattr node block */
131 xattr_addr = (void *)xattr_node;
132 memcpy(xattr_addr, txattr_addr + inline_size,
133 F2FS_BLKSIZE - sizeof(struct node_footer));
134
135 ret = dev_write_block(xattr_node, blkaddr);
136
137 free_xattr_node:
138 free(xattr_node);
139 ASSERT(ret >= 0);
140 }
141
f2fs_setxattr(struct f2fs_sb_info * sbi,nid_t ino,int index,const char * name,const void * value,size_t size,int flags)142 int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *name,
143 const void *value, size_t size, int flags)
144 {
145 struct f2fs_node *inode;
146 void *base_addr;
147 void *last_base_addr;
148 struct f2fs_xattr_entry *here, *last;
149 struct node_info ni;
150 int error = 0;
151 int len;
152 int found, newsize;
153 __u32 new_hsize;
154 int ret;
155
156 if (name == NULL)
157 return -EINVAL;
158
159 if (value == NULL)
160 return -EINVAL;
161
162 len = strlen(name);
163
164 if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN)
165 return -ERANGE;
166
167 if (ino < 3)
168 return -EINVAL;
169
170 /* Now We just support selinux */
171 ASSERT(index == F2FS_XATTR_INDEX_SECURITY);
172
173 get_node_info(sbi, ino, &ni);
174 inode = calloc(BLOCK_SZ, 1);
175 ASSERT(inode);
176 ret = dev_read_block(inode, ni.blk_addr);
177 ASSERT(ret >= 0);
178
179 base_addr = read_all_xattrs(sbi, inode, true);
180 ASSERT(base_addr);
181
182 last_base_addr = (void *)base_addr + XATTR_SIZE(&inode->i);
183
184 here = __find_xattr(base_addr, last_base_addr, index, len, name);
185 if (!here) {
186 MSG(0, "Need to run fsck due to corrupted xattr.\n");
187 error = -EINVAL;
188 goto exit;
189 }
190
191 found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
192
193 if ((flags & XATTR_REPLACE) && !found) {
194 error = -ENODATA;
195 goto exit;
196 } else if ((flags & XATTR_CREATE) && found) {
197 error = -EEXIST;
198 goto exit;
199 }
200
201 last = here;
202 while (!IS_XATTR_LAST_ENTRY(last))
203 last = XATTR_NEXT_ENTRY(last);
204
205 newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
206
207 /* 1. Check space */
208 if (value) {
209 int free;
210 /*
211 * If value is NULL, it is remove operation.
212 * In case of update operation, we calculate free.
213 */
214 free = MIN_OFFSET - ((char *)last - (char *)base_addr);
215 if (found)
216 free = free + ENTRY_SIZE(here);
217 if (free < newsize) {
218 error = -ENOSPC;
219 goto exit;
220 }
221 }
222
223 /* 2. Remove old entry */
224 if (found) {
225 /*
226 * If entry if sound, remove old entry.
227 * If not found, remove operation is not needed
228 */
229 struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
230 int oldsize = ENTRY_SIZE(here);
231
232 memmove(here, next, (char *)last - (char *)next);
233 last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
234 memset(last, 0, oldsize);
235
236 }
237
238 new_hsize = (char *)last - (char *)base_addr;
239
240 /* 3. Write new entry */
241 if (value) {
242 char *pval;
243 /*
244 * Before we come here, old entry is removed.
245 * We just write new entry.
246 */
247 memset(last, 0, newsize);
248 last->e_name_index = index;
249 last->e_name_len = len;
250 memcpy(last->e_name, name, len);
251 pval = last->e_name + len;
252 memcpy(pval, value, size);
253 last->e_value_size = cpu_to_le16(size);
254 new_hsize += newsize;
255 }
256
257 write_all_xattrs(sbi, inode, new_hsize, base_addr);
258
259 /* inode need update */
260 ASSERT(write_inode(inode, ni.blk_addr) >= 0);
261 exit:
262 free(inode);
263 free(base_addr);
264 return error;
265 }
266
inode_set_selinux(struct f2fs_sb_info * sbi,u32 ino,const char * secon)267 int inode_set_selinux(struct f2fs_sb_info *sbi, u32 ino, const char *secon)
268 {
269 if (!secon)
270 return 0;
271
272 return f2fs_setxattr(sbi, ino, F2FS_XATTR_INDEX_SECURITY,
273 XATTR_SELINUX_SUFFIX, secon, strlen(secon), 1);
274 }
275