diff options
| author | Linus Torvalds <[email protected]> | 2017-07-05 16:41:23 -0700 | 
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2017-07-05 16:41:23 -0700 | 
| commit | 8c27cb3566762613a23c080e3db7d0501af9a787 (patch) | |
| tree | 32b2752e320b6cb3ecf289dd00b5145a6de947e6 /fs/btrfs/tree-log.c | |
| parent | 7114f51fcb979f167ab5f625ac74059dcb1afc28 (diff) | |
| parent | 848c23b78fafdcd3270b06a30737f8dbd70c347f (diff) | |
Merge branch 'for-4.13-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs updates from David Sterba:
 "The core updates improve error handling (mostly related to bios), with
  the usual incremental work on the GFP_NOFS (mis)use removal,
  refactoring or cleanups. Except the two top patches, all have been in
  for-next for an extensive amount of time.
  User visible changes:
   - statx support
   - quota override tunable
   - improved compression thresholds
   - obsoleted mount option alloc_start
  Core updates:
   - bio-related updates:
       - faster bio cloning
       - no allocation failures
       - preallocated flush bios
   - more kvzalloc use, memalloc_nofs protections, GFP_NOFS updates
   - prep work for btree_inode removal
   - dir-item validation
   - qgoup fixes and updates
   - cleanups:
       - removed unused struct members, unused code, refactoring
       - argument refactoring (fs_info/root, caller -> callee sink)
       - SEARCH_TREE ioctl docs"
* 'for-4.13-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (115 commits)
  btrfs: Remove false alert when fiemap range is smaller than on-disk extent
  btrfs: Don't clear SGID when inheriting ACLs
  btrfs: fix integer overflow in calc_reclaim_items_nr
  btrfs: scrub: fix target device intialization while setting up scrub context
  btrfs: qgroup: Fix qgroup reserved space underflow by only freeing reserved ranges
  btrfs: qgroup: Introduce extent changeset for qgroup reserve functions
  btrfs: qgroup: Fix qgroup reserved space underflow caused by buffered write and quotas being enabled
  btrfs: qgroup: Return actually freed bytes for qgroup release or free data
  btrfs: qgroup: Cleanup btrfs_qgroup_prepare_account_extents function
  btrfs: qgroup: Add quick exit for non-fs extents
  Btrfs: rework delayed ref total_bytes_pinned accounting
  Btrfs: return old and new total ref mods when adding delayed refs
  Btrfs: always account pinned bytes when dropping a tree block ref
  Btrfs: update total_bytes_pinned when pinning down extents
  Btrfs: make BUG_ON() in add_pinned_bytes() an ASSERT()
  Btrfs: make add_pinned_bytes() take an s64 num_bytes instead of u64
  btrfs: fix validation of XATTR_ITEM dir items
  btrfs: Verify dir_item in iterate_object_props
  btrfs: Check name_len before in btrfs_del_root_ref
  btrfs: Check name_len before reading btrfs_get_name
  ...
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 44 | 
1 files changed, 33 insertions, 11 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ccfe9fe7754a..f20ef211a73d 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1175,15 +1175,19 @@ next:  	return 0;  } -static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, -			     u32 *namelen, char **name, u64 *index, -			     u64 *parent_objectid) +static int extref_get_fields(struct extent_buffer *eb, int slot, +			     unsigned long ref_ptr, u32 *namelen, char **name, +			     u64 *index, u64 *parent_objectid)  {  	struct btrfs_inode_extref *extref;  	extref = (struct btrfs_inode_extref *)ref_ptr;  	*namelen = btrfs_inode_extref_name_len(eb, extref); +	if (!btrfs_is_name_len_valid(eb, slot, (unsigned long)&extref->name, +				     *namelen)) +		return -EIO; +  	*name = kmalloc(*namelen, GFP_NOFS);  	if (*name == NULL)  		return -ENOMEM; @@ -1198,14 +1202,19 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,  	return 0;  } -static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, -			  u32 *namelen, char **name, u64 *index) +static int ref_get_fields(struct extent_buffer *eb, int slot, +			  unsigned long ref_ptr, u32 *namelen, char **name, +			  u64 *index)  {  	struct btrfs_inode_ref *ref;  	ref = (struct btrfs_inode_ref *)ref_ptr;  	*namelen = btrfs_inode_ref_name_len(eb, ref); +	if (!btrfs_is_name_len_valid(eb, slot, (unsigned long)(ref + 1), +				     *namelen)) +		return -EIO; +  	*name = kmalloc(*namelen, GFP_NOFS);  	if (*name == NULL)  		return -ENOMEM; @@ -1280,8 +1289,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,  	while (ref_ptr < ref_end) {  		if (log_ref_ver) { -			ret = extref_get_fields(eb, ref_ptr, &namelen, &name, -						&ref_index, &parent_objectid); +			ret = extref_get_fields(eb, slot, ref_ptr, &namelen, +					  &name, &ref_index, &parent_objectid);  			/*  			 * parent object can change from one array  			 * item to another. @@ -1293,8 +1302,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,  				goto out;  			}  		} else { -			ret = ref_get_fields(eb, ref_ptr, &namelen, &name, -					     &ref_index); +			ret = ref_get_fields(eb, slot, ref_ptr, &namelen, +					     &name, &ref_index);  		}  		if (ret)  			goto out; @@ -1841,7 +1850,7 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,  	ptr_end = ptr + item_size;  	while (ptr < ptr_end) {  		di = (struct btrfs_dir_item *)ptr; -		if (verify_dir_item(fs_info, eb, di)) +		if (verify_dir_item(fs_info, eb, slot, di))  			return -EIO;  		name_len = btrfs_dir_name_len(eb, di);  		ret = replay_one_name(trans, root, path, eb, di, key); @@ -2017,7 +2026,7 @@ again:  	ptr_end = ptr + item_size;  	while (ptr < ptr_end) {  		di = (struct btrfs_dir_item *)ptr; -		if (verify_dir_item(fs_info, eb, di)) { +		if (verify_dir_item(fs_info, eb, slot, di)) {  			ret = -EIO;  			goto out;  		} @@ -2102,6 +2111,7 @@ static int replay_xattr_deletes(struct btrfs_trans_handle *trans,  			      struct btrfs_path *path,  			      const u64 ino)  { +	struct btrfs_fs_info *fs_info = root->fs_info;  	struct btrfs_key search_key;  	struct btrfs_path *log_path;  	int i; @@ -2143,6 +2153,12 @@ process_leaf:  			u32 this_len = sizeof(*di) + name_len + data_len;  			char *name; +			ret = verify_dir_item(fs_info, path->nodes[0], +					      path->slots[0], di); +			if (ret) { +				ret = -EIO; +				goto out; +			}  			name = kmalloc(name_len, GFP_NOFS);  			if (!name) {  				ret = -ENOMEM; @@ -4546,6 +4562,12 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb,  			this_len = sizeof(*extref) + this_name_len;  		} +		ret = btrfs_is_name_len_valid(eb, slot, name_ptr, +					      this_name_len); +		if (!ret) { +			ret = -EIO; +			goto out; +		}  		if (this_name_len > name_len) {  			char *new_name; |