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 |