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