From: Tahsin Erdogan <tahsin@google.com>
To: Andreas Dilger <adilger@dilger.ca>,
"Darrick J . Wong" <darrick.wong@oracle.com>,
Jan Kara <jack@suse.cz>, "Theodore Ts'o" <tytso@mit.edu>,
linux-ext4@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Tahsin Erdogan <tahsin@google.com>
Subject: [PATCH 31/32] ext4: strong binding of xattr inode references
Date: Wed, 21 Jun 2017 14:21:41 -0700 [thread overview]
Message-ID: <20170621212142.16581-31-tahsin@google.com> (raw)
In-Reply-To: <20170621212142.16581-1-tahsin@google.com>
To verify that a xattr entry is not pointing to the wrong xattr inode,
we currently check that the target inode has EXT4_EA_INODE_FL flag set and
also the entry size matches the target inode size.
For stronger validation, also incorporate crc32c hash of the value into
the e_hash field. This is done regardless of whether the entry lives in
the inode body or external attribute block.
Signed-off-by: Tahsin Erdogan <tahsin@google.com>
---
v2: naming updates to adapt to other patch changes in the series
fs/ext4/xattr.c | 104 +++++++++++++++++++++++++++++++++++---------------------
1 file changed, 65 insertions(+), 39 deletions(-)
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index b1bd60244978..edef88a2cc7c 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -77,8 +77,8 @@ static void ext4_xattr_block_cache_insert(struct mb_cache *,
static struct buffer_head *
ext4_xattr_block_cache_find(struct inode *, struct ext4_xattr_header *,
struct mb_cache_entry **);
-static void ext4_xattr_hash_entry(struct ext4_xattr_entry *entry,
- void *value_base);
+static __le32 ext4_xattr_hash_entry(char *name, size_t name_len, __le32 *value,
+ size_t value_count);
static void ext4_xattr_rehash(struct ext4_xattr_header *);
static const struct xattr_handler * const ext4_xattr_handler_map[] = {
@@ -380,7 +380,9 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
}
static int
-ext4_xattr_inode_verify_hash(struct inode *ea_inode, void *buffer, size_t size)
+ext4_xattr_inode_verify_hashes(struct inode *ea_inode,
+ struct ext4_xattr_entry *entry, void *buffer,
+ size_t size)
{
u32 hash;
@@ -388,23 +390,35 @@ ext4_xattr_inode_verify_hash(struct inode *ea_inode, void *buffer, size_t size)
hash = ext4_xattr_inode_hash(EXT4_SB(ea_inode->i_sb), buffer, size);
if (hash != ext4_xattr_inode_get_hash(ea_inode))
return -EFSCORRUPTED;
+
+ if (entry) {
+ __le32 e_hash, tmp_data;
+
+ /* Verify entry hash. */
+ tmp_data = cpu_to_le32(hash);
+ e_hash = ext4_xattr_hash_entry(entry->e_name, entry->e_name_len,
+ &tmp_data, 1);
+ if (e_hash != entry->e_hash)
+ return -EFSCORRUPTED;
+ }
return 0;
}
#define EXT4_XATTR_INODE_GET_PARENT(inode) ((__u32)(inode)->i_mtime.tv_sec)
/*
- * Read the value from the EA inode.
+ * Read xattr value from the EA inode.
*/
static int
-ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino, void *buffer,
- size_t size)
+ext4_xattr_inode_get(struct inode *inode, struct ext4_xattr_entry *entry,
+ void *buffer, size_t size)
{
struct mb_cache *ea_inode_cache = EA_INODE_CACHE(inode);
struct inode *ea_inode;
int err;
- err = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
+ err = ext4_xattr_inode_iget(inode, le32_to_cpu(entry->e_value_inum),
+ &ea_inode);
if (err) {
ea_inode = NULL;
goto out;
@@ -422,7 +436,7 @@ ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino, void *buffer,
if (err)
goto out;
- err = ext4_xattr_inode_verify_hash(ea_inode, buffer, size);
+ err = ext4_xattr_inode_verify_hashes(ea_inode, entry, buffer, size);
/*
* Compatibility check for old Lustre ea_inode implementation. Old
* version does not have hash validation, but it has a backpointer
@@ -489,9 +503,8 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
if (size > buffer_size)
goto cleanup;
if (entry->e_value_inum) {
- error = ext4_xattr_inode_get(inode,
- le32_to_cpu(entry->e_value_inum),
- buffer, size);
+ error = ext4_xattr_inode_get(inode, entry, buffer,
+ size);
if (error)
goto cleanup;
} else {
@@ -539,9 +552,8 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
if (size > buffer_size)
goto cleanup;
if (entry->e_value_inum) {
- error = ext4_xattr_inode_get(inode,
- le32_to_cpu(entry->e_value_inum),
- buffer, size);
+ error = ext4_xattr_inode_get(inode, entry, buffer,
+ size);
if (error)
goto cleanup;
} else {
@@ -1387,8 +1399,8 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
(EXT4_I(ea_inode)->i_flags & EXT4_EA_INODE_FL) &&
i_size_read(ea_inode) == value_len &&
!ext4_xattr_inode_read(ea_inode, ea_data, value_len) &&
- !ext4_xattr_inode_verify_hash(ea_inode, ea_data,
- value_len) &&
+ !ext4_xattr_inode_verify_hashes(ea_inode, NULL, ea_data,
+ value_len) &&
!memcmp(value, ea_data, value_len)) {
mb_cache_entry_touch(ea_inode_cache, ce);
mb_cache_entry_put(ea_inode_cache, ce);
@@ -1652,12 +1664,36 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
here->e_value_size = cpu_to_le32(i->value_len);
}
- if (is_block) {
- if (i->value)
- ext4_xattr_hash_entry(here, s->base);
- ext4_xattr_rehash((struct ext4_xattr_header *)s->base);
+ if (i->value) {
+ __le32 hash = 0;
+
+ /* Entry hash calculation. */
+ if (in_inode) {
+ __le32 crc32c_hash;
+
+ /*
+ * Feed crc32c hash instead of the raw value for entry
+ * hash calculation. This is to avoid walking
+ * potentially long value buffer again.
+ */
+ crc32c_hash = cpu_to_le32(
+ ext4_xattr_inode_get_hash(new_ea_inode));
+ hash = ext4_xattr_hash_entry(here->e_name,
+ here->e_name_len,
+ &crc32c_hash, 1);
+ } else if (is_block) {
+ __le32 *value = s->base + min_offs - new_size;
+
+ hash = ext4_xattr_hash_entry(here->e_name,
+ here->e_name_len, value,
+ new_size >> 2);
+ }
+ here->e_hash = hash;
}
+ if (is_block)
+ ext4_xattr_rehash((struct ext4_xattr_header *)s->base);
+
ret = 0;
out:
iput(old_ea_inode);
@@ -2439,9 +2475,7 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
/* Save the entry name and the entry value */
if (entry->e_value_inum) {
- error = ext4_xattr_inode_get(inode,
- le32_to_cpu(entry->e_value_inum),
- buffer, value_size);
+ error = ext4_xattr_inode_get(inode, entry, buffer, value_size);
if (error)
goto out;
} else {
@@ -2931,30 +2965,22 @@ ext4_xattr_block_cache_find(struct inode *inode,
*
* Compute the hash of an extended attribute.
*/
-static void ext4_xattr_hash_entry(struct ext4_xattr_entry *entry,
- void *value_base)
+static __le32 ext4_xattr_hash_entry(char *name, size_t name_len, __le32 *value,
+ size_t value_count)
{
__u32 hash = 0;
- char *name = entry->e_name;
- int n;
- for (n = 0; n < entry->e_name_len; n++) {
+ while (name_len--) {
hash = (hash << NAME_HASH_SHIFT) ^
(hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
*name++;
}
-
- if (!entry->e_value_inum && entry->e_value_size) {
- __le32 *value = (__le32 *)((char *)value_base +
- le16_to_cpu(entry->e_value_offs));
- for (n = (le32_to_cpu(entry->e_value_size) +
- EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
- hash = (hash << VALUE_HASH_SHIFT) ^
- (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
- le32_to_cpu(*value++);
- }
+ while (value_count--) {
+ hash = (hash << VALUE_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+ le32_to_cpu(*value++);
}
- entry->e_hash = cpu_to_le32(hash);
+ return cpu_to_le32(hash);
}
#undef NAME_HASH_SHIFT
--
2.13.1.611.g7e3b11ae1-goog
next prev parent reply other threads:[~2017-06-21 21:24 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-21 21:21 [PATCH 01/32] ext4: xattr-in-inode support Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 02/32] ext4: fix lockdep warning about recursive inode locking Tahsin Erdogan
2017-06-22 1:18 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 03/32] ext4: lock inode before calling ext4_orphan_add() Tahsin Erdogan
2017-06-22 1:20 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 04/32] ext4: do not set posix acls on xattr inodes Tahsin Erdogan
2017-06-22 1:23 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 05/32] ext4: attach jinode after creation of xattr inode Tahsin Erdogan
2017-06-22 1:26 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 06/32] ext4: ea_inode owner should be the same as the inode owner Tahsin Erdogan
2017-06-22 1:28 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 07/32] ext4: call journal revoke when freeing ea_inode blocks Tahsin Erdogan
2017-06-22 1:38 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 08/32] ext4: fix ref counting for ea_inode Tahsin Erdogan
2017-06-22 1:40 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 09/32] ext4: extended attribute value size limit is enforced by vfs Tahsin Erdogan
2017-06-22 1:42 ` Theodore Ts'o
2017-06-22 18:02 ` Darrick J. Wong
2017-06-22 19:40 ` Andreas Dilger
2017-06-22 22:27 ` Theodore Ts'o
2017-06-22 23:21 ` Darrick J. Wong
2017-06-21 21:21 ` [PATCH 10/32] ext4: change ext4_xattr_inode_iget() signature Tahsin Erdogan
2017-06-22 1:55 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 11/32] ext4: clean up ext4_xattr_inode_get() Tahsin Erdogan
2017-06-22 1:58 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 12/32] ext4: add missing le32_to_cpu(e_value_inum) conversions Tahsin Erdogan
2017-06-22 2:00 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 13/32] ext4: ext4_xattr_value_same() should return false for external data Tahsin Erdogan
2017-06-22 2:04 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 14/32] ext4: fix ext4_xattr_make_inode_space() value size calculation Tahsin Erdogan
2017-06-22 2:09 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 15/32] ext4: fix ext4_xattr_move_to_block() Tahsin Erdogan
2017-06-22 2:13 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 16/32] ext4: fix ext4_xattr_cmp() Tahsin Erdogan
2017-06-22 2:15 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 17/32] ext4: fix credits calculation for xattr inode Tahsin Erdogan
2017-06-22 2:19 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 18/32] ext4: retry storing value in external inode with xattr block too Tahsin Erdogan
2017-06-22 2:22 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 19/32] ext4: ext4_xattr_delete_inode() should return accurate errors Tahsin Erdogan
2017-06-22 2:27 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 20/32] ext4: improve journal credit handling in set xattr paths Tahsin Erdogan
2017-06-22 2:30 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 21/32] ext4: modify ext4_xattr_ino_array to hold struct inode * Tahsin Erdogan
2017-06-22 14:28 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 22/32] ext4: move struct ext4_xattr_inode_array to xattr.h Tahsin Erdogan
2017-06-22 14:29 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 23/32] mbcache: make mbcache naming more generic Tahsin Erdogan
2017-06-22 14:37 ` Theodore Ts'o
2017-06-21 21:21 ` [PATCH 24/32] ext2, ext4: make mb block cache names more explicit Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 25/32] ext4: add ext4_is_quota_file() Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 26/32] ext4: cleanup transaction restarts during inode deletion Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 27/32] ext4: xattr inode deduplication Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 28/32] quota: add get_inode_usage callback to transfer multi-inode charges Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 29/32] ext4: reserve space for xattr entries/names Tahsin Erdogan
2017-06-21 21:21 ` [PATCH 30/32] ext4: eliminate xattr entry e_hash recalculation for removes Tahsin Erdogan
2017-06-21 21:21 ` Tahsin Erdogan [this message]
2017-06-21 21:21 ` [PATCH 32/32] ext4: add nombcache mount option Tahsin Erdogan
2017-06-22 1:16 ` [PATCH 01/32] ext4: xattr-in-inode support Theodore Ts'o
2017-06-22 1:49 [PATCH 24/32] ext2, ext4: make mb block cache names more explicit Tahsin Erdogan
2017-06-22 1:49 ` [PATCH 31/32] ext4: strong binding of xattr inode references Tahsin Erdogan
2017-06-22 15:54 ` Theodore Ts'o
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170621212142.16581-31-tahsin@google.com \
--to=tahsin@google.com \
--cc=adilger@dilger.ca \
--cc=darrick.wong@oracle.com \
--cc=jack@suse.cz \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).