Whamcloud - gitweb
This patch completes the initial extended attribute/ACL support for
authorTheodore Ts'o <tytso@mit.edu>
Thu, 19 Jul 2001 20:31:25 +0000 (16:31 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 19 Jul 2001 20:31:25 +0000 (16:31 -0400)
e2fsck.  We now check the entire EA block to make sure that the all
of the EA entries look sane.

e2fsck/ChangeLog
e2fsck/Makefile.in
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/region.c [new file with mode: 0644]

index 3432de9..a8d0da7 100644 (file)
@@ -1,3 +1,16 @@
+2001-07-19  Theodore Tso  <tytso@valinux.com>
+
+       * pass1.c (check_ext_attr): The entire EA block is now checked to
+               make sure that parts of the EA block aren't being used for
+               multiple purposes.
+
+       * Makefile.in e2fsck.h, region.c: New file which is used to detect
+               collisions in extended attribute block.
+
+       * problem.h, problem.c (PR_1_EA_MULTI_BLOCK, PR_1_EA_ALLOC_REGION,
+               PR_1_EA_ALLOC_COLLISION, PR_1_EA_BAD_NAME,
+               PR_1_EA_BAD_VALUE): Add new problem codes.
+
 2001-07-10  Theodore Tso  <tytso@valinux.com>
 
        * journal.c (e2fsck_run_ext3_journal): Only call ext3_flush() if
index 2fde4b0..5e76e0d 100644 (file)
@@ -56,7 +56,8 @@ PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) \
 
 OBJS= unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o pass3.o pass4.o \
        pass5.o journal.o swapfs.o badblocks.o util.o dirinfo.o ehandler.o \
-       problem.o message.o recovery.o revoke.o ea_refcount.o $(MTRACE_OBJ)
+       problem.o message.o recovery.o region.o revoke.o ea_refcount.o \
+       $(MTRACE_OBJ)
 
 PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
        profiled/pass1.o profiled/pass1b.o \
@@ -64,7 +65,7 @@ PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
        profiled/journal.o profiled/badblocks.o profiled/util.o \
        profiled/dirinfo.o profiled/ehandler.o profiled/message.o \
        profiled/problem.o profiled/swapfs.o profiled/recovery.o \
-       profiled/revoke.o profiled/ea_refcount.o
+       profiled/region.o profiled/revoke.o profiled/ea_refcount.o
 
 SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/super.c \
@@ -86,6 +87,7 @@ SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/message.c \
        $(srcdir)/swapfs.c \
        $(srcdir)/ea_refcount.c \
+       $(srcdir)/region.c \
        $(MTRACE_SRC)
 
 all:: profiled $(PROGS) e2fsck.static e2fsck.shared $(MANPAGES)
@@ -111,6 +113,10 @@ tst_refcount: ea_refcount.c
        $(CC) -o tst_refcount $(srcdir)/ea_refcount.c \
                $(ALL_CFLAGS) -DTEST_PROGRAM -lcom_err
 
+tst_region: region.c
+       $(CC) -o tst_region $(srcdir)/region.c \
+               $(ALL_CFLAGS) -DTEST_PROGRAM -lcom_err
+
 extend: extend.o
        $(LD) $(ALL_LDFLAGS) -o extend extend.o $(CHECKLIB)
 
@@ -181,7 +187,8 @@ pass1.o: $(srcdir)/pass1.c $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/bitops.h $(srcdir)/problem.h
+ $(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h \
+ $(srcdir)/problem.h
 pass1b.o: $(srcdir)/pass1b.c $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
@@ -266,3 +273,13 @@ swapfs.o: $(srcdir)/swapfs.c $(top_srcdir)/lib/et/com_err.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
  $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
+ea_refcount.o: $(srcdir)/ea_refcount.c $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h
+region.o: $(srcdir)/region.c $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h
index 26f63cf..a5c58ad 100644 (file)
@@ -250,6 +250,9 @@ struct e2fsck_struct {
        void *priv_data;
 };
 
+/* Used by the region allocation code */
+typedef __u32 region_addr_t;
+typedef struct region_struct *region_t;
 
 /*
  * Procedure declarations
@@ -314,6 +317,11 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, ext2_ino_t ino
 /* pass3.c */
 extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
 
+/* region.c */
+extern region_t region_create(region_addr_t min, region_addr_t max);
+extern void region_free(region_t region);
+extern int region_allocate(region_t region, region_addr_t start, int n);
+
 /* super.c */
 void check_super_block(e2fsck_t ctx);
 errcode_t e2fsck_get_device_size(e2fsck_t ctx);
index 11aaaec..ab8dcfe 100644 (file)
@@ -939,8 +939,11 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
        ext2_ino_t      ino = pctx->ino;
        struct ext2_inode *inode = pctx->inode;
        blk_t           blk;
+       char *          end;
        struct ext2_ext_attr_header *header;
+       struct ext2_ext_attr_entry *entry;
        int             count;
+       region_t        region;
        
        blk = inode->i_file_acl;
        if (blk == 0)
@@ -1001,7 +1004,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
                                pctx->num = 2;
                                fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
                                ctx->flags |= E2F_FLAG_ABORT;
-                               return 1;
+                               return 0;
                        }
                }
                ea_refcount_increment(ctx->refcount_extra, blk, 0);
@@ -1017,14 +1020,55 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
        if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
                goto clear_extattr;
        header = (struct ext2_ext_attr_header *) block_buf;
-
+       pctx->blk = inode->i_file_acl;
        if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
-               pctx->blk = inode->i_file_acl;
-               if (fix_problem, ctx, PR_1_BAD_EA_BLOCK, pctx)
+               if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
+                       goto clear_extattr;
+       }
+       if (header->h_blocks != 1) {
+               if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
+                       goto clear_extattr;
+       }
+
+       region = region_create(0, fs->blocksize);
+       if (!region) {
+               fix_problem(ctx, PR_1_EA_ALLOC_REGION, pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return 0;
+       }
+       if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
+               if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
                        goto clear_extattr;
        }
        
-       /* @@@ validate the contents of the EA block */
+       entry = (struct ext2_ext_attr_entry *)(header+1);
+       end = block_buf + fs->blocksize;
+       while ((char *)entry < end && *(__u32 *)entry) {
+               if (region_allocate(region, (char *)entry - (char *)header,
+                                  EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
+                       if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+                               goto clear_extattr;
+               }
+               if (entry->e_name_len == 0 || entry->e_name_index != 0) {
+                       if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
+                               goto clear_extattr;
+               }
+               if (entry->e_value_block != 0) {
+                       if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
+                               goto clear_extattr;
+               }
+               if (region_allocate(region, entry->e_value_offs,
+                                  EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
+                       if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+                               goto clear_extattr;
+               }
+               entry = EXT2_EXT_ATTR_NEXT(entry);
+       }
+       if (region_allocate(region, (char *)entry - (char *)header, 4)) {
+               if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+                       goto clear_extattr;
+       }
+       region_free(region);
 
        count = header->h_refcount - 1;
        if (count)
index 4e13c53..2ded448 100644 (file)
@@ -596,6 +596,31 @@ static const struct e2fsck_problem problem_table[] = {
        { PR_1_EXTATTR_WRITE,
          N_("Error writing @a @b %b (%m).  "),
          PROMPT_ABORT, 0 },
+
+       /* Multiple EA blocks not supported */
+       { PR_1_EA_MULTI_BLOCK,
+         N_("@a @b %b has h_blocks > 1.  "),
+         PROMPT_CLEAR, 0},       
+
+       /* Error allocating EA region allocation structure */
+       { PR_1_EA_ALLOC_REGION,
+         N_("Error allocating @a @b %b.  "),
+         PROMPT_ABORT, 0},
+       
+       /* Error EA allocation collision */
+       { PR_1_EA_ALLOC_COLLISION,
+         N_("@a @b %b is corrupt (allocation collision).  "),
+         PROMPT_ABORT, 0},
+       
+       /* Bad extended attribute name */
+       { PR_1_EA_BAD_NAME,
+         N_("@a @b %b is corrupt (invalid name).  "),
+         PROMPT_CLEAR, 0},       
+
+       /* Bad extended attribute value */
+       { PR_1_EA_BAD_VALUE,
+         N_("@a @b %b is corrupt (invalid value).  "),
+         PROMPT_CLEAR, 0},       
                  
        /* Pass 1b errors */
 
index aa2b706..be35fc9 100644 (file)
@@ -344,6 +344,21 @@ struct problem_context {
 
 /* Error writing Extended Attribute block while fixing refcount */ 
 #define PR_1_EXTATTR_WRITE             0x01003D
+
+/* Multiple EA blocks not supported */
+#define PR_1_EA_MULTI_BLOCK            0x01003E
+
+/* Error allocating EA region allocation structure */
+#define PR_1_EA_ALLOC_REGION           0x01003F
+       
+/* Error EA allocation collision */
+#define PR_1_EA_ALLOC_COLLISION                0x010040
+       
+/* Bad extended attribute name */
+#define PR_1_EA_BAD_NAME               0x010041
+
+/* Bad extended attribute value */
+#define PR_1_EA_BAD_VALUE              0x0100423
        
 /*
  * Pass 1b errors
diff --git a/e2fsck/region.c b/e2fsck/region.c
new file mode 100644 (file)
index 0000000..9ccb684
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * region.c --- code which manages allocations within a region.
+ * 
+ * Copyright (C) 2001 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+
+#include "e2fsck.h"
+
+struct region_el {
+       region_addr_t   start;
+       region_addr_t   end;
+       struct region_el *next;
+};
+
+struct region_struct {
+       region_addr_t   min;
+       region_addr_t   max;
+       struct region_el *allocated;
+};
+
+region_t region_create(region_addr_t min, region_addr_t max)
+{
+       region_t        region;
+
+       region = malloc(sizeof(struct region_struct));
+       if (!region)
+               return NULL;
+       memset(region, 0, sizeof(struct region_struct));
+       region->min = min;
+       region->max = max;
+       return region;
+}
+
+void region_free(region_t region)
+{
+       struct region_el        *r, *next;
+
+       for (r = region->allocated; r; r = next) {
+               next = r->next;
+               free(r);
+       }
+       memset(region, 0, sizeof(struct region_struct));
+       free(region);
+}
+
+int region_allocate(region_t region, region_addr_t start, int n)
+{
+       struct region_el        *r, *new_region, *prev, *next;
+       region_addr_t end;
+
+       end = start+n;
+       if ((start < region->min) || (end > region->max))
+               return -1;
+       if (n == 0)
+               return 1;
+
+       /*
+        * Search through the linked list.  If we find that it
+        * conflicts witih something that's already allocated, return
+        * 1; if we can find an existing region which we can grow, do
+        * so.  Otherwise, stop when we find the appropriate place
+        * insert a new region element into the linked list.
+        */
+       for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
+               if (((start >= r->start) && (start < r->end)) ||
+                   ((end > r->start) && (end <= r->end)) ||
+                   ((start <= r->start) && (end >= r->end)))
+                       return 1;
+               if (end == r->start) {
+                       r->start = start;
+                       return 0;
+               }
+               if (start == r->end) {
+                       if ((next = r->next)) {
+                               if (end > next->start)
+                                       return 1;
+                               if (end == next->start) {
+                                       r->end = next->end;
+                                       r->next = next->next;
+                                       free(next);
+                                       return 0;
+                               }
+                       }
+                       r->end = end;
+                       return 0;
+               }
+               if (start < r->start)
+                       break;
+       }
+       /*
+        * Insert a new region element structure into the linked list
+        */
+       new_region = malloc(sizeof(struct region_el));
+       if (!new_region)
+               return -1;
+       new_region->start = start;
+       new_region->end = start + n;
+       new_region->next = r;
+       if (prev)
+               prev->next = new_region;
+       else
+               region->allocated = new_region;
+       return 0;
+}
+
+#ifdef TEST_PROGRAM
+#include <stdio.h>
+
+#define BCODE_END      0
+#define BCODE_CREATE   1
+#define BCODE_FREE     2
+#define BCODE_ALLOCATE 3
+#define BCODE_PRINT    4
+
+int bcode_program[] = {
+       BCODE_CREATE, 1, 1001,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 10, 10,
+       BCODE_ALLOCATE, 30, 10,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 1, 15,
+       BCODE_ALLOCATE, 15, 8,
+       BCODE_ALLOCATE, 1, 20,
+       BCODE_ALLOCATE, 1, 8,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 40, 10,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 22, 5,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 27, 3,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 20, 2,
+       BCODE_PRINT,
+       BCODE_ALLOCATE, 49, 1,
+       BCODE_ALLOCATE, 50, 5,
+       BCODE_ALLOCATE, 9, 2,
+       BCODE_ALLOCATE, 9, 1,
+       BCODE_PRINT,
+       BCODE_FREE,
+       BCODE_END
+};
+
+void region_print(region_t region, FILE *f)
+{
+       struct region_el        *r;
+       int     i = 0;
+       
+       fprintf(f, "Printing region (min=%d. max=%d)\n\t", region->min,
+               region->max);
+       for (r = region->allocated; r; r = r->next) {
+               fprintf(f, "(%d, %d)  ", r->start, r->end);
+               if (++i >= 8)
+                       fprintf(f, "\n\t");
+       }
+       fprintf(f, "\n");
+}
+
+int main(int argc, char **argv)
+{
+       region_t        r;
+       int             pc = 0, ret;
+       region_addr_t   start, end, len;
+
+       
+       while (1) {
+               switch (bcode_program[pc++]) {
+               case BCODE_END:
+                       exit(0);
+               case BCODE_CREATE:
+                       start = bcode_program[pc++];
+                       end = bcode_program[pc++];
+                       printf("Creating region with args(%d, %d)\n",
+                              start, end);
+                       r = region_create(start, end);
+                       if (!r) {
+                               fprintf(stderr, "Couldn't create region.\n");
+                               exit(1);
+                       }
+                       break;
+               case BCODE_ALLOCATE:
+                       start = bcode_program[pc++];
+                       end = bcode_program[pc++];
+                       ret = region_allocate(r, start, end);
+                       printf("Region_allocate(%d, %d) returns %d\n",
+                              start, end, ret);
+                       break;
+               case BCODE_PRINT:
+                       region_print(r, stdout);
+                       break;
+               }
+       }
+}
+
+#endif /* TEST_PROGRAM */