Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e0362b3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'xfs-for-linux-4.10-rc5-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Darrick Wong:
 "I have a few more patches this week -- one to make the behavior of a
  quota id ioctl consistent with the other filesystems, and the rest
  improve validation of i_mode & i_size values coming into xfs so that
  we don't read off the ends of arrays or crash when handed garbage disk
  data.

  Summary:
   - inode i_mode sanitization
   - prevent overflows in getnextquota
   - minor build fixes"

* tag 'xfs-for-linux-4.10-rc5-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: fix xfs_mode_to_ftype() prototype
  xfs: don't wrap ID in xfs_dq_get_next_id
  xfs: sanity check inode di_mode
  xfs: sanity check inode mode when creating new dentry
  xfs: replace xfs_mode_to_ftype table with switch statement
  xfs: add missing include dependencies to xfs_dir2.h
  xfs: sanity check directory inode di_size
  xfs: make the ASSERT() condition likely
parents 81aaeaac fd29f7af
Loading
Loading
Loading
Loading
+24 −15
Original line number Diff line number Diff line
@@ -36,21 +36,29 @@
struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };

/*
 * @mode, if set, indicates that the type field needs to be set up.
 * This uses the transformation from file mode to DT_* as defined in linux/fs.h
 * for file type specification. This will be propagated into the directory
 * structure if appropriate for the given operation and filesystem config.
 * Convert inode mode to directory entry filetype
 */
const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
	[0]			= XFS_DIR3_FT_UNKNOWN,
	[S_IFREG >> S_SHIFT]    = XFS_DIR3_FT_REG_FILE,
	[S_IFDIR >> S_SHIFT]    = XFS_DIR3_FT_DIR,
	[S_IFCHR >> S_SHIFT]    = XFS_DIR3_FT_CHRDEV,
	[S_IFBLK >> S_SHIFT]    = XFS_DIR3_FT_BLKDEV,
	[S_IFIFO >> S_SHIFT]    = XFS_DIR3_FT_FIFO,
	[S_IFSOCK >> S_SHIFT]   = XFS_DIR3_FT_SOCK,
	[S_IFLNK >> S_SHIFT]    = XFS_DIR3_FT_SYMLINK,
};
unsigned char xfs_mode_to_ftype(int mode)
{
	switch (mode & S_IFMT) {
	case S_IFREG:
		return XFS_DIR3_FT_REG_FILE;
	case S_IFDIR:
		return XFS_DIR3_FT_DIR;
	case S_IFCHR:
		return XFS_DIR3_FT_CHRDEV;
	case S_IFBLK:
		return XFS_DIR3_FT_BLKDEV;
	case S_IFIFO:
		return XFS_DIR3_FT_FIFO;
	case S_IFSOCK:
		return XFS_DIR3_FT_SOCK;
	case S_IFLNK:
		return XFS_DIR3_FT_SYMLINK;
	default:
		return XFS_DIR3_FT_UNKNOWN;
	}
}

/*
 * ASCII case-insensitive (ie. A-Z) support for directories that was
@@ -631,7 +639,8 @@ xfs_dir2_isblock(
	if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
		return rval;
	rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
	ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize);
	if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
		return -EFSCORRUPTED;
	*vp = rval;
	return 0;
}
+5 −3
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@
#ifndef __XFS_DIR2_H__
#define __XFS_DIR2_H__

#include "xfs_da_format.h"
#include "xfs_da_btree.h"

struct xfs_defer_ops;
struct xfs_da_args;
struct xfs_inode;
@@ -32,10 +35,9 @@ struct xfs_dir2_data_unused;
extern struct xfs_name	xfs_name_dotdot;

/*
 * directory filetype conversion tables.
 * Convert inode mode to directory entry filetype
 */
#define S_SHIFT 12
extern const unsigned char xfs_mode_to_ftype[];
extern unsigned char xfs_mode_to_ftype(int mode);

/*
 * directory operations vector for encode/decode routines
+8 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "xfs_icache.h"
#include "xfs_trans.h"
#include "xfs_ialloc.h"
#include "xfs_dir2.h"

/*
 * Check that none of the inode's in the buffer have a next
@@ -386,6 +387,7 @@ xfs_dinode_verify(
	xfs_ino_t		ino,
	struct xfs_dinode	*dip)
{
	uint16_t		mode;
	uint16_t		flags;
	uint64_t		flags2;

@@ -396,8 +398,12 @@ xfs_dinode_verify(
	if (be64_to_cpu(dip->di_size) & (1ULL << 63))
		return false;

	/* No zero-length symlinks. */
	if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0)
	mode = be16_to_cpu(dip->di_mode);
	if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN)
		return false;

	/* No zero-length symlinks/dirs. */
	if ((S_ISLNK(mode) || S_ISDIR(mode)) && dip->di_size == 0)
		return false;

	/* only version 3 or greater inodes are extensively verified here */
+4 −0
Original line number Diff line number Diff line
@@ -710,6 +710,10 @@ xfs_dq_get_next_id(
	/* Simple advance */
	next_id = *id + 1;

	/* If we'd wrap past the max ID, stop */
	if (next_id < *id)
		return -ENOENT;

	/* If new ID is within the current chunk, advancing it sufficed */
	if (next_id % mp->m_quotainfo->qi_dqperchunk) {
		*id = next_id;
+40 −10
Original line number Diff line number Diff line
@@ -97,13 +97,28 @@ xfs_init_security(

static void
xfs_dentry_to_name(
	struct xfs_name	*namep,
	struct dentry	*dentry)
{
	namep->name = dentry->d_name.name;
	namep->len = dentry->d_name.len;
	namep->type = XFS_DIR3_FT_UNKNOWN;
}

static int
xfs_dentry_mode_to_name(
	struct xfs_name	*namep,
	struct dentry	*dentry,
	int		mode)
{
	namep->name = dentry->d_name.name;
	namep->len = dentry->d_name.len;
	namep->type = xfs_mode_to_ftype[(mode & S_IFMT) >> S_SHIFT];
	namep->type = xfs_mode_to_ftype(mode);

	if (unlikely(namep->type == XFS_DIR3_FT_UNKNOWN))
		return -EFSCORRUPTED;

	return 0;
}

STATIC void
@@ -119,7 +134,7 @@ xfs_cleanup_inode(
	 * xfs_init_security we must back out.
	 * ENOSPC can hit here, among other things.
	 */
	xfs_dentry_to_name(&teardown, dentry, 0);
	xfs_dentry_to_name(&teardown, dentry);

	xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
}
@@ -154,8 +169,12 @@ xfs_generic_create(
	if (error)
		return error;

	/* Verify mode is valid also for tmpfile case */
	error = xfs_dentry_mode_to_name(&name, dentry, mode);
	if (unlikely(error))
		goto out_free_acl;

	if (!tmpfile) {
		xfs_dentry_to_name(&name, dentry, mode);
		error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
	} else {
		error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip);
@@ -248,7 +267,7 @@ xfs_vn_lookup(
	if (dentry->d_name.len >= MAXNAMELEN)
		return ERR_PTR(-ENAMETOOLONG);

	xfs_dentry_to_name(&name, dentry, 0);
	xfs_dentry_to_name(&name, dentry);
	error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
	if (unlikely(error)) {
		if (unlikely(error != -ENOENT))
@@ -275,7 +294,7 @@ xfs_vn_ci_lookup(
	if (dentry->d_name.len >= MAXNAMELEN)
		return ERR_PTR(-ENAMETOOLONG);

	xfs_dentry_to_name(&xname, dentry, 0);
	xfs_dentry_to_name(&xname, dentry);
	error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
	if (unlikely(error)) {
		if (unlikely(error != -ENOENT))
@@ -310,7 +329,9 @@ xfs_vn_link(
	struct xfs_name	name;
	int		error;

	xfs_dentry_to_name(&name, dentry, inode->i_mode);
	error = xfs_dentry_mode_to_name(&name, dentry, inode->i_mode);
	if (unlikely(error))
		return error;

	error = xfs_link(XFS_I(dir), XFS_I(inode), &name);
	if (unlikely(error))
@@ -329,7 +350,7 @@ xfs_vn_unlink(
	struct xfs_name	name;
	int		error;

	xfs_dentry_to_name(&name, dentry, 0);
	xfs_dentry_to_name(&name, dentry);

	error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry)));
	if (error)
@@ -359,7 +380,9 @@ xfs_vn_symlink(

	mode = S_IFLNK |
		(irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
	xfs_dentry_to_name(&name, dentry, mode);
	error = xfs_dentry_mode_to_name(&name, dentry, mode);
	if (unlikely(error))
		goto out;

	error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip);
	if (unlikely(error))
@@ -395,6 +418,7 @@ xfs_vn_rename(
{
	struct inode	*new_inode = d_inode(ndentry);
	int		omode = 0;
	int		error;
	struct xfs_name	oname;
	struct xfs_name	nname;

@@ -405,8 +429,14 @@ xfs_vn_rename(
	if (flags & RENAME_EXCHANGE)
		omode = d_inode(ndentry)->i_mode;

	xfs_dentry_to_name(&oname, odentry, omode);
	xfs_dentry_to_name(&nname, ndentry, d_inode(odentry)->i_mode);
	error = xfs_dentry_mode_to_name(&oname, odentry, omode);
	if (omode && unlikely(error))
		return error;

	error = xfs_dentry_mode_to_name(&nname, ndentry,
					d_inode(odentry)->i_mode);
	if (unlikely(error))
		return error;

	return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)),
			  XFS_I(ndir), &nname,
Loading