1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Originally contributed by an anonymous person,
4 * heavily changed by Li Guifu <blucerlee@gmail.com>
5 * and Gao Xiang <hsiangkao@aol.com>
6 */
7 #define _GNU_SOURCE
8 #include <stdlib.h>
9 #include <sys/xattr.h>
10 #ifdef HAVE_LINUX_XATTR_H
11 #include <linux/xattr.h>
12 #endif
13 #include <sys/stat.h>
14 #include <dirent.h>
15 #include "erofs/print.h"
16 #include "erofs/hashtable.h"
17 #include "erofs/xattr.h"
18 #include "erofs/cache.h"
19 #include "erofs/io.h"
20 #include "liberofs_private.h"
21
22 #define EA_HASHTABLE_BITS 16
23
24 struct xattr_item {
25 const char *kvbuf;
26 unsigned int hash[2], len[2], count;
27 int shared_xattr_id;
28 u8 prefix;
29 struct hlist_node node;
30 };
31
32 struct inode_xattr_node {
33 struct list_head list;
34 struct xattr_item *item;
35 };
36
37 static DECLARE_HASHTABLE(ea_hashtable, EA_HASHTABLE_BITS);
38
39 static LIST_HEAD(shared_xattrs_list);
40 static unsigned int shared_xattrs_count, shared_xattrs_size;
41
42 static struct xattr_prefix {
43 const char *prefix;
44 u16 prefix_len;
45 } xattr_types[] = {
46 [EROFS_XATTR_INDEX_USER] = {
47 XATTR_USER_PREFIX,
48 XATTR_USER_PREFIX_LEN
49 }, [EROFS_XATTR_INDEX_POSIX_ACL_ACCESS] = {
50 XATTR_NAME_POSIX_ACL_ACCESS,
51 sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
52 }, [EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT] = {
53 XATTR_NAME_POSIX_ACL_DEFAULT,
54 sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1
55 }, [EROFS_XATTR_INDEX_TRUSTED] = {
56 XATTR_TRUSTED_PREFIX,
57 XATTR_TRUSTED_PREFIX_LEN
58 }, [EROFS_XATTR_INDEX_SECURITY] = {
59 XATTR_SECURITY_PREFIX,
60 XATTR_SECURITY_PREFIX_LEN
61 }
62 };
63
BKDRHash(char * str,unsigned int len)64 static unsigned int BKDRHash(char *str, unsigned int len)
65 {
66 const unsigned int seed = 131313;
67 unsigned int hash = 0;
68
69 while (len) {
70 hash = hash * seed + (*str++);
71 --len;
72 }
73 return hash;
74 }
75
xattr_item_hash(u8 prefix,char * buf,unsigned int len[2],unsigned int hash[2])76 static unsigned int xattr_item_hash(u8 prefix, char *buf,
77 unsigned int len[2], unsigned int hash[2])
78 {
79 hash[0] = BKDRHash(buf, len[0]); /* key */
80 hash[1] = BKDRHash(buf + len[0], len[1]); /* value */
81
82 return prefix ^ hash[0] ^ hash[1];
83 }
84
put_xattritem(struct xattr_item * item)85 static unsigned int put_xattritem(struct xattr_item *item)
86 {
87 if (item->count > 1)
88 return --item->count;
89 free(item);
90 return 0;
91 }
92
get_xattritem(u8 prefix,char * kvbuf,unsigned int len[2])93 static struct xattr_item *get_xattritem(u8 prefix, char *kvbuf,
94 unsigned int len[2])
95 {
96 struct xattr_item *item;
97 unsigned int hash[2], hkey;
98
99 hkey = xattr_item_hash(prefix, kvbuf, len, hash);
100
101 hash_for_each_possible(ea_hashtable, item, node, hkey) {
102 if (prefix == item->prefix &&
103 item->len[0] == len[0] && item->len[1] == len[1] &&
104 item->hash[0] == hash[0] && item->hash[1] == hash[1] &&
105 !memcmp(kvbuf, item->kvbuf, len[0] + len[1])) {
106 free(kvbuf);
107 ++item->count;
108 return item;
109 }
110 }
111
112 item = malloc(sizeof(*item));
113 if (!item) {
114 free(kvbuf);
115 return ERR_PTR(-ENOMEM);
116 }
117 INIT_HLIST_NODE(&item->node);
118 item->count = 1;
119 item->kvbuf = kvbuf;
120 item->len[0] = len[0];
121 item->len[1] = len[1];
122 item->hash[0] = hash[0];
123 item->hash[1] = hash[1];
124 item->shared_xattr_id = -1;
125 item->prefix = prefix;
126 hash_add(ea_hashtable, &item->node, hkey);
127 return item;
128 }
129
match_prefix(const char * key,u8 * index,u16 * len)130 static bool match_prefix(const char *key, u8 *index, u16 *len)
131 {
132 struct xattr_prefix *p;
133
134 for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) {
135 if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) {
136 *len = p->prefix_len;
137 *index = p - xattr_types;
138 return true;
139 }
140 }
141 return false;
142 }
143
parse_one_xattr(const char * path,const char * key,unsigned int keylen)144 static struct xattr_item *parse_one_xattr(const char *path, const char *key,
145 unsigned int keylen)
146 {
147 ssize_t ret;
148 u8 prefix;
149 u16 prefixlen;
150 unsigned int len[2];
151 char *kvbuf;
152
153 erofs_dbg("parse xattr [%s] of %s", path, key);
154
155 if (!match_prefix(key, &prefix, &prefixlen))
156 return ERR_PTR(-ENODATA);
157
158 DBG_BUGON(keylen < prefixlen);
159
160 /* determine length of the value */
161 #ifdef HAVE_LGETXATTR
162 ret = lgetxattr(path, key, NULL, 0);
163 #elif defined(__APPLE__)
164 ret = getxattr(path, key, NULL, 0, 0, XATTR_NOFOLLOW);
165 #else
166 return ERR_PTR(-EOPNOTSUPP);
167 #endif
168 if (ret < 0)
169 return ERR_PTR(-errno);
170 len[1] = ret;
171
172 /* allocate key-value buffer */
173 len[0] = keylen - prefixlen;
174
175 kvbuf = malloc(len[0] + len[1]);
176 if (!kvbuf)
177 return ERR_PTR(-ENOMEM);
178 memcpy(kvbuf, key + prefixlen, len[0]);
179 if (len[1]) {
180 /* copy value to buffer */
181 #ifdef HAVE_LGETXATTR
182 ret = lgetxattr(path, key, kvbuf + len[0], len[1]);
183 #elif defined(__APPLE__)
184 ret = getxattr(path, key, kvbuf + len[0], len[1], 0,
185 XATTR_NOFOLLOW);
186 #else
187 free(kvbuf);
188 return ERR_PTR(-EOPNOTSUPP);
189 #endif
190 if (ret < 0) {
191 free(kvbuf);
192 return ERR_PTR(-errno);
193 }
194 if (len[1] != ret) {
195 erofs_err("size of xattr value got changed just now (%u-> %ld)",
196 len[1], (long)ret);
197 len[1] = ret;
198 }
199 }
200 return get_xattritem(prefix, kvbuf, len);
201 }
202
erofs_get_selabel_xattr(const char * srcpath,mode_t mode)203 static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
204 mode_t mode)
205 {
206 #ifdef HAVE_LIBSELINUX
207 if (cfg.sehnd) {
208 char *secontext;
209 int ret;
210 unsigned int len[2];
211 char *kvbuf, *fspath;
212
213 #ifdef WITH_ANDROID
214 if (cfg.mount_point)
215 ret = asprintf(&fspath, "/%s/%s", cfg.mount_point,
216 erofs_fspath(srcpath));
217 else
218 #endif
219 ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
220 if (ret <= 0)
221 return ERR_PTR(-ENOMEM);
222
223 ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
224 free(fspath);
225
226 if (ret) {
227 ret = -errno;
228 if (ret != -ENOENT) {
229 erofs_err("failed to lookup selabel for %s: %s",
230 srcpath, erofs_strerror(ret));
231 return ERR_PTR(ret);
232 }
233 /* secontext = "u:object_r:unlabeled:s0"; */
234 return NULL;
235 }
236
237 len[0] = sizeof("selinux") - 1;
238 len[1] = strlen(secontext);
239 kvbuf = malloc(len[0] + len[1] + 1);
240 if (!kvbuf) {
241 freecon(secontext);
242 return ERR_PTR(-ENOMEM);
243 }
244 sprintf(kvbuf, "selinux%s", secontext);
245 freecon(secontext);
246 return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
247 }
248 #endif
249 return NULL;
250 }
251
inode_xattr_add(struct list_head * hlist,struct xattr_item * item)252 static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
253 {
254 struct inode_xattr_node *node = malloc(sizeof(*node));
255
256 if (!node)
257 return -ENOMEM;
258 init_list_head(&node->list);
259 node->item = item;
260 list_add(&node->list, hlist);
261 return 0;
262 }
263
shared_xattr_add(struct xattr_item * item)264 static int shared_xattr_add(struct xattr_item *item)
265 {
266 struct inode_xattr_node *node = malloc(sizeof(*node));
267
268 if (!node)
269 return -ENOMEM;
270
271 init_list_head(&node->list);
272 node->item = item;
273 list_add(&node->list, &shared_xattrs_list);
274
275 shared_xattrs_size += sizeof(struct erofs_xattr_entry);
276 shared_xattrs_size = EROFS_XATTR_ALIGN(shared_xattrs_size +
277 item->len[0] + item->len[1]);
278 return ++shared_xattrs_count;
279 }
280
erofs_xattr_add(struct list_head * ixattrs,struct xattr_item * item)281 static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
282 {
283 if (ixattrs)
284 return inode_xattr_add(ixattrs, item);
285
286 if (item->count == cfg.c_inline_xattr_tolerance + 1) {
287 int ret = shared_xattr_add(item);
288
289 if (ret < 0)
290 return ret;
291 }
292 return 0;
293 }
294
erofs_is_skipped_xattr(const char * key)295 static bool erofs_is_skipped_xattr(const char *key)
296 {
297 #ifdef HAVE_LIBSELINUX
298 /* if sehnd is valid, selabels will be overridden */
299 if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
300 return true;
301 #endif
302 return false;
303 }
304
read_xattrs_from_file(const char * path,mode_t mode,struct list_head * ixattrs)305 static int read_xattrs_from_file(const char *path, mode_t mode,
306 struct list_head *ixattrs)
307 {
308 #ifdef HAVE_LLISTXATTR
309 ssize_t kllen = llistxattr(path, NULL, 0);
310 #elif defined(__APPLE__)
311 ssize_t kllen = listxattr(path, NULL, 0, XATTR_NOFOLLOW);
312 #else
313 ssize_t kllen = 0;
314 #endif
315 int ret;
316 char *keylst, *key, *klend;
317 unsigned int keylen;
318 struct xattr_item *item;
319
320 if (kllen < 0 && errno != ENODATA) {
321 erofs_err("llistxattr to get the size of names for %s failed",
322 path);
323 return -errno;
324 }
325
326 ret = 0;
327 if (kllen <= 1)
328 goto out;
329
330 keylst = malloc(kllen);
331 if (!keylst)
332 return -ENOMEM;
333
334 /* copy the list of attribute keys to the buffer.*/
335 #ifdef HAVE_LLISTXATTR
336 kllen = llistxattr(path, keylst, kllen);
337 #elif defined(__APPLE__)
338 kllen = listxattr(path, keylst, kllen, XATTR_NOFOLLOW);
339 if (kllen < 0) {
340 erofs_err("llistxattr to get names for %s failed", path);
341 ret = -errno;
342 goto err;
343 }
344 #else
345 ret = -EOPNOTSUPP;
346 goto err;
347 #endif
348 /*
349 * loop over the list of zero terminated strings with the
350 * attribute keys. Use the remaining buffer length to determine
351 * the end of the list.
352 */
353 klend = keylst + kllen;
354 ret = 0;
355
356 for (key = keylst; key != klend; key += keylen + 1) {
357 keylen = strlen(key);
358 if (erofs_is_skipped_xattr(key))
359 continue;
360
361 item = parse_one_xattr(path, key, keylen);
362 if (IS_ERR(item)) {
363 ret = PTR_ERR(item);
364 goto err;
365 }
366
367 ret = erofs_xattr_add(ixattrs, item);
368 if (ret < 0)
369 goto err;
370 }
371 free(keylst);
372
373 out:
374 /* if some selabel is avilable, need to add right now */
375 item = erofs_get_selabel_xattr(path, mode);
376 if (IS_ERR(item))
377 return PTR_ERR(item);
378 if (item)
379 ret = erofs_xattr_add(ixattrs, item);
380 return ret;
381
382 err:
383 free(keylst);
384 return ret;
385 }
386
387 #ifdef WITH_ANDROID
erofs_droid_xattr_set_caps(struct erofs_inode * inode)388 static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
389 {
390 const u64 capabilities = inode->capabilities;
391 char *kvbuf;
392 unsigned int len[2];
393 struct vfs_cap_data caps;
394 struct xattr_item *item;
395
396 if (!capabilities)
397 return 0;
398
399 len[0] = sizeof("capability") - 1;
400 len[1] = sizeof(caps);
401
402 kvbuf = malloc(len[0] + len[1]);
403 if (!kvbuf)
404 return -ENOMEM;
405
406 memcpy(kvbuf, "capability", len[0]);
407 caps.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
408 caps.data[0].permitted = (u32) capabilities;
409 caps.data[0].inheritable = 0;
410 caps.data[1].permitted = (u32) (capabilities >> 32);
411 caps.data[1].inheritable = 0;
412 memcpy(kvbuf + len[0], &caps, len[1]);
413
414 item = get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
415 if (IS_ERR(item))
416 return PTR_ERR(item);
417 if (!item)
418 return 0;
419
420 return erofs_xattr_add(&inode->i_xattrs, item);
421 }
422 #else
erofs_droid_xattr_set_caps(struct erofs_inode * inode)423 static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
424 {
425 return 0;
426 }
427 #endif
428
erofs_prepare_xattr_ibody(struct erofs_inode * inode)429 int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
430 {
431 int ret;
432 struct inode_xattr_node *node;
433 struct list_head *ixattrs = &inode->i_xattrs;
434
435 /* check if xattr is disabled */
436 if (cfg.c_inline_xattr_tolerance < 0)
437 return 0;
438
439 ret = read_xattrs_from_file(inode->i_srcpath, inode->i_mode, ixattrs);
440 if (ret < 0)
441 return ret;
442
443 ret = erofs_droid_xattr_set_caps(inode);
444 if (ret < 0)
445 return ret;
446
447 if (list_empty(ixattrs))
448 return 0;
449
450 /* get xattr ibody size */
451 ret = sizeof(struct erofs_xattr_ibody_header);
452 list_for_each_entry(node, ixattrs, list) {
453 const struct xattr_item *item = node->item;
454
455 if (item->shared_xattr_id >= 0) {
456 ret += sizeof(__le32);
457 continue;
458 }
459 ret += sizeof(struct erofs_xattr_entry);
460 ret = EROFS_XATTR_ALIGN(ret + item->len[0] + item->len[1]);
461 }
462 inode->xattr_isize = ret;
463 return ret;
464 }
465
erofs_count_all_xattrs_from_path(const char * path)466 static int erofs_count_all_xattrs_from_path(const char *path)
467 {
468 int ret;
469 DIR *_dir;
470 struct stat64 st;
471
472 _dir = opendir(path);
473 if (!_dir) {
474 erofs_err("failed to opendir at %s: %s",
475 path, erofs_strerror(errno));
476 return -errno;
477 }
478
479 ret = 0;
480 while (1) {
481 struct dirent *dp;
482 char buf[PATH_MAX];
483
484 /*
485 * set errno to 0 before calling readdir() in order to
486 * distinguish end of stream and from an error.
487 */
488 errno = 0;
489 dp = readdir(_dir);
490 if (!dp)
491 break;
492
493 if (is_dot_dotdot(dp->d_name) ||
494 !strncmp(dp->d_name, "lost+found", strlen("lost+found")))
495 continue;
496
497 ret = snprintf(buf, PATH_MAX, "%s/%s", path, dp->d_name);
498
499 if (ret < 0 || ret >= PATH_MAX) {
500 /* ignore the too long path */
501 ret = -ENOMEM;
502 goto fail;
503 }
504
505 ret = lstat64(buf, &st);
506 if (ret) {
507 ret = -errno;
508 goto fail;
509 }
510
511 ret = read_xattrs_from_file(buf, st.st_mode, NULL);
512 if (ret)
513 goto fail;
514
515 if (!S_ISDIR(st.st_mode))
516 continue;
517
518 ret = erofs_count_all_xattrs_from_path(buf);
519 if (ret)
520 goto fail;
521 }
522
523 if (errno)
524 ret = -errno;
525
526 fail:
527 closedir(_dir);
528 return ret;
529 }
530
erofs_cleanxattrs(bool sharedxattrs)531 static void erofs_cleanxattrs(bool sharedxattrs)
532 {
533 unsigned int i;
534 struct xattr_item *item;
535 struct hlist_node *tmp;
536
537 hash_for_each_safe(ea_hashtable, i, tmp, item, node) {
538 if (sharedxattrs && item->shared_xattr_id >= 0)
539 continue;
540
541 hash_del(&item->node);
542 free(item);
543 }
544
545 if (sharedxattrs)
546 return;
547
548 shared_xattrs_size = shared_xattrs_count = 0;
549 }
550
erofs_bh_flush_write_shared_xattrs(struct erofs_buffer_head * bh)551 static bool erofs_bh_flush_write_shared_xattrs(struct erofs_buffer_head *bh)
552 {
553 void *buf = bh->fsprivate;
554 int err = dev_write(buf, erofs_btell(bh, false), shared_xattrs_size);
555
556 if (err)
557 return false;
558 free(buf);
559 return erofs_bh_flush_generic_end(bh);
560 }
561
562 static struct erofs_bhops erofs_write_shared_xattrs_bhops = {
563 .flush = erofs_bh_flush_write_shared_xattrs,
564 };
565
erofs_build_shared_xattrs_from_path(const char * path)566 int erofs_build_shared_xattrs_from_path(const char *path)
567 {
568 int ret;
569 struct erofs_buffer_head *bh;
570 struct inode_xattr_node *node, *n;
571 char *buf;
572 unsigned int p;
573 erofs_off_t off;
574
575 /* check if xattr or shared xattr is disabled */
576 if (cfg.c_inline_xattr_tolerance < 0 ||
577 cfg.c_inline_xattr_tolerance == INT_MAX)
578 return 0;
579
580 if (shared_xattrs_size || shared_xattrs_count) {
581 DBG_BUGON(1);
582 return -EINVAL;
583 }
584
585 ret = erofs_count_all_xattrs_from_path(path);
586 if (ret)
587 return ret;
588
589 if (!shared_xattrs_size)
590 goto out;
591
592 buf = calloc(1, shared_xattrs_size);
593 if (!buf)
594 return -ENOMEM;
595
596 bh = erofs_balloc(XATTR, shared_xattrs_size, 0, 0);
597 if (IS_ERR(bh)) {
598 free(buf);
599 return PTR_ERR(bh);
600 }
601 bh->op = &erofs_skip_write_bhops;
602
603 erofs_mapbh(bh->block);
604 off = erofs_btell(bh, false);
605
606 sbi.xattr_blkaddr = off / EROFS_BLKSIZ;
607 off %= EROFS_BLKSIZ;
608 p = 0;
609
610 list_for_each_entry_safe(node, n, &shared_xattrs_list, list) {
611 struct xattr_item *const item = node->item;
612 const struct erofs_xattr_entry entry = {
613 .e_name_index = item->prefix,
614 .e_name_len = item->len[0],
615 .e_value_size = cpu_to_le16(item->len[1])
616 };
617
618 list_del(&node->list);
619
620 item->shared_xattr_id = (off + p) /
621 sizeof(struct erofs_xattr_entry);
622
623 memcpy(buf + p, &entry, sizeof(entry));
624 p += sizeof(struct erofs_xattr_entry);
625 memcpy(buf + p, item->kvbuf, item->len[0] + item->len[1]);
626 p = EROFS_XATTR_ALIGN(p + item->len[0] + item->len[1]);
627 free(node);
628 }
629 bh->fsprivate = buf;
630 bh->op = &erofs_write_shared_xattrs_bhops;
631 out:
632 erofs_cleanxattrs(true);
633 return 0;
634 }
635
erofs_export_xattr_ibody(struct list_head * ixattrs,unsigned int size)636 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size)
637 {
638 struct inode_xattr_node *node, *n;
639 struct erofs_xattr_ibody_header *header;
640 LIST_HEAD(ilst);
641 unsigned int p;
642 char *buf = calloc(1, size);
643
644 if (!buf)
645 return ERR_PTR(-ENOMEM);
646
647 header = (struct erofs_xattr_ibody_header *)buf;
648 header->h_shared_count = 0;
649
650 p = sizeof(struct erofs_xattr_ibody_header);
651 list_for_each_entry_safe(node, n, ixattrs, list) {
652 struct xattr_item *const item = node->item;
653
654 list_del(&node->list);
655
656 /* move inline xattrs to the onstack list */
657 if (item->shared_xattr_id < 0) {
658 list_add(&node->list, &ilst);
659 continue;
660 }
661
662 *(__le32 *)(buf + p) = cpu_to_le32(item->shared_xattr_id);
663 p += sizeof(__le32);
664 ++header->h_shared_count;
665 free(node);
666 put_xattritem(item);
667 }
668
669 list_for_each_entry_safe(node, n, &ilst, list) {
670 struct xattr_item *const item = node->item;
671 const struct erofs_xattr_entry entry = {
672 .e_name_index = item->prefix,
673 .e_name_len = item->len[0],
674 .e_value_size = cpu_to_le16(item->len[1])
675 };
676
677 memcpy(buf + p, &entry, sizeof(entry));
678 p += sizeof(struct erofs_xattr_entry);
679 memcpy(buf + p, item->kvbuf, item->len[0] + item->len[1]);
680 p = EROFS_XATTR_ALIGN(p + item->len[0] + item->len[1]);
681
682 list_del(&node->list);
683 free(node);
684 put_xattritem(item);
685 }
686 DBG_BUGON(p > size);
687 return buf;
688 }
689