View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000188 | file | General | public | 2020-08-26 08:37 | 2020-09-05 14:28 |
Reporter | neal | Assigned To | christos | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Fixed in Version | 5.40 | ||||
Summary | 0000188: nested use of name is unexpected | ||||
Description | file doesn't handle non-top level "name" directives well. | ||||
Steps To Reproduce | Consider the following magic file (also attached): 0 byte x 1 >0 name foo >>0 byte x in foo >0 byte x 2 >0 use foo If this successfully parses, then I'd expect the 'use foo' to succeed. Instead, it executes from top to bottom *including the body of foo*, and then fails at the 'use foo' line. See the trace below. I can understand not wanting the complexity that non-top level named continuations would introduce. But, in that case, I think the parse should reject files that have named continuations that are not at the top level. | ||||
Additional Information | $ file -d -m /tmp/nested-name.magic /tmp/byte.bin unknown, 0: Warning: using regular magic file `/tmp/nest-name.magic' 1: binary [try zmagic 0] [try tar 0] [try json 0] [try cdf 0] [try elf 0] bb=[0x7f227cca8010,256], 0 [b=0x7f227cca8010,256], [o=0, c=0] mget(type=1, flag=0x20, offset=0, o=0, nbytes=256, il=0, nc=0) mget/96 @0: \000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 1: > 0 byte&,x,"1"] 0 == *any* = 1 bb=[0x7f227cca8010,256], 0 [b=0x7f227cca8010,256], [o=0, c=1] mget(type=45, flag=0, offset=0, o=0, nbytes=256, il=0, nc=0) mget/96 @0: \000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 2: >> 0 name,='foo',""] bb=[0x7f227cca8010,256], 0 [b=0x7f227cca8010,256], [o=0, c=2] mget(type=1, flag=0, offset=0, o=0, nbytes=256, il=0, nc=0) mget/96 @0: \000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 3: >>> 0 byte&,x,"in foo"] 0 == *any* = 1 bb=[0x7f227cca8010,256], 0 [b=0x7f227cca8010,256], [o=0, c=1] mget(type=1, flag=0, offset=0, o=0, nbytes=256, il=0, nc=0) mget/96 @0: \000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 4: >> 0 byte&,x,"2"] 0 == *any* = 1 bb=[0x7f227cca8010,256], 0 [b=0x7f227cca8010,256], [o=0, c=1] mget(type=46, flag=0, offset=0, o=0, nbytes=256, il=0, nc=0) mget/96 @0: \000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 4: >> 0 use,='foo',""] [try softmagic -1] /tmp/byte.bin: ERROR: 1 in foo 2 cannot find entry `foo' | ||||
Tags | No tags attached. | ||||
|
|
|
This fixes the issue for me. I've tried to make the changes as non-invasive as possible. 0001-Fix-use.patch (10,365 bytes)
From a92c756ee150bf2e47871fedecfb8486f355920f Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" <neal@gnu.org> Date: Wed, 26 Aug 2020 14:02:09 +0200 Subject: [PATCH] Fix 'use'. - When 'use' is used, it calls 'match' with the same magic set (ms). - 'match' starts counting the continuation levels at 0. - When the 'use' call returns, 'ms->c' has been clobbered. - Change 'ms->c' to a stack, and push a fresh 'struct cont' before calling 'match' or 'parse'. Pop those when the functions return. - Example: 10 byte x >&0 byte x 1:%d >&0 use foo >&0 byte x 2:%d 20 name foo >&30 byte x 3:%d That should print: $ src/file -m /tmp/cont_level.magic /tmp/byte.bin /tmp/byte.bin: 1:11 3:41 2:11 Without this patch, it incorrectly prints: $ file -m /tmp/cont_level.magic /tmp/byte.bin /tmp/byte.bin: 1:11 3:41 2:0 byte.bin was generated as follows: $ for i in $(seq 0 255); do echo -en '\x'$(printf "%x" $i); done > /tmp/byte.bin - See issue #188. https://bugs.astron.com/view.php?id=188 --- src/apprentice.c | 24 ++++++++++++++---------- src/der.c | 2 +- src/file.h | 6 ++++-- src/funcs.c | 33 ++++++++++++++++++++++++--------- src/softmagic.c | 37 +++++++++++++++++++++++-------------- 5 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/apprentice.c b/src/apprentice.c index 1437bcc1..64df467d 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -504,7 +504,9 @@ file_ms_free(struct magic_set *ms) mlist_free(ms->mlist[i]); free(ms->o.pbuf); free(ms->o.buf); - free(ms->c.li); + while (ms->c) { + file_continuation_level_pop(ms); + } free(ms); } @@ -512,7 +514,7 @@ protected struct magic_set * file_ms_alloc(int flags) { struct magic_set *ms; - size_t i, len; + size_t i; if ((ms = CAST(struct magic_set *, calloc(CAST(size_t, 1u), sizeof(struct magic_set)))) == NULL) @@ -525,10 +527,7 @@ file_ms_alloc(int flags) ms->o.buf = ms->o.pbuf = NULL; ms->o.blen = 0; - len = (ms->c.len = 10) * sizeof(*ms->c.li); - - if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) - goto free; + ms->c = NULL; ms->event_flags = 0; ms->error = -1; @@ -1183,6 +1182,7 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, char *line = NULL; ssize_t len; struct magic_entry me; + int rt; FILE *f = fopen(ms->file = fn, "r"); if (f == NULL) { @@ -1241,7 +1241,11 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, /*FALLTHROUGH*/ default: again: - switch (parse(ms, &me, line, lineno, action)) { + if (file_check_mem(ms, 0, 1) == -1) + return; + rt = parse(ms, &me, line, lineno, action); + file_continuation_level_pop(ms); + switch (rt) { case 0: continue; case 1: @@ -1676,7 +1680,7 @@ private int check_cond(struct magic_set *ms, int cond, uint32_t cont_level) { int last_cond; - last_cond = ms->c.li[cont_level].last_cond; + last_cond = ms->c->li[cont_level].last_cond; switch (cond) { case COND_IF: @@ -1711,7 +1715,7 @@ check_cond(struct magic_set *ms, int cond, uint32_t cont_level) break; } - ms->c.li[cont_level].last_cond = last_cond; + ms->c->li[cont_level].last_cond = last_cond; return 0; } #endif /* ENABLE_CONDITIONALS */ @@ -1884,7 +1888,7 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, } #ifdef ENABLE_CONDITIONALS if (cont_level == 0 || cont_level > last_cont_level) - if (file_check_mem(ms, cont_level) == -1) + if (file_check_mem(ms, cont_level, 0) == -1) return -1; last_cont_level = cont_level; #endif diff --git a/src/der.c b/src/der.c index 4bee9f16..84df577b 100644 --- a/src/der.c +++ b/src/der.c @@ -290,7 +290,7 @@ der_offs(struct magic_set *ms, struct magic *m, size_t nbytes) if (m->cont_level != 0) { if (offs + tlen > nbytes) return -1; - ms->c.li[m->cont_level - 1].off = CAST(int, offs + tlen); + ms->c->li[m->cont_level - 1].off = CAST(int, offs + tlen); DPRINTF(("cont_level[%u] = %u\n", m->cont_level - 1, ms->c.li[m->cont_level - 1].off)); } diff --git a/src/file.h b/src/file.h index 8fb9e060..7298b424 100644 --- a/src/file.h +++ b/src/file.h @@ -417,7 +417,8 @@ struct magic_set { struct cont { size_t len; struct level_info *li; - } c; + struct cont *next; + } *c; struct out { char *buf; /* Accumulation buffer */ size_t blen; /* Length of buffer */ @@ -526,7 +527,8 @@ protected void file_showstr(FILE *, const char *, size_t); protected size_t file_mbswidth(const char *); protected const char *file_getbuffer(struct magic_set *); protected ssize_t sread(int, void *, size_t, int); -protected int file_check_mem(struct magic_set *, unsigned int); +protected void file_continuation_level_pop(struct magic_set *); +protected int file_check_mem(struct magic_set *, unsigned int, int); protected int file_looks_utf8(const unsigned char *, size_t, file_unichar_t *, size_t *); protected size_t file_pstring_length_size(struct magic_set *, diff --git a/src/funcs.c b/src/funcs.c index ecbfa28c..55e96435 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -576,28 +576,43 @@ file_getbuffer(struct magic_set *ms) } protected int -file_check_mem(struct magic_set *ms, unsigned int level) +file_check_mem(struct magic_set *ms, unsigned int level, + int push_continuation_stack) { size_t len; - if (level >= ms->c.len) { - len = (ms->c.len = 20 + level) * sizeof(*ms->c.li); - ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? + if (push_continuation_stack) { + struct cont *c = calloc(1, sizeof *c); + if (c == NULL) { + file_oomem(ms, sizeof *c); + } + c->next = ms->c; + ms->c = c; + } + if (level >= ms->c->len) { + len = (ms->c->len = 20 + level) * sizeof(*ms->c->li); + ms->c->li = CAST(struct level_info *, (ms->c->li == NULL) ? malloc(len) : - realloc(ms->c.li, len)); - if (ms->c.li == NULL) { + realloc(ms->c->li, len)); + if (ms->c->li == NULL) { file_oomem(ms, len); return -1; } } - ms->c.li[level].got_match = 0; + ms->c->li[level].got_match = 0; #ifdef ENABLE_CONDITIONALS - ms->c.li[level].last_match = 0; - ms->c.li[level].last_cond = COND_NONE; + ms->c->li[level].last_match = 0; + ms->c->li[level].last_cond = COND_NONE; #endif /* ENABLE_CONDITIONALS */ return 0; } +protected void +file_continuation_level_pop(struct magic_set *ms) +{ + ms->c = ms->c->next; +} + protected size_t file_printedlen(const struct magic_set *ms) { diff --git a/src/softmagic.c b/src/softmagic.c index 95061e56..c27209ad 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -130,12 +130,18 @@ file_softmagic(struct magic_set *ms, const struct buffer *b, indir_count = ⁣ } + if (file_check_mem(ms, 0, 1) == -1) + return -1; + for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode, text, 0, indir_count, name_count, - &printed_something, &need_separator, NULL, NULL)) != 0) + &printed_something, &need_separator, NULL, NULL)) != 0) { + file_continuation_level_pop(ms); return rv; + } + file_continuation_level_pop(ms); return 0; } @@ -214,7 +220,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (found_match == NULL) found_match = &found_matchv; - if (file_check_mem(ms, cont_level) == -1) + if (file_check_mem(ms, cont_level, 0) == -1) return -1; for (magindex = 0; magindex < nmagic; magindex++) { @@ -302,7 +308,7 @@ flush: return -1; } - switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) { + switch (moffset(ms, m, &bb, &ms->c->li[cont_level].off)) { case -1: case 0: goto flush; @@ -311,7 +317,7 @@ flush: } /* and any continuations that match */ - if (file_check_mem(ms, ++cont_level) == -1) + if (file_check_mem(ms, ++cont_level, 0) == -1) return -1; while (magindex + 1 < nmagic && @@ -339,13 +345,13 @@ flush: return 0; } ms->offset += - ms->c.li[cont_level - 1].off; + ms->c->li[cont_level - 1].off; } #ifdef ENABLE_CONDITIONALS if (m->cond == COND_ELSE || m->cond == COND_ELIF) { - if (ms->c.li[cont_level].last_match == 1) + if (ms->c->li[cont_level].last_match == 1) continue; } #endif @@ -375,20 +381,20 @@ flush: return -1; case 0: #ifdef ENABLE_CONDITIONALS - ms->c.li[cont_level].last_match = 0; + ms->c->li[cont_level].last_match = 0; #endif break; default: #ifdef ENABLE_CONDITIONALS - ms->c.li[cont_level].last_match = 1; + ms->c->li[cont_level].last_match = 1; #endif if (m->type == FILE_CLEAR) - ms->c.li[cont_level].got_match = 0; - else if (ms->c.li[cont_level].got_match) { + ms->c->li[cont_level].got_match = 0; + else if (ms->c->li[cont_level].got_match) { if (m->type == FILE_DEFAULT) break; } else - ms->c.li[cont_level].got_match = 1; + ms->c->li[cont_level].got_match = 1; if (*m->desc) *found_match = 1; @@ -432,7 +438,7 @@ flush: } switch (moffset(ms, m, &bb, - &ms->c.li[cont_level].off)) { + &ms->c->li[cont_level].off)) { case -1: case 0: flush = 1; @@ -447,7 +453,7 @@ flush: * at a higher level, * process them. */ - if (file_check_mem(ms, ++cont_level) == -1) + if (file_check_mem(ms, ++cont_level, 0) == -1) return -1; break; } @@ -1743,7 +1749,7 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, "indirect *zero* cont_level\n"); return 0; } - offset += ms->c.li[cont_level - 1].off; + offset += ms->c->li[cont_level - 1].off; if (offset == 0) { if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, @@ -1880,9 +1886,12 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b, oneed_separator = *need_separator; if (m->flag & NOSPACE) *need_separator = 0; + if (file_check_mem(ms, 0, 1) == -1) + return -1; rv = match(ms, ml.magic, ml.nmagic, b, offset + o, mode, text, flip, indir_count, name_count, printed_something, need_separator, returnval, found_match); + file_continuation_level_pop(ms); (*name_count)--; if (rv != 1) *need_separator = oneed_separator; -- 2.20.1 |
|
Fixed, thanks! mag2, 2: Warning: `name foo' entries can only be declared at top level |
Date Modified | Username | Field | Change |
---|---|---|---|
2020-08-26 08:37 | neal | New Issue | |
2020-08-26 08:37 | neal | File Added: nested-name.magic | |
2020-08-26 12:12 | neal | File Added: 0001-Fix-use.patch | |
2020-08-26 12:12 | neal | Note Added: 0003464 | |
2020-09-05 14:27 | christos | Assigned To | => christos |
2020-09-05 14:27 | christos | Status | new => assigned |
2020-09-05 14:28 | christos | Status | assigned => resolved |
2020-09-05 14:28 | christos | Resolution | open => fixed |
2020-09-05 14:28 | christos | Fixed in Version | => 5.40 |
2020-09-05 14:28 | christos | Note Added: 0003474 |