mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-29 04:09:39 +00:00
\n
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmGWL+AACgkQnJ2qBz9k QNnK3ggAtJLlaCwg4TxyIIGEWBP/KBKs2STLf80VDavhxZuplKKZ0o5/9IPZ2uu9 v9SgME4hnGpUNaECttVWqijT823SiIxA/4uFSBnN1hLlvPj2Wkwl0oRWb6vCFzZ5 OBUiZrycZKxEq78p2Ao8+FxeRsJ9RuXHnPkZULAqizkEue23d+gW33cO0x//UwB0 lB6i32yDqCmOAtLaT1Div5ttJ3oM/hGBbOURkh3YB7jV2MxojHX28ZjDv657S30k lhpQwvmHF70jM7MPWbxtcbSTBdPKQdaF5+oDqpAFwDQn3nhEk1sjw6IrCUKr2NAK Z+YFlRgv5eD+loRPEBVVU/6QrmfSEQ== =ueAF -----END PGP SIGNATURE----- Merge tag 'fs_for_v5.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs Pull UDF fix from Jan Kara: "A fix for a long-standing UDF bug where we were not properly validating directory position inside readdir" * tag 'fs_for_v5.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: udf: Fix crash after seekdir
This commit is contained in:
commit
db850a9b8d
3 changed files with 35 additions and 2 deletions
32
fs/udf/dir.c
32
fs/udf/dir.c
|
@ -31,6 +31,7 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/iversion.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
@ -43,7 +44,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
|
|||
struct fileIdentDesc *fi = NULL;
|
||||
struct fileIdentDesc cfi;
|
||||
udf_pblk_t block, iblock;
|
||||
loff_t nf_pos;
|
||||
loff_t nf_pos, emit_pos = 0;
|
||||
int flen;
|
||||
unsigned char *fname = NULL, *copy_name = NULL;
|
||||
unsigned char *nameptr;
|
||||
|
@ -57,6 +58,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
|
|||
int i, num, ret = 0;
|
||||
struct extent_position epos = { NULL, 0, {0, 0} };
|
||||
struct super_block *sb = dir->i_sb;
|
||||
bool pos_valid = false;
|
||||
|
||||
if (ctx->pos == 0) {
|
||||
if (!dir_emit_dot(file, ctx))
|
||||
|
@ -67,6 +69,21 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
|
|||
if (nf_pos >= size)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Something changed since last readdir (either lseek was called or dir
|
||||
* changed)? We need to verify the position correctly points at the
|
||||
* beginning of some dir entry so that the directory parsing code does
|
||||
* not get confused. Since UDF does not have any reliable way of
|
||||
* identifying beginning of dir entry (names are under user control),
|
||||
* we need to scan the directory from the beginning.
|
||||
*/
|
||||
if (!inode_eq_iversion(dir, file->f_version)) {
|
||||
emit_pos = nf_pos;
|
||||
nf_pos = 0;
|
||||
} else {
|
||||
pos_valid = true;
|
||||
}
|
||||
|
||||
fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
|
||||
if (!fname) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -122,13 +139,21 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
|
|||
|
||||
while (nf_pos < size) {
|
||||
struct kernel_lb_addr tloc;
|
||||
loff_t cur_pos = nf_pos;
|
||||
|
||||
ctx->pos = (nf_pos >> 2) + 1;
|
||||
/* Update file position only if we got past the current one */
|
||||
if (nf_pos >= emit_pos) {
|
||||
ctx->pos = (nf_pos >> 2) + 1;
|
||||
pos_valid = true;
|
||||
}
|
||||
|
||||
fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
|
||||
&elen, &offset);
|
||||
if (!fi)
|
||||
goto out;
|
||||
/* Still not at offset where user asked us to read from? */
|
||||
if (cur_pos < emit_pos)
|
||||
continue;
|
||||
|
||||
liu = le16_to_cpu(cfi.lengthOfImpUse);
|
||||
lfi = cfi.lengthFileIdent;
|
||||
|
@ -186,8 +211,11 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
|
|||
} /* end while */
|
||||
|
||||
ctx->pos = (nf_pos >> 2) + 1;
|
||||
pos_valid = true;
|
||||
|
||||
out:
|
||||
if (pos_valid)
|
||||
file->f_version = inode_query_iversion(dir);
|
||||
if (fibh.sbh != fibh.ebh)
|
||||
brelse(fibh.ebh);
|
||||
brelse(fibh.sbh);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/crc-itu-t.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/iversion.h>
|
||||
|
||||
static inline int udf_match(int len1, const unsigned char *name1, int len2,
|
||||
const unsigned char *name2)
|
||||
|
@ -134,6 +135,8 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
|
|||
mark_buffer_dirty_inode(fibh->ebh, inode);
|
||||
mark_buffer_dirty_inode(fibh->sbh, inode);
|
||||
}
|
||||
inode_inc_iversion(inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include <linux/crc-itu-t.h>
|
||||
#include <linux/log2.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/iversion.h>
|
||||
|
||||
#include "udf_sb.h"
|
||||
#include "udf_i.h"
|
||||
|
@ -149,6 +150,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
|
|||
init_rwsem(&ei->i_data_sem);
|
||||
ei->cached_extent.lstart = -1;
|
||||
spin_lock_init(&ei->i_extent_cache_lock);
|
||||
inode_set_iversion(&ei->vfs_inode, 1);
|
||||
|
||||
return &ei->vfs_inode;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue