diff options
Diffstat (limited to 'fs/ntfs3/xattr.c')
| -rw-r--r-- | fs/ntfs3/xattr.c | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 3fffda784892..594ef6860b93 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -146,26 +146,29 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, for (off = 0; off < size; off += ea_size) { const struct EA_FULL *ef = Add2Ptr(ea_p, off); u32 bytes = size - off; + size_t need; /* Check if we can use field ea->size. */ if (bytes < sizeof(ef->size)) goto out1; + /* Check if we can use fields ef->name_len and ef->elength. */ + if (bytes < offsetof(struct EA_FULL, name)) + goto out1; + + /* Size needed to hold this record's name and value. */ + need = struct_size(ef, name, + 1 + ef->name_len + le16_to_cpu(ef->elength)); + if (ef->size) { ea_size = le32_to_cpu(ef->size); - if (ea_size > bytes) + /* ef->size must fit the list and cover the record. */ + if (ea_size > bytes || ea_size < need) goto out1; continue; } - /* Check if we can use fields ef->name_len and ef->elength. */ - if (bytes < offsetof(struct EA_FULL, name)) - goto out1; - - ea_size = ALIGN(struct_size(ef, name, - 1 + ef->name_len + - le16_to_cpu(ef->elength)), - 4); + ea_size = ALIGN(need, 4); if (ea_size > bytes) goto out1; } @@ -660,7 +663,6 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, inode->i_mode = old_mode; goto out; } - inode->i_mode = mode; } set_cached_acl(inode, type, acl); inode_set_ctime_current(inode); @@ -851,6 +853,12 @@ out: return err; } +static bool ntfs_is_reserved_lxattr(const char *name) +{ + return !strcmp(name, "$LXUID") || !strcmp(name, "$LXGID") || + !strcmp(name, "$LXMOD") || !strcmp(name, "$LXDEV"); +} + /* * ntfs_setxattr - inode_operations::setxattr */ @@ -867,7 +875,9 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler, if (!strcmp(name, SYSTEM_DOS_ATTRIB)) { if (sizeof(u8) != size) goto out; - new_fa = cpu_to_le32(*(u8 *)value); + /* system.dos_attrib only covers the low DOS attribute byte. */ + new_fa = (ni->std_fa & ~cpu_to_le32(0xff)) | + cpu_to_le32(*(u8 *)value); goto set_new_fa; } @@ -955,6 +965,12 @@ set_new_fa: goto out; } + /* Do not allow non privileged users to change $LXUID/$LXGID... */ + if (ntfs_is_reserved_lxattr(name) && !capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + /* Deal with NTFS extended attribute. */ err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0, NULL); @@ -1031,7 +1047,7 @@ void ntfs_get_wsl_perm(struct inode *inode) i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); inode->i_mode = le32_to_cpu(value[2]); - if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, + if (ntfs_get_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value[0], sizeof(value), &sz) == sizeof(value[0])) { inode->i_rdev = le32_to_cpu(value[0]); |
