diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index fcc89856ab95..9d5342b8dbc6 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1458,6 +1458,47 @@ int ocfs2_validate_inode_block(struct super_block *sb, (unsigned long long)bh->b_blocknr); goto bail; } + if (di->i_dyn_features & cpu_to_le16(OCFS2_INLINE_XATTR_FL)) { + struct ocfs2_xattr_header *header; + u16 xattr_inline_size; + u16 xattr_count; + size_t max_entries; + + xattr_inline_size = le16_to_cpu(di->i_xattr_inline_size); + + /* Validate inline size is within block bounds */ + if (xattr_inline_size > sb->s_blocksize) { + mlog(ML_ERROR, + "xattr inline size %u exceeds block size %lu in inode %llu\n", + xattr_inline_size, sb->s_blocksize, + (unsigned long long)bh->b_blocknr); + goto bail; + } + /* If there's xattr data, validate it */ + if (xattr_inline_size > 0) { + /* Must be at least big enough for header */ + if (xattr_inline_size < sizeof(struct ocfs2_xattr_header)) { + mlog(ML_ERROR, + "xattr inline size %u too small for header in inode %llu\n", + xattr_inline_size, + (unsigned long long)bh->b_blocknr); + goto bail; + } + header = (struct ocfs2_xattr_header *) + ((void *)di + sb->s_blocksize - xattr_inline_size); + xattr_count = le16_to_cpu(header->xh_count); + max_entries = (xattr_inline_size - + sizeof(struct ocfs2_xattr_header)) / + sizeof(struct ocfs2_xattr_entry); + if (xattr_count > max_entries) { + mlog(ML_ERROR, + "xattr count %u exceeds maximum %zu in inode %llu\n", + xattr_count, max_entries, + (unsigned long long)bh->b_blocknr); + goto bail; + } + } + } /* * Errors after here are fatal. diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index d70a20d29e3e..db352df00101 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -928,8 +928,21 @@ static int ocfs2_xattr_list_entries(struct inode *inode, size_t result = 0; int i, type, ret; const char *name; - - for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) { + u16 count; + size_t max_entries; + struct super_block *sb = inode->i_sb; + + count = le16_to_cpu(header->xh_count); + max_entries = (sb->s_blocksize - sizeof(struct ocfs2_xattr_header)) / + sizeof(struct ocfs2_xattr_entry); + if (count > max_entries) { + mlog(ML_ERROR, + "xattr entry count %u exceeds maximum %zu in inode %llu\n", + count, max_entries, + (unsigned long long)OCFS2_I(inode)->ip_blkno); + return -EUCLEAN; + } + for (i = 0 ; i < count; i++) { struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; type = ocfs2_xattr_get_type(entry); name = (const char *)header +