From 55fd07ed0a5f4ed3dcc770526ee1ad3be967ac98 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 19 Jul 2001 16:31:25 -0400 Subject: [PATCH] This patch completes the initial extended attribute/ACL support for e2fsck. We now check the entire EA block to make sure that the all of the EA entries look sane. --- e2fsck/ChangeLog | 13 ++++ e2fsck/Makefile.in | 23 +++++- e2fsck/e2fsck.h | 8 +++ e2fsck/pass1.c | 54 ++++++++++++-- e2fsck/problem.c | 25 +++++++ e2fsck/problem.h | 15 ++++ e2fsck/region.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 334 insertions(+), 8 deletions(-) create mode 100644 e2fsck/region.c diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index 3432de9..a8d0da7 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,16 @@ +2001-07-19 Theodore Tso + + * 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 * journal.c (e2fsck_run_ext3_journal): Only call ext3_flush() if diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in index 2fde4b0..5e76e0d 100644 --- a/e2fsck/Makefile.in +++ b/e2fsck/Makefile.in @@ -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 diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 26f63cf..a5c58ad 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -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); diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 11aaaec..ab8dcfe 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -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) diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 4e13c53..2ded448 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -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 */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index aa2b706..be35fc9 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -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 index 0000000..9ccb684 --- /dev/null +++ b/e2fsck/region.c @@ -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 +#endif +#include + +#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 + +#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 */ -- 1.8.3.1