Patch "xfs: verify inline directory data forks" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
xfs: verify inline directory data forks
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
xfs-verify-inline-directory-data-forks.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
630a04e79dd41ff746b545d4fc052e0abb836120Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <[email protected]>
Date: Wed, 15 Mar 2017 00:24:25 -0700
Subject: xfs: verify inline directory data forks
From: Darrick J. Wong <[email protected]>
commit 630a04e79dd41ff746b545d4fc052e0abb836120 upstream.
When we're reading or writing the data fork of an inline directory, check the contents to make sure we're not overflowing buffers or eating garbage data. xfs/348 corrupts an inline symlink into an inline directory, triggering a buffer overflow bug.
v2: add more checks consistent with _dir2_sf_check and make the verifier usable from anywhere.
--- fs/xfs/libxfs/xfs_dir2_priv.h | 2 fs/xfs/libxfs/xfs_dir2_sf.c | 87 +++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_inode_fork.c | 26 ++++++++++-- fs/xfs/libxfs/xfs_inode_fork.h | 2 fs/xfs/xfs_dir2_readdir.c | 11 ----- fs/xfs/xfs_inode.c | 12 ++++- 6 files changed, 122 insertions(+), 18 deletions(-)
fs/xfs/libxfs/xfs_dir2_priv.h +2 -0
@@ -126,6 +126,8 @@ extern int xfs_dir2_sf_create(struct xfsextern int xfs_dir2_sf_lookup (struct xfs_da_args *args);extern int xfs_dir2_sf_removename (struct xfs_da_args *args);extern int xfs_dir2_sf_replace (struct xfs_da_args *args); +extern int xfs_dir2_sf_verify (struct xfs_mount *mp,struct xfs_dir2_sf_hdr *sfp, +int size);/* xfs_dir2_readdir.c */ extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx,
fs/xfs/libxfs/xfs_dir2_sf.c +87 -0
93 lines not on this page · raw message
fs/xfs/libxfs/xfs_inode_fork.c +23 -3
@@ -33,6 +33,8 @@#include "xfs_trace.h" #include "xfs_attr_sf.h" #include "xfs_da_format.h" +#include "xfs_da_btree.h" +#include "xfs_dir2_priv.h" kmem_zone_t *xfs_ifork_zone;
@@ -320,6 +322,7 @@ xfs_iformat_local( int whichfork, int size) { +int error;/* * If the size is unreasonable, then something
@@ -336,6 +339,14 @@ xfs_iformat_local(return -EFSCORRUPTED ; } +if (S_ISDIR (VFS_I (ip)->i_mode) && whichfork ==XFS_DATA_FORK ) { + error =xfs_dir2_sf_verify (ip->i_mount, + (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR (dip), + size); +if (error) +return error; + } +xfs_init_local_fork (ip, whichfork,XFS_DFORK_PTR (dip, whichfork), size);return 0 ; }
@@ -856,7 +867,7 @@ xfs_iextents_copy(* In these cases, the format always takes precedence, because the * format indicates the current state of the fork. */ -void +int xfs_iflush_fork( xfs_inode_t *ip, xfs_dinode_t *dip,
@@ -866,6 +877,7 @@ xfs_iflush_fork(char *cp;xfs_ifork_t *ifp;xfs_mount_t *mp; +int error;static const short brootflag[2 ] = {XFS_ILOG_DBROOT ,XFS_ILOG_ABROOT }; static const short dataflag[2] =
@@ -874,7 +886,7 @@ xfs_iflush_fork( { XFS_ILOG_DEXT, XFS_ILOG_AEXT };if (!iip) -return ; +return 0 ; ifp =XFS_IFORK_PTR (ip, whichfork);/* * This can happen if we gave up in iformat in an error path,
@@ -882,12 +894,19 @@ xfs_iflush_fork(*/ if (!ifp) {ASSERT (whichfork ==XFS_ATTR_FORK ); -return ; +return 0 ; } cp =XFS_DFORK_PTR (dip, whichfork); mp = ip->i_mount;switch (XFS_IFORK_FORMAT (ip, whichfork)) {case XFS_DINODE_FMT_LOCAL : +if (S_ISDIR (VFS_I (ip)->i_mode) && whichfork ==XFS_DATA_FORK ) { + error =xfs_dir2_sf_verify (mp, + (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data, + ifp->if_bytes); +if (error) +return error; + }if ((iip->ili_fields & dataflag[whichfork]) && (ifp->if_bytes >0 )) {ASSERT (ifp->if_u1.if_data !=NULL );
@@ -940,6 +959,7 @@ xfs_iflush_fork(ASSERT (0 );break ; } +return 0 ; }/*
fs/xfs/libxfs/xfs_inode_fork.h +1 -1
@@ -140,7 +140,7 @@ typedef struct xfs_ifork {struct xfs_ifork *xfs_iext_state_to_fork (struct xfs_inode *ip,int state);int xfs_iformat_fork (struct xfs_inode *,struct xfs_dinode *); -void xfs_iflush_fork (struct xfs_inode *,struct xfs_dinode *, +int xfs_iflush_fork (struct xfs_inode *,struct xfs_dinode *,struct xfs_inode_log_item *,int );void xfs_idestroy_fork (struct xfs_inode *,int );void xfs_idata_realloc (struct xfs_inode *,int ,int );
fs/xfs/xfs_dir2_readdir.c +0 -11
@@ -71,22 +71,11 @@ xfs_dir2_sf_getdents(struct xfs_da_geometry *geo = args->geo;ASSERT (dp->i_df.if_flags &XFS_IFINLINE ); -/* -* Give up if the directory is way too short. -*/ -if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t , parent)) { -ASSERT (XFS_FORCED_SHUTDOWN (dp->i_mount)); -return -EIO ; - } -ASSERT (dp->i_df.if_bytes == dp->i_d.di_size);ASSERT (dp->i_df.if_u1.if_data !=NULL ); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; -if (dp->i_d.di_size <xfs_dir2_sf_hdr_size (sfp->i8count)) -return -EFSCORRUPTED ; -/* * If the block number in the offset is out of range, we're done. */
fs/xfs/xfs_inode.c +9 -3
@@ -3491,6 +3491,7 @@ xfs_iflush_int(struct xfs_inode_log_item *iip = ip->i_itemp;struct xfs_dinode *dip;struct xfs_mount *mp = ip->i_mount; +int error;ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL |XFS_ILOCK_SHARED ));ASSERT (xfs_isiflocked (ip));
@@ -3573,9 +3574,14 @@ xfs_iflush_int(if (ip->i_d.di_flushiter ==DI_MAX_FLUSH ) ip->i_d.di_flushiter =0 ; -xfs_iflush_fork (ip, dip, iip,XFS_DATA_FORK ); -if (XFS_IFORK_Q (ip)) -xfs_iflush_fork (ip, dip, iip,XFS_ATTR_FORK ); + error =xfs_iflush_fork (ip, dip, iip,XFS_DATA_FORK ); +if (error) +return error; +if (XFS_IFORK_Q (ip)) { + error =xfs_iflush_fork (ip, dip, iip,XFS_ATTR_FORK ); +if (error) +return error; + }xfs_inobp_check (mp, bp);/*
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/xfs-fix-missed-holes-in-seek_hole-implementation.patch queue-4.9/xfs-fix-off-by-one-on-max-nr_pages-in-xfs_find_get_desired_pgoff.patch queue-4.9/xfs-use-dedicated-log-worker-wq-to-avoid-deadlock-with-cil-wq.patch queue-4.9/xfs-rework-the-inline-directory-verifiers.patch queue-4.9/xfs-use-b_state-to-fix-buffer-i-o-accounting-release-race.patch queue-4.9/xfs-verify-inline-directory-data-forks.patch queue-4.9/xfs-fix-kernel-memory-exposure-problems.patch