Summary
StringTest.parse reads two relational operators off a string value where libmagic reads one.
A definition that writes !>ABC means, to libmagic, "not the literal four bytes >ABC". PolyFile
reads it as "not (greater than ABC)".
This is the string analogue of #3498, which PR #3528 fixed for regex.
Reproducer
$ printf '0\tstring\t!>ABC\tfound\n' > relop.magic
$ printf 'ZZZZZ' > z.bin
$ TZ=UTC ./file/src/file -b -m relop.magic z.bin
found
from polyfile.magic import MagicMatcher
matcher = MagicMatcher.parse("relop.magic")
print({str(m) for m in matcher.match(b"ZZZZZ")})
{'ASCII text, with no line terminators'}
ZZZZZ does not begin with the four bytes >ABC, so libmagic's negation succeeds. PolyFile builds
a NegatedStringTest around a StringLengthTest, finds that ZZZ sorts after ABC, and negates
that into a failure.
Cause
libmagic's parse reads exactly one character out of the relation switch and leaves the rest of
the line to getvalue (file/src/apprentice.c:2366-2416):
case '!':
m->reln = *l;
++l;
break;
StringTest.parse in polyfile/magic.py strips a leading !, then tests the remainder for a
leading > or < and builds a StringLengthTest from it, so both characters are consumed as
operators.
The same applies to !<ABC, and to !=ABC: libmagic takes the = as the first byte of the value,
while StringTest.parse strips it.
Impact
No shipped definition in magic_defs/ writes !> or !< on a string, so nothing in the corpus
reaches this. It affects hand-written definitions and any future import from upstream.
Found while checking the sibling string tests for #3557.
Summary
StringTest.parsereads two relational operators off astringvalue where libmagic reads one.A definition that writes
!>ABCmeans, to libmagic, "not the literal four bytes>ABC". PolyFilereads it as "not (greater than
ABC)".This is the
stringanalogue of #3498, which PR #3528 fixed forregex.Reproducer
ZZZZZdoes not begin with the four bytes>ABC, so libmagic's negation succeeds. PolyFile buildsa
NegatedStringTestaround aStringLengthTest, finds thatZZZsorts afterABC, and negatesthat into a failure.
Cause
libmagic's
parsereads exactly one character out of the relation switch and leaves the rest ofthe line to
getvalue(file/src/apprentice.c:2366-2416):StringTest.parseinpolyfile/magic.pystrips a leading!, then tests the remainder for aleading
>or<and builds aStringLengthTestfrom it, so both characters are consumed asoperators.
The same applies to
!<ABC, and to!=ABC: libmagic takes the=as the first byte of the value,while
StringTest.parsestrips it.Impact
No shipped definition in
magic_defs/writes!>or!<on astring, so nothing in the corpusreaches this. It affects hand-written definitions and any future import from upstream.
Found while checking the sibling string tests for #3557.