Whamcloud - gitweb
e2fsck: check ea-in-inode regions for overlap
authorDarrick J. Wong <darrick.wong@oracle.com>
Sun, 10 Aug 2014 22:34:43 +0000 (18:34 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 10 Aug 2014 22:34:43 +0000 (18:34 -0400)
Ensure that the various blobs in the in-inode EA region do not overlap.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass1.c
e2fsck/problem.c
e2fsck/problem.h
tests/f_inode_ea_collision/expect.1 [new file with mode: 0644]
tests/f_inode_ea_collision/expect.2 [new file with mode: 0644]
tests/f_inode_ea_collision/image.gz [new file with mode: 0644]
tests/f_inode_ea_collision/name [new file with mode: 0644]

index 6c79eed..3fbf00a 100644 (file)
@@ -286,15 +286,17 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
        struct ext2_super_block *sb = ctx->fs->super;
        struct ext2_inode_large *inode;
        struct ext2_ext_attr_entry *entry;
-       char *start;
+       char *start, *header;
        unsigned int storage_size, remain;
        problem_t problem = 0;
+       region_t region = 0;
 
        inode = (struct ext2_inode_large *) pctx->inode;
        storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
                inode->i_extra_isize;
-       start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
-               inode->i_extra_isize + sizeof(__u32);
+       header = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+                inode->i_extra_isize;
+       start = header + sizeof(__u32);
        entry = (struct ext2_ext_attr_entry *) start;
 
        /* scan all entry's headers first */
@@ -302,10 +304,28 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
        /* take finish entry 0UL into account */
        remain = storage_size - sizeof(__u32);
 
+       region = region_create(0, storage_size);
+       if (!region) {
+               fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx);
+               problem = 0;
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
+       }
+       if (region_allocate(region, 0, sizeof(__u32))) {
+               problem = PR_1_INODE_EA_ALLOC_COLLISION;
+               goto fix;
+       }
+
        while (remain >= sizeof(struct ext2_ext_attr_entry) &&
               !EXT2_EXT_IS_LAST_ENTRY(entry)) {
                __u32 hash;
 
+               if (region_allocate(region, (char *)entry - (char *)header,
+                                   EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
+                       problem = PR_1_INODE_EA_ALLOC_COLLISION;
+                       goto fix;
+               }
+
                /* header eats this space */
                remain -= sizeof(struct ext2_ext_attr_entry);
 
@@ -333,6 +353,13 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
                        goto fix;
                }
 
+               if (entry->e_value_size &&
+                   region_allocate(region, sizeof(__u32) + entry->e_value_offs,
+                                   EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
+                       problem = PR_1_INODE_EA_ALLOC_COLLISION;
+                       goto fix;
+               }
+
                hash = ext2fs_ext_attr_hash_entry(entry,
                                                  start + entry->e_value_offs);
 
@@ -347,7 +374,15 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 
                entry = EXT2_EXT_ATTR_NEXT(entry);
        }
+
+       if (region_allocate(region, (char *)entry - (char *)header,
+                           sizeof(__u32))) {
+               problem = PR_1_INODE_EA_ALLOC_COLLISION;
+               goto fix;
+       }
 fix:
+       if (region)
+               region_free(region);
        /*
         * it seems like a corruption. it's very unlikely we could repair
         * EA(s) in automatic fashion -bzzz
@@ -356,7 +391,7 @@ fix:
                return;
 
        /* simply remove all possible EA(s) */
-       *((__u32 *)start) = 0UL;
+       *((__u32 *)header) = 0UL;
        e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
                                EXT2_INODE_SIZE(sb), "pass1");
 }
index 2d29c35..b982a27 100644 (file)
@@ -977,6 +977,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i passes checks, but checksum does not match @i.  "),
          PROMPT_FIX, PR_PREEN_OK },
 
+       /* Inode extended attribute is corrupt (allocation collision) */
+       { PR_1_INODE_EA_ALLOC_COLLISION,
+         N_("@i %i @a is corrupt (allocation collision).  "),
+         PROMPT_CLEAR, 0},
+
        /*
         * Inode extent block passes checks, but checksum does not match
         * extent
index 89146ec..f051c11 100644 (file)
@@ -577,6 +577,9 @@ struct problem_context {
 /* inode passes checks, but checksum does not match inode */
 #define PR_1_INODE_ONLY_CSUM_INVALID   0x010068
 
+/* Inode EA allocation collision */
+#define PR_1_INODE_EA_ALLOC_COLLISION  0x010069
+
 /* extent block passes checks, but checksum does not match extent block */
 #define PR_1_EXTENT_ONLY_CSUM_INVALID  0x01006A
 
diff --git a/tests/f_inode_ea_collision/expect.1 b/tests/f_inode_ea_collision/expect.1
new file mode 100644 (file)
index 0000000..a67a5f1
--- /dev/null
@@ -0,0 +1,15 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 extended attribute is corrupt (allocation collision).  Clear? yes
+
+Inode 13 extended attribute is corrupt (allocation collision).  Clear? yes
+
+Inode 14 extended attribute is corrupt (allocation collision).  Clear? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_inode_ea_collision/expect.2 b/tests/f_inode_ea_collision/expect.2
new file mode 100644 (file)
index 0000000..5a7ca86
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_inode_ea_collision/image.gz b/tests/f_inode_ea_collision/image.gz
new file mode 100644 (file)
index 0000000..5217f65
Binary files /dev/null and b/tests/f_inode_ea_collision/image.gz differ
diff --git a/tests/f_inode_ea_collision/name b/tests/f_inode_ea_collision/name
new file mode 100644 (file)
index 0000000..b64119e
--- /dev/null
@@ -0,0 +1 @@
+collisions in the inode ea area