Fix numerous sign-extension problems, and add support for explicitly unsigned

comparisons.
This commit is contained in:
mycroft 1993-11-03 04:04:19 +00:00
parent 9fc3df91d1
commit ab61bc03f0
4 changed files with 117 additions and 137 deletions

View File

@ -26,7 +26,7 @@
*/
#ifndef lint
static char rcsid[] = "$Id: apprentice.c,v 1.3 1993/08/01 18:16:26 mycroft Exp $";
static char rcsid[] = "$Id: apprentice.c,v 1.4 1993/11/03 04:04:21 mycroft Exp $";
#endif /* not lint */
#include <stdio.h>
@ -43,6 +43,7 @@ static int getvalue __P((struct magic *, char **));
static int hextoint __P((int));
static char *getstr __P((char *, char *, int, int *));
static int parse __P((char *, int *, int));
extern unsigned long signextend __P((struct magic *, unsigned long));
static int maxmagic = 0;
@ -75,10 +76,6 @@ int check; /* non-zero? checking-only run. */
exit(1);
}
/* parse it */
if (check) /* print silly verbose header for USG compat. */
(void) printf("cont\toffset\ttype\topcode\tmask\tvalue\tdesc\n");
for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
if (line[0]=='#') /* comment, do not parse */
continue;
@ -93,6 +90,45 @@ int check; /* non-zero? checking-only run. */
return errs ? -1 : 0;
}
/*
* extend the sign bit if the comparison is to be signed
*/
unsigned long
signextend(m, v)
struct magic *m;
unsigned long v;
{
if (!(m->flag & UNSIGNED))
switch(m->type) {
/*
* Do not remove the casts below. They are
* vital. When later compared with the data,
* the sign extension must have happened.
*/
case BYTE:
v = (char) v;
break;
case SHORT:
case BESHORT:
case LESHORT:
v = (short) v;
break;
case DATE:
case BEDATE:
case LEDATE:
case LONG:
case BELONG:
case LELONG:
v = (long) v;
break;
default:
magwarn("can't happen: m->type=%d\n",
m->type);
return -1;
}
return v;
}
/*
* parse one line from magic file, put into magic[index++] if valid
*/
@ -188,6 +224,11 @@ int *ndx, check;
#define NLELONG 6
#define NLEDATE 6
if (*l == 'u') {
++l;
m->flag |= UNSIGNED;
}
/* get type, skip it */
if (strncmp(l, "byte", NBYTE)==0) {
m->type = BYTE;
@ -229,7 +270,8 @@ int *ndx, check;
/* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
if (*l == '&') {
++l;
m->mask = strtol(l, &l, 0);
m->mask = signextend(m, strtol(l, &l, 0));
m->flag |= MASK;
} else
m->mask = 0L;
EATAB;
@ -310,36 +352,9 @@ char **p;
if (m->type == STRING) {
*p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
m->vallen = slen;
} else {
if (m->reln != 'x') {
switch(m->type) {
/*
* Do not remove the casts below. They are vital.
* When later compared with the data, the sign
* extension must have happened.
*/
case BYTE:
m->value.l = (char) strtol(*p,p,0);
break;
case SHORT:
case BESHORT:
case LESHORT:
m->value.l = (short) strtol(*p,p,0);
break;
case DATE:
case BEDATE:
case LEDATE:
case LONG:
case BELONG:
case LELONG:
m->value.l = (long) strtol(*p,p,0);
break;
default:
magwarn("can't happen: m->type=%d\n", m->type);
return -1;
}
}
}
} else
if (m->reln != 'x')
m->value.l = signextend(m, strtol(*p, p, 0));
return 0;
}

View File

@ -1,7 +1,7 @@
/*
* file.h - definitions for file(1) program
*
* $Id: file.h,v 1.3 1993/08/01 18:16:29 mycroft Exp $
* $Id: file.h,v 1.4 1993/11/03 04:04:19 mycroft Exp $
*
* Copyright (c) Ian F. Darwin, 1987.
* Written by Ian F. Darwin.
@ -35,13 +35,14 @@
struct magic {
short flag;
#define INDIR 1 /* if '>(...)' appears, */
#define UNSIGNED 2 /* comparison is unsigned */
#define MASK 4 /* this is a masked op, like & v1 = v2 */
short cont_level; /* level of ">" */
struct {
char type; /* byte short long */
long offset; /* offset from indirection */
} in;
long offset; /* offset to magic number */
#define MASK 0200 /* this is a masked op, like & v1 = v2 */
unsigned char reln; /* relation (0=eq, '>'=gt, etc) */
char type; /* int, short, long or string. */
char vallen; /* length of string value, if any */
@ -57,14 +58,14 @@ struct magic {
#define LELONG 11
#define LEDATE 12
union VALUETYPE {
char b;
short h;
long l;
unsigned char b;
unsigned short h;
unsigned long l;
char s[MAXstring];
unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */
unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */
} value; /* either number or string */
long mask; /* mask before comparison with value */
unsigned long mask; /* mask before comparison with value */
char nospflag; /* supress space character */
char desc[MAXDESC]; /* description */
};

View File

@ -26,7 +26,7 @@
*/
#ifndef lint
static char rcsid[] = "$Id: print.c,v 1.4 1993/08/06 01:47:19 deraadt Exp $";
static char rcsid[] = "$Id: print.c,v 1.5 1993/11/03 04:04:20 mycroft Exp $";
#endif /* not lint */
#include <stdio.h>
@ -45,31 +45,27 @@ void
mdump(m)
struct magic *m;
{
static char *offs[] = { "absolute", "offset",
"indirect", "indirect-offset" };
static char *typ[] = { "invalid", "byte", "short", "invalid",
"long", "string", "date", "beshort",
"belong", "bedate", "leshort", "lelong",
"ledate" };
(void) fprintf(stderr, "[%s,%d,%s,%s%c,",
(m->flag >= 0 && m->flag < 4 ? offs[m->flag]: "*bad*"),
m->offset,
(m->type >= 0 && m->type < 13 ?
typ[(unsigned char) m->type] : "*bad*"),
m->reln & MASK ? "&" : "",
m->reln & ~MASK);
printf(">>>>>>>>%d" + 8 - m->cont_level, m->offset);
if (m->flag & INDIR)
(void) fprintf(stderr, "(%s,%d)",
(m->in.type >= 0 &&
m->in.type < 6 ? typ[(unsigned char) m->in.type] : "*bad*"),
printf("(%s,%d)",
(m->in.type >= 0 && m->in.type < 6 ?
typ[(unsigned char) m->in.type] : "*bad*"),
m->in.offset);
printf(" %s%s", m->flag & UNSIGNED ? "u" : "",
(m->type >= 0 && m->type < 13 ?
typ[(unsigned char) m->type] : "*bad*"));
if (m->flag & MASK)
printf("&%d", m->mask);
printf(" %c", m->reln);
if (m->type == STRING)
showstr(m->value.s);
else
(void) fprintf(stderr, "%d",m->value.l);
(void) fprintf(stderr, ",%s", m->desc);
(void) fputs("]\n", stderr);
printf("%d", m->value.l);
printf(" %s\n", m->desc);
}
/*

View File

@ -26,7 +26,7 @@
*/
#ifndef lint
static char rcsid[] = "$Id: softmagic.c,v 1.4 1993/08/06 01:47:19 deraadt Exp $";
static char rcsid[] = "$Id: softmagic.c,v 1.5 1993/11/03 04:04:22 mycroft Exp $";
#endif /* not lint */
#include <stdio.h>
@ -38,7 +38,10 @@ static char rcsid[] = "$Id: softmagic.c,v 1.4 1993/08/06 01:47:19 deraadt Exp $"
static int match __P((unsigned char *));
static int mcheck __P((unsigned char *, struct magic *));
static void mprint __P((struct magic *, unsigned char *));
static void mprint __P((unsigned char *, struct magic *, unsigned long));
extern unsigned long signextend __P((struct magic *, unsigned long));
static int need_separator;
/*
* softmagic - lookup one file in database
@ -90,18 +93,11 @@ unsigned char *s;
{
int magindex = 0;
int cont_level = 0;
int need_separator = 0;
while (magindex < nmagic) {
/* if main entry matches, print it... */
need_separator = 0;
if (mcheck(s, &magic[magindex])) {
mprint(&magic[magindex],s);
/*
* If we printed something, we'll need to print
* a blank before we print something else.
*/
if (magic[magindex].desc[0])
need_separator = 1;
/* and any continuations that match */
cont_level++;
while (magic[magindex+1].cont_level != 0 &&
@ -122,24 +118,6 @@ unsigned char *s;
if (mcheck(s, &magic[magindex])) {
/*
* This continuation matched.
* Print its message, with
* a blank before it if
* the previous item printed
* and this item isn't empty.
*/
/* space if previous printed */
if (need_separator
&& (magic[magindex].nospflag == 0)
&& (magic[magindex].desc[0] != '\0')
) {
(void) putchar(' ');
need_separator = 0;
}
mprint(&magic[magindex],s);
if (magic[magindex].desc[0])
need_separator = 1;
/*
* If we see any continuations
* at a higher level,
* process them.
@ -162,49 +140,29 @@ unsigned char *s;
}
static void
mprint(m, s)
struct magic *m;
mprint(s, m, v)
unsigned char *s;
struct magic *m;
unsigned long v;
{
register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
char *pp, *rt;
/* correct byte order dependancies */
switch (m->type) {
case BESHORT:
p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
break;
case BELONG:
case BEDATE:
p->l = (long)
((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
break;
case LESHORT:
p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
break;
case LELONG:
case LEDATE:
p->l = (long)
((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
break;
if (m->desc[0]) {
if (need_separator && !m->nospflag)
(void) putchar(' ');
need_separator = 1;
}
switch (m->type) {
case BYTE:
(void) printf(m->desc,
(m->reln & MASK) ? p->b & m->mask : p->b);
break;
case SHORT:
case BESHORT:
case LESHORT:
(void) printf(m->desc,
(m->reln & MASK) ? p->h & m->mask : p->h);
break;
case LONG:
case BELONG:
case LELONG:
(void) printf(m->desc,
(m->reln & MASK) ? p->l & m->mask : p->l);
(void) printf(m->desc, v);
break;
case STRING:
if ((rt=strchr(p->s, '\n')) != NULL)
@ -216,7 +174,7 @@ unsigned char *s;
case DATE:
case BEDATE:
case LEDATE:
pp = ctime((time_t*) &p->l);
pp = ctime((time_t*) &v);
if ((rt = strchr(pp, '\n')) != NULL)
*rt = '\0';
(void) printf(m->desc, pp);
@ -235,19 +193,21 @@ unsigned char *s;
struct magic *m;
{
register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
register long l = m->value.l;
register long mask = m->mask;
register long v;
register unsigned long l = m->value.l;
register unsigned long v;
register int matched;
if (debug) {
(void) printf("mcheck: %10.10s ", s);
mdump(m);
}
#if 0
if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
printf("BOINK");
return 1;
}
#endif
switch (m->type) {
case BYTE:
@ -276,19 +236,19 @@ struct magic *m;
}
break;
case BESHORT:
v = (short)((p->hs[0]<<8)|(p->hs[1]));
v = (unsigned short)((p->hs[0]<<8)|(p->hs[1]));
break;
case BELONG:
case BEDATE:
v = (long)
v = (unsigned long)
((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
break;
case LESHORT:
v = (short)((p->hs[1]<<8)|(p->hs[0]));
v = (unsigned short)((p->hs[1]<<8)|(p->hs[0]));
break;
case LELONG:
case LEDATE:
v = (long)
v = (unsigned long)
((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
break;
default:
@ -296,32 +256,40 @@ struct magic *m;
return -1;/*NOTREACHED*/
}
if (m->mask != 0L)
v = signextend(m, v);
if (m->flag & MASK)
v &= m->mask;
switch (m->reln) {
case 'x':
return 1;
matched = 1; break;
case '!':
return v != l;
matched = v != l; break;
case '=':
return v == l;
matched = v == l; break;
case '>':
return v > l;
if (m->flag & UNSIGNED)
matched = v > l;
else
matched = (long)v > (long)l;
break;
case '<':
return v < l;
if (m->flag & UNSIGNED)
matched = v < l;
else
matched = (long)v < (long)l;
break;
case '&':
return (v & l) == l;
matched = (v & l) == l; break;
case '^':
return (v & l) != l;
case MASK | '=':
return (v & mask) == l;
case MASK | '>':
return (v & mask) > l;
case MASK | '<':
return (v & mask) < l;
matched = (v & l) != l; break;
default:
error("mcheck: can't happen: invalid relation %d.\n", m->reln);
return -1;/*NOTREACHED*/
}
if (matched)
mprint(s, m, v);
return matched;
}