]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/2.6.15.7/fix-ext2-readdir-f_pos-re-validation-logic.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.15.7 / fix-ext2-readdir-f_pos-re-validation-logic.patch
CommitLineData
ac6dc5f6
CW
1From nobody Mon Sep 17 00:00:00 2001
2From: Al Viro <viro@ftp.linux.org.uk>
3Date: Wed Mar 15 21:41:59 2006 +0000
4Subject: [PATCH] Fix ext2 readdir f_pos re-validation logic
5
6This fixes not one, but _two_, silly (but admittedly hard to hit) bugs
7in the ext2 filesystem "readdir()" function. It also cleans up the code
8to avoid the unnecessary goto mess.
9
10The bugs were related to re-valiating the f_pos value after somebody had
11either done an "lseek()" on the directory to an invalid offset, or when
12the offset had become invalid due to a file being unlinked in the
13directory. The code would not only set the f_version too eagerly, it
14would also not update f_pos appropriately for when the offset fixup took
15place.
16
17When that happened, we'd occasionally subsequently fail the readdir()
18even when we shouldn't (no real harm done, but an ugly printk, and
19obviously you would end up not necessarily seeing all entries).
20
21Thanks to Masoud Sharbiani <masouds@google.com> who noticed the problem
22and had a test-case for it, and also fixed up a thinko in the first
23version of this patch.
24
25Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
26Acked-by: Masoud Sharbiani <masouds@google.com>
27Signed-off-by: Linus Torvalds <torvalds@osdl.org>
28Signed-off-by: Chris Wright <chrisw@sous-sol.org>
5390119a 29Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
ac6dc5f6
CW
30---
31
32 fs/ext2/dir.c | 28 ++++++++++++----------------
5390119a 33 1 file changed, 12 insertions(+), 16 deletions(-)
ac6dc5f6
CW
34
352d7f2ea9c989853310c7f6e8be52cc090cc8e66b
ac6dc5f6
CW
36--- linux-2.6.15.6.orig/fs/ext2/dir.c
37+++ linux-2.6.15.6/fs/ext2/dir.c
38@@ -256,11 +256,10 @@ ext2_readdir (struct file * filp, void *
39 unsigned long npages = dir_pages(inode);
40 unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
41 unsigned char *types = NULL;
42- int need_revalidate = (filp->f_version != inode->i_version);
43- int ret;
44+ int need_revalidate = filp->f_version != inode->i_version;
45
46 if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
47- goto success;
48+ return 0;
49
50 if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
51 types = ext2_filetype_table;
52@@ -275,12 +274,15 @@ ext2_readdir (struct file * filp, void *
53 "bad page in #%lu",
54 inode->i_ino);
55 filp->f_pos += PAGE_CACHE_SIZE - offset;
56- ret = -EIO;
57- goto done;
58+ return -EIO;
59 }
60 kaddr = page_address(page);
61- if (need_revalidate) {
62- offset = ext2_validate_entry(kaddr, offset, chunk_mask);
63+ if (unlikely(need_revalidate)) {
64+ if (offset) {
65+ offset = ext2_validate_entry(kaddr, offset, chunk_mask);
66+ filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
67+ }
68+ filp->f_version = inode->i_version;
69 need_revalidate = 0;
70 }
71 de = (ext2_dirent *)(kaddr+offset);
72@@ -289,9 +291,8 @@ ext2_readdir (struct file * filp, void *
73 if (de->rec_len == 0) {
74 ext2_error(sb, __FUNCTION__,
75 "zero-length directory entry");
76- ret = -EIO;
77 ext2_put_page(page);
78- goto done;
79+ return -EIO;
80 }
81 if (de->inode) {
82 int over;
83@@ -306,19 +307,14 @@ ext2_readdir (struct file * filp, void *
84 le32_to_cpu(de->inode), d_type);
85 if (over) {
86 ext2_put_page(page);
87- goto success;
88+ return 0;
89 }
90 }
91 filp->f_pos += le16_to_cpu(de->rec_len);
92 }
93 ext2_put_page(page);
94 }
95-
96-success:
97- ret = 0;
98-done:
99- filp->f_version = inode->i_version;
100- return ret;
101+ return 0;
102 }
103
104 /*