diff options
author | Christos Zoulas <christos@zoulas.com> | 2016-07-20 11:27:08 +0000 |
---|---|---|
committer | Christos Zoulas <christos@zoulas.com> | 2016-07-20 11:27:08 +0000 |
commit | 558649d66b57e365a8d2ea429db73df72bd3f0a9 (patch) | |
tree | 86d7dd612ab0fa954d7ad8c63ac42812ffa0841c | |
parent | 7a880cbe4a493607cabd400f052989d557c522bc (diff) | |
download | file-git-558649d66b57e365a8d2ea429db73df72bd3f0a9.tar.gz |
Add support for signed indirect offsets.
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | doc/magic.man | 11 | ||||
-rw-r--r-- | src/apprentice.c | 10 | ||||
-rw-r--r-- | src/file.h | 4 | ||||
-rw-r--r-- | src/softmagic.c | 331 |
5 files changed, 88 insertions, 276 deletions
@@ -1,3 +1,11 @@ +2016-07-20 7:26 Christos Zoulas <christos@zoulas.com> + + * Add support for signed indirect offsets + +2016-07-18 7:41 Christos Zoulas <christos@zoulas.com> + + * cat /dev/null | file - should print empty (Christoph Biedl) + 2016-07-05 15:20 Christos Zoulas <christos@zoulas.com> * Bump string size from 64 to 96. diff --git a/doc/magic.man b/doc/magic.man index f3b63b46..831e1e4d 100644 --- a/doc/magic.man +++ b/doc/magic.man @@ -1,5 +1,5 @@ -.\" $File: magic.man,v 1.86 2015/09/08 13:48:44 christos Exp $ -.Dd January 1, 2015 +.\" $File: magic.man,v 1.87 2016/07/20 11:27:08 christos Exp $ +.Dd July 20, 2016 .Dt MAGIC __FSECTION__ .Os .\" install as magic.4 on USG, magic.5 on V7, Berkeley and Linux systems. @@ -535,13 +535,18 @@ the file. The value at that offset is read, and is used again as an offset in the file. Indirect offsets are of the form: -.Em (( x [.[bislBISL]][+\-][ y ]) . +.Em (( x [[.,][bislBISL]][+\-][ y ]) . The value of .Em x is used as an offset in the file. A byte, id3 length, short or long is read at that offset depending on the .Em [bislBISLm] type specifier. +The value is treated as signed if +.Dq , +is specified or unsigned if +.Dq . +is specified. The capitalized types interpret the number as a big endian value, whereas the small letter versions interpret the number as a little endian value; diff --git a/src/apprentice.c b/src/apprentice.c index 8793982e..cd8250b1 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.250 2016/07/05 19:20:19 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.251 2016/07/20 11:27:08 christos Exp $") #endif /* lint */ #include "magic.h" @@ -1881,10 +1881,13 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, if (m->flag & INDIR) { m->in_type = FILE_LONG; m->in_offset = 0; + m->in_op = 0; /* - * read [.lbs][+-]nnnnn) + * read [.,lbs][+-]nnnnn) */ - if (*l == '.') { + if (*l == '.' || *l == ',') { + if (*l == ',') + m->in_op |= FILE_OPSIGNED; l++; switch (*l) { case 'l': @@ -1936,7 +1939,6 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, l++; } - m->in_op = 0; if (*l == '~') { m->in_op |= FILE_OPINVERSE; l++; @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.179 2016/07/05 19:20:19 christos Exp $ + * @(#)$File: file.h,v 1.180 2016/07/20 11:27:08 christos Exp $ */ #ifndef __file_h__ @@ -275,7 +275,7 @@ struct magic { #define FILE_OPS_MASK 0x07 /* mask for above ops */ #define FILE_UNUSED_1 0x08 #define FILE_UNUSED_2 0x10 -#define FILE_UNUSED_3 0x20 +#define FILE_OPSIGNED 0x20 #define FILE_OPINVERSE 0x40 #define FILE_OPINDIRECT 0x80 diff --git a/src/softmagic.c b/src/softmagic.c index 9f8b0bb6..80b02461 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.235 2016/06/14 00:22:36 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.236 2016/07/20 11:27:08 christos Exp $") #endif /* lint */ #include "magic.h" @@ -63,7 +63,7 @@ private int cvt_16(union VALUETYPE *, const struct magic *); private int cvt_32(union VALUETYPE *, const struct magic *); private int cvt_64(union VALUETYPE *, const struct magic *); -#define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) +#define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o))) #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \ ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \ ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \ @@ -80,6 +80,7 @@ private int cvt_64(union VALUETYPE *, const struct magic *); ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2])) #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1])) #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0])) +#define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p)) /* * softmagic - lookup one file in parsed, in-memory copy of database @@ -1294,6 +1295,45 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, return 0; } +private uint32_t +do_ops(struct magic *m, intmax_t lhs, intmax_t off) +{ + intmax_t offset; + if (off) { + switch (m->in_op & FILE_OPS_MASK) { + case FILE_OPAND: + offset = lhs & off; + break; + case FILE_OPOR: + offset = lhs | off; + break; + case FILE_OPXOR: + offset = lhs ^ off; + break; + case FILE_OPADD: + offset = lhs + off; + break; + case FILE_OPMINUS: + offset = lhs - off; + break; + case FILE_OPMULTIPLY: + offset = lhs * off; + break; + case FILE_OPDIVIDE: + offset = lhs / off; + break; + case FILE_OPMODULO: + offset = lhs % off; + break; + } + } else + offset = lhs; + if (m->in_op & FILE_OPINVERSE) + offset = ~offset; + + return (uint32_t)offset; +} + private int mget(struct magic_set *ms, const unsigned char *s, struct magic *m, size_t nbytes, size_t o, unsigned int cont_level, int mode, int text, @@ -1301,7 +1341,7 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, int *printed_something, int *need_separator, int *returnval) { uint32_t offset = ms->offset; - uint32_t lhs; + intmax_t lhs; file_pushbuf_t *pb; int rv, oneed_separator, in_type; char *rbuf; @@ -1337,7 +1377,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, } if (m->flag & INDIR) { - int off = m->in_offset; + intmax_t off = m->in_offset; + const int sgn = m->in_op & FILE_OPSIGNED; if (m->in_op & FILE_OPINDIRECT) { const union VALUETYPE *q = CAST(const union VALUETYPE *, ((const void *)(s + offset + off))); @@ -1345,178 +1386,55 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return 0; switch (cvt_flip(m->in_type, flip)) { case FILE_BYTE: - off = q->b; + off = SEXT(sgn,8,q->b); break; case FILE_SHORT: - off = q->h; + off = SEXT(sgn,16,q->h); break; case FILE_BESHORT: - off = (short)BE16(q); + off = SEXT(sgn,16,BE16(q)); break; case FILE_LESHORT: - off = (short)LE16(q); + off = SEXT(sgn,16,LE16(q)); break; case FILE_LONG: - off = q->l; + off = SEXT(sgn,32,q->l); break; case FILE_BELONG: case FILE_BEID3: - off = (int32_t)BE32(q); + off = SEXT(sgn,32,BE32(q)); break; case FILE_LEID3: case FILE_LELONG: - off = (int32_t)LE32(q); + off = SEXT(sgn,32,LE32(q)); break; case FILE_MELONG: - off = (int32_t)ME32(q); + off = SEXT(sgn,32,ME32(q)); break; } if ((ms->flags & MAGIC_DEBUG) != 0) - fprintf(stderr, "indirect offs=%u\n", off); + fprintf(stderr, "indirect offs=%jd\n", off); } switch (in_type = cvt_flip(m->in_type, flip)) { case FILE_BYTE: if (OFFSET_OOB(nbytes, offset, 1)) return 0; - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = p->b & off; - break; - case FILE_OPOR: - offset = p->b | off; - break; - case FILE_OPXOR: - offset = p->b ^ off; - break; - case FILE_OPADD: - offset = p->b + off; - break; - case FILE_OPMINUS: - offset = p->b - off; - break; - case FILE_OPMULTIPLY: - offset = p->b * off; - break; - case FILE_OPDIVIDE: - offset = p->b / off; - break; - case FILE_OPMODULO: - offset = p->b % off; - break; - } - } else - offset = p->b; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + offset = do_ops(m, SEXT(sgn,8,p->b), off); break; case FILE_BESHORT: if (OFFSET_OOB(nbytes, offset, 2)) return 0; - lhs = (p->hs[0] << 8) | p->hs[1]; - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = lhs & off; - break; - case FILE_OPOR: - offset = lhs | off; - break; - case FILE_OPXOR: - offset = lhs ^ off; - break; - case FILE_OPADD: - offset = lhs + off; - break; - case FILE_OPMINUS: - offset = lhs - off; - break; - case FILE_OPMULTIPLY: - offset = lhs * off; - break; - case FILE_OPDIVIDE: - offset = lhs / off; - break; - case FILE_OPMODULO: - offset = lhs % off; - break; - } - } else - offset = lhs; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + offset = do_ops(m, SEXT(sgn,16,BE16(p)), off); break; case FILE_LESHORT: if (OFFSET_OOB(nbytes, offset, 2)) return 0; - lhs = (p->hs[1] << 8) | p->hs[0]; - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = lhs & off; - break; - case FILE_OPOR: - offset = lhs | off; - break; - case FILE_OPXOR: - offset = lhs ^ off; - break; - case FILE_OPADD: - offset = lhs + off; - break; - case FILE_OPMINUS: - offset = lhs - off; - break; - case FILE_OPMULTIPLY: - offset = lhs * off; - break; - case FILE_OPDIVIDE: - offset = lhs / off; - break; - case FILE_OPMODULO: - offset = lhs % off; - break; - } - } else - offset = lhs; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + offset = do_ops(m, SEXT(sgn,16,LE16(p)), off); break; case FILE_SHORT: if (OFFSET_OOB(nbytes, offset, 2)) return 0; - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = p->h & off; - break; - case FILE_OPOR: - offset = p->h | off; - break; - case FILE_OPXOR: - offset = p->h ^ off; - break; - case FILE_OPADD: - offset = p->h + off; - break; - case FILE_OPMINUS: - offset = p->h - off; - break; - case FILE_OPMULTIPLY: - offset = p->h * off; - break; - case FILE_OPDIVIDE: - offset = p->h / off; - break; - case FILE_OPMODULO: - offset = p->h % off; - break; - } - } - else - offset = p->h; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + offset = do_ops(m, SEXT(sgn,16,p->h), off); break; case FILE_BELONG: case FILE_BEID3: @@ -1524,38 +1442,8 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return 0; lhs = BE32(p); if (in_type == FILE_BEID3) - lhs = cvt_id3(ms, lhs); - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = lhs & off; - break; - case FILE_OPOR: - offset = lhs | off; - break; - case FILE_OPXOR: - offset = lhs ^ off; - break; - case FILE_OPADD: - offset = lhs + off; - break; - case FILE_OPMINUS: - offset = lhs - off; - break; - case FILE_OPMULTIPLY: - offset = lhs * off; - break; - case FILE_OPDIVIDE: - offset = lhs / off; - break; - case FILE_OPMODULO: - offset = lhs % off; - break; - } - } else - offset = lhs; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + lhs = cvt_id3(ms, (uint32_t)lhs); + offset = do_ops(m, SEXT(sgn,32,lhs), off); break; case FILE_LELONG: case FILE_LEID3: @@ -1563,109 +1451,18 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, return 0; lhs = LE32(p); if (in_type == FILE_LEID3) - lhs = cvt_id3(ms, lhs); - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = lhs & off; - break; - case FILE_OPOR: - offset = lhs | off; - break; - case FILE_OPXOR: - offset = lhs ^ off; - break; - case FILE_OPADD: - offset = lhs + off; - break; - case FILE_OPMINUS: - offset = lhs - off; - break; - case FILE_OPMULTIPLY: - offset = lhs * off; - break; - case FILE_OPDIVIDE: - offset = lhs / off; - break; - case FILE_OPMODULO: - offset = lhs % off; - break; - } - } else - offset = lhs; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + lhs = cvt_id3(ms, (uint32_t)lhs); + offset = do_ops(m, SEXT(sgn,32,lhs), off); break; case FILE_MELONG: if (OFFSET_OOB(nbytes, offset, 4)) return 0; - lhs = ME32(p); - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = lhs & off; - break; - case FILE_OPOR: - offset = lhs | off; - break; - case FILE_OPXOR: - offset = lhs ^ off; - break; - case FILE_OPADD: - offset = lhs + off; - break; - case FILE_OPMINUS: - offset = lhs - off; - break; - case FILE_OPMULTIPLY: - offset = lhs * off; - break; - case FILE_OPDIVIDE: - offset = lhs / off; - break; - case FILE_OPMODULO: - offset = lhs % off; - break; - } - } else - offset = lhs; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + offset = do_ops(m, SEXT(sgn,32,ME32(p)), off); break; case FILE_LONG: if (OFFSET_OOB(nbytes, offset, 4)) return 0; - if (off) { - switch (m->in_op & FILE_OPS_MASK) { - case FILE_OPAND: - offset = p->l & off; - break; - case FILE_OPOR: - offset = p->l | off; - break; - case FILE_OPXOR: - offset = p->l ^ off; - break; - case FILE_OPADD: - offset = p->l + off; - break; - case FILE_OPMINUS: - offset = p->l - off; - break; - case FILE_OPMULTIPLY: - offset = p->l * off; - break; - case FILE_OPDIVIDE: - offset = p->l / off; - break; - case FILE_OPMODULO: - offset = p->l % off; - break; - } - } else - offset = p->l; - if (m->in_op & FILE_OPINVERSE) - offset = ~offset; + offset = do_ops(m, SEXT(sgn,32,p->l), off); break; default: break; |