2008-10-22 15:11:57

by Eric Sandeen

[permalink] [raw]
Subject: [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

This is a trivial backport of the following upstream commits:

- bd39597cbd42a784105a04010100e27267481c67 (ext2)
- cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
- 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)

This addresses CVE-2008-3528

ext[234]: Avoid printk floods in the face of directory corruption

Note: some people thinks this represents a security bug, since it
might make the system go away while it is printing a large number of
console messages, especially if a serial console is involved. Hence,
it has been assigned CVE-2008-3528, but it requires that the attacker
either has physical access to your machine to insert a USB disk with a
corrupted filesystem image (at which point why not just hit the power
button), or is otherwise able to convince the system administrator to
mount an arbitrary filesystem image (at which point why not just
include a setuid shell or world-writable hard disk device file or some
such). Me, I think they're just being silly. --tytso

Signed-off-by: Eric Sandeen <[email protected]>
Signed-off-by: "Theodore Ts'o" <[email protected]>
Cc: [email protected]
Cc: Eugene Teo <[email protected]>
---

Index: linux-2.6/fs/ext2/dir.c
===================================================================
--- linux-2.6.orig/fs/ext2/dir.c 2008-10-22 09:49:34.147001360 -0500
+++ linux-2.6/fs/ext2/dir.c 2008-10-22 09:59:12.242063845 -0500
@@ -103,7 +103,7 @@ static int ext2_commit_chunk(struct page
return err;
}

-static void ext2_check_page(struct page *page)
+static void ext2_check_page(struct page *page, int quiet)
{
struct inode *dir = page->mapping->host;
struct super_block *sb = dir->i_sb;
@@ -146,10 +146,10 @@ out:
/* Too bad, we had an error */

Ebadsize:
- ext2_error(sb, "ext2_check_page",
- "size of directory #%lu is not a multiple of chunk size",
- dir->i_ino
- );
+ if (!quiet)
+ ext2_error(sb, __func__,
+ "size of directory #%lu is not a multiple "
+ "of chunk size", dir->i_ino);
goto fail;
Eshort:
error = "rec_len is smaller than minimal";
@@ -166,32 +166,36 @@ Espan:
Einumber:
error = "inode out of bounds";
bad_entry:
- ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode),
- rec_len, p->name_len);
+ if (!quiet)
+ ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode),
+ rec_len, p->name_len);
goto fail;
Eend:
- p = (ext2_dirent *)(kaddr + offs);
- ext2_error (sb, "ext2_check_page",
- "entry in directory #%lu spans the page boundary"
- "offset=%lu, inode=%lu",
- dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode));
+ if (!quiet) {
+ p = (ext2_dirent *)(kaddr + offs);
+ ext2_error(sb, "ext2_check_page",
+ "entry in directory #%lu spans the page boundary"
+ "offset=%lu, inode=%lu",
+ dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode));
+ }
fail:
SetPageChecked(page);
SetPageError(page);
}

-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+static struct page * ext2_get_page(struct inode *dir, unsigned long n,
+ int quiet)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
kmap(page);
if (!PageChecked(page))
- ext2_check_page(page);
+ ext2_check_page(page, quiet);
if (PageError(page))
goto fail;
}
@@ -292,7 +296,7 @@ ext2_readdir (struct file * filp, void *
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
ext2_dirent *de;
- struct page *page = ext2_get_page(inode, n);
+ struct page *page = ext2_get_page(inode, n, 0);

if (IS_ERR(page)) {
ext2_error(sb, __func__,
@@ -361,6 +365,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
struct page *page = NULL;
struct ext2_inode_info *ei = EXT2_I(dir);
ext2_dirent * de;
+ int dir_has_error = 0;

if (npages == 0)
goto out;
@@ -374,7 +379,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
n = start;
do {
char *kaddr;
- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, dir_has_error);
if (!IS_ERR(page)) {
kaddr = page_address(page);
de = (ext2_dirent *) kaddr;
@@ -391,7 +396,9 @@ struct ext2_dir_entry_2 * ext2_find_entr
de = ext2_next_entry(de);
}
ext2_put_page(page);
- }
+ } else
+ dir_has_error = 1;
+
if (++n >= npages)
n = 0;
/* next page is past the blocks we've got */
@@ -414,7 +421,7 @@ found:

struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
{
- struct page *page = ext2_get_page(dir, 0);
+ struct page *page = ext2_get_page(dir, 0, 0);
ext2_dirent *de = NULL;

if (!IS_ERR(page)) {
@@ -487,7 +494,7 @@ int ext2_add_link (struct dentry *dentry
for (n = 0; n <= npages; n++) {
char *dir_end;

- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, 0);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
@@ -655,14 +662,17 @@ int ext2_empty_dir (struct inode * inode
{
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
+ int dir_has_error = 0;

for (i = 0; i < npages; i++) {
char *kaddr;
ext2_dirent * de;
- page = ext2_get_page(inode, i);
+ page = ext2_get_page(inode, i, dir_has_error);

- if (IS_ERR(page))
+ if (IS_ERR(page)) {
+ dir_has_error = 1;
continue;
+ }

kaddr = page_address(page);
de = (ext2_dirent *)kaddr;
Index: linux-2.6/fs/ext3/dir.c
===================================================================
--- linux-2.6.orig/fs/ext3/dir.c 2008-10-22 09:49:34.198580960 -0500
+++ linux-2.6/fs/ext3/dir.c 2008-10-22 09:59:27.385064161 -0500
@@ -102,6 +102,7 @@ static int ext3_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -148,9 +149,12 @@ static int ext3_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext3_error (sb, "ext3_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext3_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %lld",
+ inode->i_ino, filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;
Index: linux-2.6/fs/ext4/dir.c
===================================================================
--- linux-2.6.orig/fs/ext4/dir.c 2008-10-22 10:02:03.639064037 -0500
+++ linux-2.6/fs/ext4/dir.c 2008-10-22 10:02:45.235001297 -0500
@@ -102,6 +102,7 @@ static int ext4_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -148,9 +149,13 @@ static int ext4_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext4_error (sb, "ext4_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext4_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %Lu",
+ inode->i_ino,
+ (unsigned long long) filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;




2008-10-22 16:17:53

by Greg KH

[permalink] [raw]
Subject: Re: [stable] [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

On Wed, Oct 22, 2008 at 10:11:52AM -0500, Eric Sandeen wrote:
> This is a trivial backport of the following upstream commits:
>
> - bd39597cbd42a784105a04010100e27267481c67 (ext2)
> - cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
> - 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)
>
> This addresses CVE-2008-3528
>
> ext[234]: Avoid printk floods in the face of directory corruption

For what kernel releases is this applicable? .27? .26? .25? Earlier?

thanks,

greg k-h

2008-10-22 16:21:15

by Eric Sandeen

[permalink] [raw]
Subject: Re: [stable] [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

Greg KH wrote:
> On Wed, Oct 22, 2008 at 10:11:52AM -0500, Eric Sandeen wrote:
>> This is a trivial backport of the following upstream commits:
>>
>> - bd39597cbd42a784105a04010100e27267481c67 (ext2)
>> - cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
>> - 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)
>>
>> This addresses CVE-2008-3528
>>
>> ext[234]: Avoid printk floods in the face of directory corruption
>
> For what kernel releases is this applicable? .27? .26? .25? Earlier?

Sorry.. it is applicable to pretty much any kernel in the past :) .27
certainly (that's what the patch is against), .26, .25.... yes.

It's not a particularly dangerous condition - you have to somehow get
the administrator to mount the filesystem before you can trigger the
"exploit" (which is a DoS, essentially) - so, I don't know if it's worth
porting back to the dawn of time...

Thanks,
-Eric

> thanks,
>
> greg k-h


2008-10-22 17:03:24

by Greg KH

[permalink] [raw]
Subject: Re: [stable] [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

On Wed, Oct 22, 2008 at 11:21:08AM -0500, Eric Sandeen wrote:
> Greg KH wrote:
> > On Wed, Oct 22, 2008 at 10:11:52AM -0500, Eric Sandeen wrote:
> >> This is a trivial backport of the following upstream commits:
> >>
> >> - bd39597cbd42a784105a04010100e27267481c67 (ext2)
> >> - cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
> >> - 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)
> >>
> >> This addresses CVE-2008-3528
> >>
> >> ext[234]: Avoid printk floods in the face of directory corruption
> >
> > For what kernel releases is this applicable? .27? .26? .25? Earlier?
>
> Sorry.. it is applicable to pretty much any kernel in the past :) .27
> certainly (that's what the patch is against), .26, .25.... yes.
>
> It's not a particularly dangerous condition - you have to somehow get
> the administrator to mount the filesystem before you can trigger the
> "exploit" (which is a DoS, essentially) - so, I don't know if it's worth
> porting back to the dawn of time...

Well, I will not port it back to older kernels than .25, so that's not a
big deal.

As for the "admin mount a filesystem", you could put an ext2/3 fs on a
usb stick and plug it into a box. It will be mounted automatically, no
admin rights required, and the DoS would happen, right?

thanks,

greg k-h

2008-10-22 17:35:11

by Eric Sandeen

[permalink] [raw]
Subject: Re: [stable] [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

Greg KH wrote:
> On Wed, Oct 22, 2008 at 11:21:08AM -0500, Eric Sandeen wrote:
>> Greg KH wrote:
>>> On Wed, Oct 22, 2008 at 10:11:52AM -0500, Eric Sandeen wrote:
>>>> This is a trivial backport of the following upstream commits:
>>>>
>>>> - bd39597cbd42a784105a04010100e27267481c67 (ext2)
>>>> - cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
>>>> - 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)
>>>>
>>>> This addresses CVE-2008-3528
>>>>
>>>> ext[234]: Avoid printk floods in the face of directory corruption
>>> For what kernel releases is this applicable? .27? .26? .25? Earlier?
>> Sorry.. it is applicable to pretty much any kernel in the past :) .27
>> certainly (that's what the patch is against), .26, .25.... yes.
>>
>> It's not a particularly dangerous condition - you have to somehow get
>> the administrator to mount the filesystem before you can trigger the
>> "exploit" (which is a DoS, essentially) - so, I don't know if it's worth
>> porting back to the dawn of time...
>
> Well, I will not port it back to older kernels than .25, so that's not a
> big deal.
>
> As for the "admin mount a filesystem", you could put an ext2/3 fs on a
> usb stick and plug it into a box. It will be mounted automatically, no
> admin rights required, and the DoS would happen, right?

If I wanted to DoS a box sitting in front of me, I'd just pull the plug.

-Eric

2008-10-22 17:43:37

by Greg KH

[permalink] [raw]
Subject: Re: [stable] [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

On Wed, Oct 22, 2008 at 12:35:06PM -0500, Eric Sandeen wrote:
> Greg KH wrote:
> > On Wed, Oct 22, 2008 at 11:21:08AM -0500, Eric Sandeen wrote:
> >> Greg KH wrote:
> >>> On Wed, Oct 22, 2008 at 10:11:52AM -0500, Eric Sandeen wrote:
> >>>> This is a trivial backport of the following upstream commits:
> >>>>
> >>>> - bd39597cbd42a784105a04010100e27267481c67 (ext2)
> >>>> - cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
> >>>> - 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)
> >>>>
> >>>> This addresses CVE-2008-3528
> >>>>
> >>>> ext[234]: Avoid printk floods in the face of directory corruption
> >>> For what kernel releases is this applicable? .27? .26? .25? Earlier?
> >> Sorry.. it is applicable to pretty much any kernel in the past :) .27
> >> certainly (that's what the patch is against), .26, .25.... yes.
> >>
> >> It's not a particularly dangerous condition - you have to somehow get
> >> the administrator to mount the filesystem before you can trigger the
> >> "exploit" (which is a DoS, essentially) - so, I don't know if it's worth
> >> porting back to the dawn of time...
> >
> > Well, I will not port it back to older kernels than .25, so that's not a
> > big deal.
> >
> > As for the "admin mount a filesystem", you could put an ext2/3 fs on a
> > usb stick and plug it into a box. It will be mounted automatically, no
> > admin rights required, and the DoS would happen, right?
>
> If I wanted to DoS a box sitting in front of me, I'd just pull the plug.

Yes, the fun "physical access" issue, right?

But for some, who run Linux in a "kiosk" mode, or in semi-secured places
like university labs, something like this would matter, so you might
want to notify the distros of this issue through vendor-sec and let them
make up their minds if they wish to backport the fixes to their
supported releases.

thanks,

greg k-h

2008-10-22 19:34:06

by Eric Sandeen

[permalink] [raw]
Subject: Re: [stable] [PATCH] stable - ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

Greg KH wrote:

> Yes, the fun "physical access" issue, right?
>
> But for some, who run Linux in a "kiosk" mode, or in semi-secured places
> like university labs, something like this would matter, so you might
> want to notify the distros of this issue through vendor-sec and let them
> make up their minds if they wish to backport the fixes to their
> supported releases.

Well, the CVE should do that, right... distro security teams should be
looking at the CVEs.

-Eric

2008-10-23 21:02:55

by Greg KH

[permalink] [raw]
Subject: patch ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch added to 2.6.27-stable tree


This is a note to let you know that we have just queued up the patch titled

Subject: ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

to the 2.6.27-stable tree. Its filename is

ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch

A git repo of this tree can be found at
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary


>From [email protected] Thu Oct 23 13:13:44 2008
From: Eric Sandeen <[email protected]>
Date: Wed, 22 Oct 2008 10:11:52 -0500
Subject: ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)
To: [email protected]
Cc: ext4 development <[email protected]>
Message-ID: <[email protected]>

From: Eric Sandeen <[email protected]>

This is a trivial backport of the following upstream commits:

- bd39597cbd42a784105a04010100e27267481c67 (ext2)
- cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
- 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)

This addresses CVE-2008-3528

ext[234]: Avoid printk floods in the face of directory corruption

Note: some people thinks this represents a security bug, since it
might make the system go away while it is printing a large number of
console messages, especially if a serial console is involved. Hence,
it has been assigned CVE-2008-3528, but it requires that the attacker
either has physical access to your machine to insert a USB disk with a
corrupted filesystem image (at which point why not just hit the power
button), or is otherwise able to convince the system administrator to
mount an arbitrary filesystem image (at which point why not just
include a setuid shell or world-writable hard disk device file or some
such). Me, I think they're just being silly. --tytso

Signed-off-by: Eric Sandeen <[email protected]>
Signed-off-by: "Theodore Ts'o" <[email protected]>
Cc: [email protected]
Cc: Eugene Teo <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
fs/ext2/dir.c | 60 +++++++++++++++++++++++++++++++++-------------------------
fs/ext3/dir.c | 10 ++++++---
fs/ext4/dir.c | 11 +++++++---
3 files changed, 50 insertions(+), 31 deletions(-)

--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -103,7 +103,7 @@ static int ext2_commit_chunk(struct page
return err;
}

-static void ext2_check_page(struct page *page)
+static void ext2_check_page(struct page *page, int quiet)
{
struct inode *dir = page->mapping->host;
struct super_block *sb = dir->i_sb;
@@ -146,10 +146,10 @@ out:
/* Too bad, we had an error */

Ebadsize:
- ext2_error(sb, "ext2_check_page",
- "size of directory #%lu is not a multiple of chunk size",
- dir->i_ino
- );
+ if (!quiet)
+ ext2_error(sb, __func__,
+ "size of directory #%lu is not a multiple "
+ "of chunk size", dir->i_ino);
goto fail;
Eshort:
error = "rec_len is smaller than minimal";
@@ -166,32 +166,36 @@ Espan:
Einumber:
error = "inode out of bounds";
bad_entry:
- ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode),
- rec_len, p->name_len);
+ if (!quiet)
+ ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode),
+ rec_len, p->name_len);
goto fail;
Eend:
- p = (ext2_dirent *)(kaddr + offs);
- ext2_error (sb, "ext2_check_page",
- "entry in directory #%lu spans the page boundary"
- "offset=%lu, inode=%lu",
- dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode));
+ if (!quiet) {
+ p = (ext2_dirent *)(kaddr + offs);
+ ext2_error(sb, "ext2_check_page",
+ "entry in directory #%lu spans the page boundary"
+ "offset=%lu, inode=%lu",
+ dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode));
+ }
fail:
SetPageChecked(page);
SetPageError(page);
}

-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+static struct page * ext2_get_page(struct inode *dir, unsigned long n,
+ int quiet)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
kmap(page);
if (!PageChecked(page))
- ext2_check_page(page);
+ ext2_check_page(page, quiet);
if (PageError(page))
goto fail;
}
@@ -292,7 +296,7 @@ ext2_readdir (struct file * filp, void *
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
ext2_dirent *de;
- struct page *page = ext2_get_page(inode, n);
+ struct page *page = ext2_get_page(inode, n, 0);

if (IS_ERR(page)) {
ext2_error(sb, __func__,
@@ -361,6 +365,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
struct page *page = NULL;
struct ext2_inode_info *ei = EXT2_I(dir);
ext2_dirent * de;
+ int dir_has_error = 0;

if (npages == 0)
goto out;
@@ -374,7 +379,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
n = start;
do {
char *kaddr;
- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, dir_has_error);
if (!IS_ERR(page)) {
kaddr = page_address(page);
de = (ext2_dirent *) kaddr;
@@ -391,7 +396,9 @@ struct ext2_dir_entry_2 * ext2_find_entr
de = ext2_next_entry(de);
}
ext2_put_page(page);
- }
+ } else
+ dir_has_error = 1;
+
if (++n >= npages)
n = 0;
/* next page is past the blocks we've got */
@@ -414,7 +421,7 @@ found:

struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
{
- struct page *page = ext2_get_page(dir, 0);
+ struct page *page = ext2_get_page(dir, 0, 0);
ext2_dirent *de = NULL;

if (!IS_ERR(page)) {
@@ -487,7 +494,7 @@ int ext2_add_link (struct dentry *dentry
for (n = 0; n <= npages; n++) {
char *dir_end;

- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, 0);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
@@ -655,14 +662,17 @@ int ext2_empty_dir (struct inode * inode
{
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
+ int dir_has_error = 0;

for (i = 0; i < npages; i++) {
char *kaddr;
ext2_dirent * de;
- page = ext2_get_page(inode, i);
+ page = ext2_get_page(inode, i, dir_has_error);

- if (IS_ERR(page))
+ if (IS_ERR(page)) {
+ dir_has_error = 1;
continue;
+ }

kaddr = page_address(page);
de = (ext2_dirent *)kaddr;
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -102,6 +102,7 @@ static int ext3_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -148,9 +149,12 @@ static int ext3_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext3_error (sb, "ext3_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext3_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %lld",
+ inode->i_ino, filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -102,6 +102,7 @@ static int ext4_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -148,9 +149,13 @@ static int ext4_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext4_error (sb, "ext4_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext4_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %Lu",
+ inode->i_ino,
+ (unsigned long long) filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;


Patches currently in stable-queue which might be from [email protected] are

queue-2.6.27/ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch

2008-10-23 21:15:57

by Greg KH

[permalink] [raw]
Subject: patch ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch added to 2.6.25-stable tree


This is a note to let you know that we have just queued up the patch titled

Subject: ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

to the 2.6.25-stable tree. Its filename is

ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch

A git repo of this tree can be found at
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary


>From [email protected] Thu Oct 23 13:13:44 2008
From: Eric Sandeen <[email protected]>
Date: Wed, 22 Oct 2008 10:11:52 -0500
Subject: ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)
To: [email protected]
Cc: ext4 development <[email protected]>
Message-ID: <[email protected]>

From: Eric Sandeen <[email protected]>

This is a trivial backport of the following upstream commits:

- bd39597cbd42a784105a04010100e27267481c67 (ext2)
- cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
- 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)

This addresses CVE-2008-3528

ext[234]: Avoid printk floods in the face of directory corruption

Note: some people thinks this represents a security bug, since it
might make the system go away while it is printing a large number of
console messages, especially if a serial console is involved. Hence,
it has been assigned CVE-2008-3528, but it requires that the attacker
either has physical access to your machine to insert a USB disk with a
corrupted filesystem image (at which point why not just hit the power
button), or is otherwise able to convince the system administrator to
mount an arbitrary filesystem image (at which point why not just
include a setuid shell or world-writable hard disk device file or some
such). Me, I think they're just being silly. --tytso

Signed-off-by: Eric Sandeen <[email protected]>
Signed-off-by: "Theodore Ts'o" <[email protected]>
Cc: [email protected]
Cc: Eugene Teo <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
fs/ext2/dir.c | 60 +++++++++++++++++++++++++++++++++-------------------------
fs/ext3/dir.c | 10 ++++++---
fs/ext4/dir.c | 11 +++++++---
3 files changed, 50 insertions(+), 31 deletions(-)

--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -103,7 +103,7 @@ static int ext2_commit_chunk(struct page
return err;
}

-static void ext2_check_page(struct page *page)
+static void ext2_check_page(struct page *page, int quiet)
{
struct inode *dir = page->mapping->host;
struct super_block *sb = dir->i_sb;
@@ -146,10 +146,10 @@ out:
/* Too bad, we had an error */

Ebadsize:
- ext2_error(sb, "ext2_check_page",
- "size of directory #%lu is not a multiple of chunk size",
- dir->i_ino
- );
+ if (!quiet)
+ ext2_error(sb, __func__,
+ "size of directory #%lu is not a multiple "
+ "of chunk size", dir->i_ino);
goto fail;
Eshort:
error = "rec_len is smaller than minimal";
@@ -166,32 +166,36 @@ Espan:
Einumber:
error = "inode out of bounds";
bad_entry:
- ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode),
- rec_len, p->name_len);
+ if (!quiet)
+ ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode),
+ rec_len, p->name_len);
goto fail;
Eend:
- p = (ext2_dirent *)(kaddr + offs);
- ext2_error (sb, "ext2_check_page",
- "entry in directory #%lu spans the page boundary"
- "offset=%lu, inode=%lu",
- dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode));
+ if (!quiet) {
+ p = (ext2_dirent *)(kaddr + offs);
+ ext2_error(sb, "ext2_check_page",
+ "entry in directory #%lu spans the page boundary"
+ "offset=%lu, inode=%lu",
+ dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode));
+ }
fail:
SetPageChecked(page);
SetPageError(page);
}

-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+static struct page * ext2_get_page(struct inode *dir, unsigned long n,
+ int quiet)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
kmap(page);
if (!PageChecked(page))
- ext2_check_page(page);
+ ext2_check_page(page, quiet);
if (PageError(page))
goto fail;
}
@@ -292,7 +296,7 @@ ext2_readdir (struct file * filp, void *
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
ext2_dirent *de;
- struct page *page = ext2_get_page(inode, n);
+ struct page *page = ext2_get_page(inode, n, 0);

if (IS_ERR(page)) {
ext2_error(sb, __FUNCTION__,
@@ -361,6 +365,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
struct page *page = NULL;
struct ext2_inode_info *ei = EXT2_I(dir);
ext2_dirent * de;
+ int dir_has_error = 0;

if (npages == 0)
goto out;
@@ -374,7 +379,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
n = start;
do {
char *kaddr;
- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, dir_has_error);
if (!IS_ERR(page)) {
kaddr = page_address(page);
de = (ext2_dirent *) kaddr;
@@ -391,7 +396,9 @@ struct ext2_dir_entry_2 * ext2_find_entr
de = ext2_next_entry(de);
}
ext2_put_page(page);
- }
+ } else
+ dir_has_error = 1;
+
if (++n >= npages)
n = 0;
/* next page is past the blocks we've got */
@@ -414,7 +421,7 @@ found:

struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
{
- struct page *page = ext2_get_page(dir, 0);
+ struct page *page = ext2_get_page(dir, 0, 0);
ext2_dirent *de = NULL;

if (!IS_ERR(page)) {
@@ -487,7 +494,7 @@ int ext2_add_link (struct dentry *dentry
for (n = 0; n <= npages; n++) {
char *dir_end;

- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, 0);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
@@ -655,14 +662,17 @@ int ext2_empty_dir (struct inode * inode
{
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
+ int dir_has_error = 0;

for (i = 0; i < npages; i++) {
char *kaddr;
ext2_dirent * de;
- page = ext2_get_page(inode, i);
+ page = ext2_get_page(inode, i, dir_has_error);

- if (IS_ERR(page))
+ if (IS_ERR(page)) {
+ dir_has_error = 1;
continue;
+ }

kaddr = page_address(page);
de = (ext2_dirent *)kaddr;
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -102,6 +102,7 @@ static int ext3_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -148,9 +149,12 @@ static int ext3_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext3_error (sb, "ext3_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext3_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %lld",
+ inode->i_ino, filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -102,6 +102,7 @@ static int ext4_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -147,9 +148,13 @@ static int ext4_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext4_error (sb, "ext4_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext4_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %Lu",
+ inode->i_ino,
+ (unsigned long long) filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;


Patches currently in stable-queue which might be from [email protected] are

queue-2.6.25/ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch

2008-10-23 21:16:05

by Greg KH

[permalink] [raw]
Subject: patch ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch added to 2.6.26-stable tree


This is a note to let you know that we have just queued up the patch titled

Subject: ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)

to the 2.6.26-stable tree. Its filename is

ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch

A git repo of this tree can be found at
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary


>From [email protected] Thu Oct 23 13:13:44 2008
From: Eric Sandeen <[email protected]>
Date: Wed, 22 Oct 2008 10:11:52 -0500
Subject: ext[234]: Avoid printk floods in the face of directory corruption (CVE-2008-3528)
To: [email protected]
Cc: ext4 development <[email protected]>
Message-ID: <[email protected]>

From: Eric Sandeen <[email protected]>

This is a trivial backport of the following upstream commits:

- bd39597cbd42a784105a04010100e27267481c67 (ext2)
- cdbf6dba28e8e6268c8420857696309470009fd9 (ext3)
- 9d9f177572d9e4eba0f2e18523b44f90dd51fe74 (ext4)

This addresses CVE-2008-3528

ext[234]: Avoid printk floods in the face of directory corruption

Note: some people thinks this represents a security bug, since it
might make the system go away while it is printing a large number of
console messages, especially if a serial console is involved. Hence,
it has been assigned CVE-2008-3528, but it requires that the attacker
either has physical access to your machine to insert a USB disk with a
corrupted filesystem image (at which point why not just hit the power
button), or is otherwise able to convince the system administrator to
mount an arbitrary filesystem image (at which point why not just
include a setuid shell or world-writable hard disk device file or some
such). Me, I think they're just being silly. --tytso

Signed-off-by: Eric Sandeen <[email protected]>
Signed-off-by: "Theodore Ts'o" <[email protected]>
Cc: [email protected]
Cc: Eugene Teo <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
fs/ext2/dir.c | 60 +++++++++++++++++++++++++++++++++-------------------------
fs/ext3/dir.c | 10 ++++++---
fs/ext4/dir.c | 11 +++++++---
3 files changed, 50 insertions(+), 31 deletions(-)

--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -103,7 +103,7 @@ static int ext2_commit_chunk(struct page
return err;
}

-static void ext2_check_page(struct page *page)
+static void ext2_check_page(struct page *page, int quiet)
{
struct inode *dir = page->mapping->host;
struct super_block *sb = dir->i_sb;
@@ -146,10 +146,10 @@ out:
/* Too bad, we had an error */

Ebadsize:
- ext2_error(sb, "ext2_check_page",
- "size of directory #%lu is not a multiple of chunk size",
- dir->i_ino
- );
+ if (!quiet)
+ ext2_error(sb, __func__,
+ "size of directory #%lu is not a multiple "
+ "of chunk size", dir->i_ino);
goto fail;
Eshort:
error = "rec_len is smaller than minimal";
@@ -166,32 +166,36 @@ Espan:
Einumber:
error = "inode out of bounds";
bad_entry:
- ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode),
- rec_len, p->name_len);
+ if (!quiet)
+ ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode),
+ rec_len, p->name_len);
goto fail;
Eend:
- p = (ext2_dirent *)(kaddr + offs);
- ext2_error (sb, "ext2_check_page",
- "entry in directory #%lu spans the page boundary"
- "offset=%lu, inode=%lu",
- dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode));
+ if (!quiet) {
+ p = (ext2_dirent *)(kaddr + offs);
+ ext2_error(sb, "ext2_check_page",
+ "entry in directory #%lu spans the page boundary"
+ "offset=%lu, inode=%lu",
+ dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode));
+ }
fail:
SetPageChecked(page);
SetPageError(page);
}

-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+static struct page * ext2_get_page(struct inode *dir, unsigned long n,
+ int quiet)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
kmap(page);
if (!PageChecked(page))
- ext2_check_page(page);
+ ext2_check_page(page, quiet);
if (PageError(page))
goto fail;
}
@@ -292,7 +296,7 @@ ext2_readdir (struct file * filp, void *
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
ext2_dirent *de;
- struct page *page = ext2_get_page(inode, n);
+ struct page *page = ext2_get_page(inode, n, 0);

if (IS_ERR(page)) {
ext2_error(sb, __func__,
@@ -361,6 +365,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
struct page *page = NULL;
struct ext2_inode_info *ei = EXT2_I(dir);
ext2_dirent * de;
+ int dir_has_error = 0;

if (npages == 0)
goto out;
@@ -374,7 +379,7 @@ struct ext2_dir_entry_2 * ext2_find_entr
n = start;
do {
char *kaddr;
- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, dir_has_error);
if (!IS_ERR(page)) {
kaddr = page_address(page);
de = (ext2_dirent *) kaddr;
@@ -391,7 +396,9 @@ struct ext2_dir_entry_2 * ext2_find_entr
de = ext2_next_entry(de);
}
ext2_put_page(page);
- }
+ } else
+ dir_has_error = 1;
+
if (++n >= npages)
n = 0;
/* next page is past the blocks we've got */
@@ -414,7 +421,7 @@ found:

struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
{
- struct page *page = ext2_get_page(dir, 0);
+ struct page *page = ext2_get_page(dir, 0, 0);
ext2_dirent *de = NULL;

if (!IS_ERR(page)) {
@@ -487,7 +494,7 @@ int ext2_add_link (struct dentry *dentry
for (n = 0; n <= npages; n++) {
char *dir_end;

- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, 0);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
@@ -655,14 +662,17 @@ int ext2_empty_dir (struct inode * inode
{
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
+ int dir_has_error = 0;

for (i = 0; i < npages; i++) {
char *kaddr;
ext2_dirent * de;
- page = ext2_get_page(inode, i);
+ page = ext2_get_page(inode, i, dir_has_error);

- if (IS_ERR(page))
+ if (IS_ERR(page)) {
+ dir_has_error = 1;
continue;
+ }

kaddr = page_address(page);
de = (ext2_dirent *)kaddr;
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -102,6 +102,7 @@ static int ext3_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -148,9 +149,12 @@ static int ext3_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext3_error (sb, "ext3_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext3_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %lld",
+ inode->i_ino, filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -102,6 +102,7 @@ static int ext4_readdir(struct file * fi
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
+ int dir_has_error = 0;

sb = inode->i_sb;

@@ -147,9 +148,13 @@ static int ext4_readdir(struct file * fi
* of recovering data when there's a bad sector
*/
if (!bh) {
- ext4_error (sb, "ext4_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
+ if (!dir_has_error) {
+ ext4_error(sb, __func__, "directory #%lu "
+ "contains a hole at offset %Lu",
+ inode->i_ino,
+ (unsigned long long) filp->f_pos);
+ dir_has_error = 1;
+ }
/* corrupt size? Maybe no more blocks to read */
if (filp->f_pos > inode->i_blocks << 9)
break;


Patches currently in stable-queue which might be from [email protected] are

queue-2.6.26/ext-avoid-printk-floods-in-the-face-of-directory-corruption.patch