Contained in this update:
- Inode i_mode sanitization - Prevent overflows in getnextquota - Minor build fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCgAGBQJYf9VQAAoJEPh/dxk0SrTr6CMQAJRUULHRS2SJe22pJSRzkjsl H838pav3bmTDGafWx5SgaazDHsVd205DHLU9ovi9zyqQGviG1kgIl9a7TvXtEU6R DXbjnxRTb9tgDbFKYstvl0lDXiWUFoB1nMOkNa8BDhBUe1sGadMXY5gh+CnpoKeg qEwNiE3yUJpnPVog4d+SRQSMTUbD3VQBtkh4IcucR+zqWsOiT7jiepqJvee5ZXYj Wz2Eo0QFhSGq7lk9IRl7C3ter77QMz6f4Ba3oZMjM2WD317JmKk5vDU1B7mHgRIZ cnwOayICECKs9GQWmgD5ew+GEaCRHuSzeoiP72O2bjwiLgJbG/eHQJ/8T7t3sgV0 mAIYZJXf8jjmTjzjV3n7aEt4iTKYssaLvmMQfg6AYwDXapzm7xYkcSDQa1pDFnEd DKDBsd17Xx399dtD/pjSw4X+/Z2ILEhcLvVKOO68jvM/wXIVQENKRt6/5QEUdBkw HjuLccA5e5gpjZ00S7cZo44TRgbJPG+hw611Fy3reJPW1sHQJEbpspOMIRB3vpff HxoTQm864ZNxR7pXv5sX9gxHp4JLAZ2wfxa+iLe/0rAelq01OHlz7fygc27jXilU v6URno92PbARzvtyeVAZ+FJLRBpQy90Y4ZRM87GDebCGCDo8xqtxxhiG1xIqriON PYLuQNeF2MELGUm3nlJO =4Mxu -----END PGP SIGNATURE----- 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
This commit is contained in:
Коммит
6e0362b3a8
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -331,11 +331,11 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
|
|||
}
|
||||
|
||||
#define ASSERT_ALWAYS(expr) \
|
||||
(unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
|
||||
(likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ASSERT(expr) \
|
||||
(unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
|
||||
(likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
|
||||
|
||||
#ifndef STATIC
|
||||
# define STATIC noinline
|
||||
|
@ -346,7 +346,7 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
|
|||
#ifdef XFS_WARN
|
||||
|
||||
#define ASSERT(expr) \
|
||||
(unlikely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__))
|
||||
(likely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__))
|
||||
|
||||
#ifndef STATIC
|
||||
# define STATIC static noinline
|
||||
|
|
Загрузка…
Ссылка в новой задаче