Hi Yong,

On Wed, Aug 03, 2022 at 10:22:22PM +0800, Sheng Yong wrote:
> This patch exports erofs_xattr_foreach() to iterate all xattrs.
> Each xattr entry is handled by operations defined in `struct
> xattr_iter_ops'.
> 

Thanks for your hard effort! 

Could we import in-kernel xattr implementation with verify enabled
(or unify these implementations) instead?

( Jianan ported a kernel implementation before, could we enhance
  it with verification?
  https://lore.kernel.org/r/[email protected])

Thanks,
Gao Xiang

> Signed-off-by: Sheng Yong <[email protected]>
> ---
>  fsck/main.c           |  83 ++++------------------------
>  include/erofs/xattr.h |   7 ++-
>  lib/xattr.c           | 123 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 139 insertions(+), 74 deletions(-)
> 
> diff --git a/fsck/main.c b/fsck/main.c
> index 5a2f659..237ccc1 100644
> --- a/fsck/main.c
> +++ b/fsck/main.c
> @@ -14,6 +14,7 @@
>  #include "erofs/compress.h"
>  #include "erofs/decompress.h"
>  #include "erofs/dir.h"
> +#include "erofs/xattr.h"
> 
>  static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid);
> 
> @@ -283,82 +284,18 @@ static int erofs_check_sb_chksum(void)
>         return 0;
>  }
> 
> -static int erofs_verify_xattr(struct erofs_inode *inode)
> +static int erofs_verify_xattr_entry(const struct erofs_xattr_entry *entry)
>  {
> -       unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header);
> -       unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry);
> -       erofs_off_t addr;
> -       unsigned int ofs, xattr_shared_count;
> -       struct erofs_xattr_ibody_header *ih;
> -       struct erofs_xattr_entry *entry;
> -       int i, remaining = inode->xattr_isize, ret = 0;
> -       char buf[EROFS_BLKSIZ];
> -
> -       if (inode->xattr_isize == xattr_hdr_size) {
> -               erofs_err("xattr_isize %d of nid %llu is not supported yet",
> -                         inode->xattr_isize, inode->nid | 0ULL);
> -               ret = -EFSCORRUPTED;
> -               goto out;
> -       } else if (inode->xattr_isize < xattr_hdr_size) {
> -               if (inode->xattr_isize) {
> -                       erofs_err("bogus xattr ibody @ nid %llu",
> -                                 inode->nid | 0ULL);
> -                       ret = -EFSCORRUPTED;
> -                       goto out;
> -               }
> -       }
> -
> -       addr = iloc(inode->nid) + inode->inode_isize;
> -       ret = dev_read(0, buf, addr, xattr_hdr_size);
> -       if (ret < 0) {
> -               erofs_err("failed to read xattr header @ nid %llu: %d",
> -                         inode->nid | 0ULL, ret);
> -               goto out;
> -       }
> -       ih = (struct erofs_xattr_ibody_header *)buf;
> -       xattr_shared_count = ih->h_shared_count;
> -
> -       ofs = erofs_blkoff(addr) + xattr_hdr_size;
> -       addr += xattr_hdr_size;
> -       remaining -= xattr_hdr_size;
> -       for (i = 0; i < xattr_shared_count; ++i) {
> -               if (ofs >= EROFS_BLKSIZ) {
> -                       if (ofs != EROFS_BLKSIZ) {
> -                               erofs_err("unaligned xattr entry in xattr 
> shared area @ nid %llu",
> -                                         inode->nid | 0ULL);
> -                               ret = -EFSCORRUPTED;
> -                               goto out;
> -                       }
> -                       ofs = 0;
> -               }
> -               ofs += xattr_entry_size;
> -               addr += xattr_entry_size;
> -               remaining -= xattr_entry_size;
> -       }
> -
> -       while (remaining > 0) {
> -               unsigned int entry_sz;
> +       return 0;
> +}
> 
> -               ret = dev_read(0, buf, addr, xattr_entry_size);
> -               if (ret) {
> -                       erofs_err("failed to read xattr entry @ nid %llu: %d",
> -                                 inode->nid | 0ULL, ret);
> -                       goto out;
> -               }
> +struct xattr_iter_ops erofs_verify_xattr_ops = {
> +       .verify = erofs_verify_xattr_entry,
> +};
> 
> -               entry = (struct erofs_xattr_entry *)buf;
> -               entry_sz = erofs_xattr_entry_size(entry);
> -               if (remaining < entry_sz) {
> -                       erofs_err("xattr on-disk corruption: xattr entry 
> beyond xattr_isize @ nid %llu",
> -                                 inode->nid | 0ULL);
> -                       ret = -EFSCORRUPTED;
> -                       goto out;
> -               }
> -               addr += entry_sz;
> -               remaining -= entry_sz;
> -       }
> -out:
> -       return ret;
> +static int erofs_verify_xattr(struct erofs_inode *inode)
> +{
> +       return erofs_xattr_foreach(inode, &erofs_verify_xattr_ops, NULL);
>  }
> 
>  static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd)
> diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
> index 226e984..c592d47 100644
> --- a/include/erofs/xattr.h
> +++ b/include/erofs/xattr.h
> @@ -45,10 +45,15 @@ extern "C"
>  #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
>  #endif
> 
> +struct xattr_iter_ops {
> +       int (*verify)(const struct erofs_xattr_entry *entry);
> +};
> +
>  int erofs_prepare_xattr_ibody(struct erofs_inode *inode);
>  char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
>  int erofs_build_shared_xattrs_from_path(const char *path);
> -
> +int erofs_xattr_foreach(struct erofs_inode *vi, struct xattr_iter_ops *ops,
> +                       void *data);
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/xattr.c b/lib/xattr.c
> index c8ce278..92c155d 100644
> --- a/lib/xattr.c
> +++ b/lib/xattr.c
> @@ -714,3 +714,126 @@ char *erofs_export_xattr_ibody(struct list_head 
> *ixattrs, unsigned int size)
>         DBG_BUGON(p > size);
>         return buf;
>  }
> +
> +static struct erofs_xattr_entry *read_xattr_entry(erofs_blk_t addr,
> +                                                 char *buf, size_t size)
> +{
> +       struct erofs_xattr_entry *entry;
> +       size_t entry_sz = sizeof(struct erofs_xattr_entry);
> +       int ret;
> +
> +       if (size < entry_sz)
> +               return ERR_PTR(-ERANGE);
> +
> +       ret = dev_read(0, buf, addr, entry_sz);
> +       if (ret) {
> +               erofs_err("failed to read xattr entry at addr %x: %d",
> +                         addr, ret);
> +               return ERR_PTR(ret);
> +       }
> +
> +       entry = (struct erofs_xattr_entry *)buf;
> +       entry_sz = erofs_xattr_entry_size(entry);
> +       if (size < entry_sz)
> +               return ERR_PTR(-ERANGE);
> +
> +       ret = dev_read(0, buf, addr, entry_sz);
> +       if (ret) {
> +               erofs_err("failed to read xattr entry at addr %x: %d",
> +                         addr, ret);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return entry;
> +}
> +
> +int erofs_xattr_foreach(struct erofs_inode *vi, struct xattr_iter_ops *ops,
> +                       void *data)
> +{
> +       unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header);
> +       unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry);
> +       erofs_off_t addr;
> +       unsigned int ofs, xattr_shared_count;
> +       struct erofs_xattr_ibody_header *ih;
> +       struct erofs_xattr_entry *entry;
> +       int i, remaining = vi->xattr_isize, ret = 0;
> +       char buf[EROFS_BLKSIZ];
> +
> +       if (vi->xattr_isize == xattr_hdr_size) {
> +               erofs_err("xattr_isize %d of nid %llu is not supported yet",
> +                         vi->xattr_isize, vi->nid | 0ULL);
> +               return -EFSCORRUPTED;
> +       } else if (vi->xattr_isize < xattr_hdr_size) {
> +               if (vi->xattr_isize) {
> +                       erofs_err("bogus xattr ibody @ nid %llu",
> +                                 vi->nid | 0ULL);
> +                       return -EFSCORRUPTED;
> +               }
> +       }
> +
> +       addr = iloc(vi->nid) + vi->inode_isize;
> +       ret = dev_read(0, buf, addr, xattr_hdr_size);
> +       if (ret < 0) {
> +               erofs_err("failed to read xattr header @ nid %llu: %d",
> +                         vi->nid | 0ULL, ret);
> +               return ret;
> +       }
> +       ih = (struct erofs_xattr_ibody_header *)buf;
> +       xattr_shared_count = ih->h_shared_count;
> +
> +       ofs = erofs_blkoff(addr) + xattr_hdr_size;
> +       addr += xattr_hdr_size;
> +       ret = dev_read(0, buf, addr, xattr_entry_size * xattr_shared_count);
> +       remaining -= xattr_hdr_size;
> +       for (i = 0; i < xattr_shared_count; ++i) {
> +               unsigned int xattr_id;
> +               erofs_blk_t xattr_addr;
> +               char tmp[EROFS_BLKSIZ];
> +
> +               if (ofs >= EROFS_BLKSIZ) {
> +                       if (ofs != EROFS_BLKSIZ) {
> +                               erofs_err("unaligned xattr entry in xattr 
> shared area @ nid %llu",
> +                                         vi->nid | 0ULL);
> +                               return -EFSCORRUPTED;
> +                       }
> +                       ofs = 0;
> +               }
> +
> +               xattr_id = le32_to_cpu(*((__le32 *)buf + i));
> +               xattr_addr = sbi.xattr_blkaddr * EROFS_BLKSIZ +  4 * xattr_id;
> +
> +               entry = read_xattr_entry(xattr_addr, tmp, EROFS_BLKSIZ);
> +               if (IS_ERR(entry))
> +                       return PTR_ERR(entry);
> +
> +               if (ops->verify) {
> +                       ret = ops->verify(entry);
> +                       if (ret < 0)
> +                               return ret;
> +               }
> +
> +               ofs += xattr_entry_size;
> +               addr += xattr_entry_size;
> +               remaining -= xattr_entry_size;
> +       }
> +
> +       while (remaining > 0) {
> +               unsigned int entry_sz;
> +
> +               entry = read_xattr_entry(addr, buf, EROFS_BLKSIZ);
> +               if (IS_ERR(entry))
> +                       return PTR_ERR(entry);
> +               entry_sz = erofs_xattr_entry_size(entry);
> +
> +               if (ops->verify) {
> +                       ret = ops->verify(entry);
> +                       if (ret < 0)
> +                               return ret;
> +               }
> +               addr += entry_sz;
> +               remaining -= entry_sz;
> +       }
> +
> +       return ret;
> +
> +}
> --
> 2.25.1
> 
> ________________________________
> OPPO
> 
> 本电子邮件及其附件含有OPPO公司的保密信息,仅限于邮件指明的收件人使用(包含个人及群组)。禁止任何人在未经授权的情况下以任何形式使用。如果您错收了本邮件,请立即以电子邮件通知发件人并删除本邮件及其附件。
> 
> This e-mail and its attachments contain confidential information from OPPO, 
> which is intended only for the person or entity whose address is listed 
> above. Any use of the information contained herein in any way (including, but 
> not limited to, total or partial disclosure, reproduction, or dissemination) 
> by persons other than the intended recipient(s) is prohibited. If you receive 
> this e-mail in error, please notify the sender by phone or email immediately 
> and delete it!

Reply via email to