// SPDX-License-Identifier: GPL-2.0
/*
*
* Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
*
*/
#include <linux/fs.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/xattr.h>
#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"
// clang-format off
#define SYSTEM_DOS_ATTRIB "system.dos_attrib"
#define SYSTEM_NTFS_ATTRIB "system.ntfs_attrib"
#define SYSTEM_NTFS_ATTRIB_BE "system.ntfs_attrib_be"
#define SYSTEM_NTFS_SECURITY "system.ntfs_security"
// clang-format on
static inline size_t unpacked_ea_size(const struct EA_FULL *ea)
{
return ea->size ? le32_to_cpu(ea->size) :
ALIGN(struct_size(ea, name,
1 + ea->name_len +
le16_to_cpu(ea->elength)),
4);
}
static inline size_t packed_ea_size(const struct EA_FULL *ea)
{
return struct_size(ea, name,
1 + ea->name_len + le16_to_cpu(ea->elength)) -
offsetof(struct EA_FULL, flags);
}
/*
* find_ea
*
* Assume there is at least one xattr in the list.
*/
static inline bool find_ea(const struct EA_FULL *ea_all, u32 bytes,
const char *name, u8 name_len, u32 *off, u32 *ea_sz)
{
u32 ea_size;
*off = 0;
if (!ea_all)
return false;
for (; *off < bytes; *off += ea_size) {
const struct EA_FULL *ea = Add2Ptr(ea_all, *off);
ea_size = unpacked_ea_size(ea);
if (ea->name_len == name_len &&
!memcmp(ea->name, name, name_len)) {
if (ea_sz)
*ea_sz = ea_size;
return true;
}
}
return false;
}
/*
* ntfs_read_ea - Read all extended attributes.
* @ea: New allocated memory.
* @info: Pointer into resident data.
*/
static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
size_t add_bytes, const struct EA_INFO **info)
{
int err = -EINVAL;
struct ntfs_sb_info *sbi = ni->mi.sbi;
struct ATTR_LIST_ENTRY *le = NULL;
struct ATTRIB *attr_info, *attr_ea;
void *ea_p;
u32 size, off, ea_size;
static_assert(le32_to_cpu(ATTR_EA_INFO) < le32_to_cpu(ATTR_EA));
*ea = NULL;
*info = NULL;
attr_info =
ni_find_attr(ni, NULL, &le, ATTR_EA_INFO, NULL, 0, NULL, NULL);
attr_ea =
ni_find_attr(ni, attr_info, &le, ATTR_EA, NULL, 0, NULL, NULL);
if (!attr_ea || !attr_info)
return 0;
*info = resident_data_ex(attr_info, sizeof(struct EA_INFO));
if (!*info)
goto out;
/* Check Ea limit. */
size = le32_to_cpu((*info)->size);
if (size > sbi->ea_max_size) {
err = -EFBIG;
goto out;
}
if (attr_size(attr_ea) > sbi->ea_max_size) {
err = -EFBIG;
goto out;
}
if (!size) {
/* EA info persists, but xattr is empty. Looks like EA problem. */
goto out;
}
/* Allocate memory for packed Ea. */
ea_p = kmalloc(size_add(size, add_bytes), GFP_NOFS);
if (!ea_p)
return -ENOMEM;
if (attr_ea->non_res) {
struct runs_tree run;
run_init(&run);
err =