[File] [PATCH] Add an octal type for offsets and use it to detect signed GPKG

Michał Górny mgorny at gentoo.org
Sat Sep 10 12:26:51 UTC 2022


Add an "octal" type that can be used to process the string
representation of numbers in base 8, and use them as indirect offsets.
This is particularly helpful for ustar format archives that use octal
representation for member sizes.

Use the new type to locate the name of the third member of GPKG archive
and determine whether it is an OpenPGP signature, indicating that
the binary package is signed.
---
 doc/magic.man        |  4 ++++
 magic/Magdir/archive |  1 +
 src/apprentice.c     |  9 +++++++++
 src/file.h           |  7 +++++--
 src/print.c          | 19 +++++++++++++++++++
 src/softmagic.c      | 21 ++++++++++++++++++++-
 6 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/doc/magic.man b/doc/magic.man
index daa394ae..3a2ac139 100644
--- a/doc/magic.man
+++ b/doc/magic.man
@@ -359,6 +359,9 @@ For example the magic entries:
 -0	offset	<=100	must be more than 100 \e
     bytes and is only %lld
 .Ed
+.It Dv octal
+A string representing an octal number.
+.El
 .El
 .Pp
 For compatibility with the Single
@@ -645,6 +648,7 @@ The following types are recognized:
 .It i	ID3	Little	4
 .It I	ID3	Big	4
 .It m	Middle	Middle	4
+.It o	Octal	Textual	Variable
 .It q	Quad	Little	8
 .It Q	Quad	Big	8
 .El
diff --git a/magic/Magdir/archive b/magic/Magdir/archive
index 65b19950..04442254 100644
--- a/magic/Magdir/archive
+++ b/magic/Magdir/archive
@@ -190,6 +190,7 @@
 >>>>&0	string		lzo\0		using lzo compression
 >>>>&0	string		xz\0		using xz compression
 >>>>&0	string		zst\0		using zstd compression
+>>>(636.o+1024)	search/611	.sig\0	\b, signed
 
 # Incremental snapshot gnu-tar format from:
 # https://www.gnu.org/software/tar/manual/html_node/Snapshot-Files.html
diff --git a/src/apprentice.c b/src/apprentice.c
index 9dbe52ee..b7b4b043 100644
--- a/src/apprentice.c
+++ b/src/apprentice.c
@@ -295,6 +295,7 @@ static const struct type_tbl_s type_tbl[] = {
 	{ XX("msdostime"),	FILE_MSDOSTIME,		FILE_FMT_STR },
 	{ XX("lemsdostime"),	FILE_LEMSDOSTIME,	FILE_FMT_STR },
 	{ XX("bemsdostime"),	FILE_BEMSDOSTIME,	FILE_FMT_STR },
+	{ XX("octal"),		FILE_OCTAL,		FILE_FMT_STR },
 	{ XX_NULL,		FILE_INVALID,		FILE_FMT_NONE },
 };
 
@@ -306,6 +307,7 @@ static const struct type_tbl_s special_tbl[] = {
 	{ XX("der"),		FILE_DER,		FILE_FMT_STR },
 	{ XX("name"),		FILE_NAME,		FILE_FMT_STR },
 	{ XX("use"),		FILE_USE,		FILE_FMT_STR },
+	{ XX("octal"),		FILE_OCTAL,		FILE_FMT_STR },
 	{ XX_NULL,		FILE_INVALID,		FILE_FMT_NONE },
 };
 # undef XX
@@ -1002,6 +1004,7 @@ apprentice_magic_strength_1(const struct magic *m)
 
 	case FILE_PSTRING:
 	case FILE_STRING:
+	case FILE_OCTAL:
 		val += m->vallen * MULT;
 		break;
 
@@ -1233,6 +1236,7 @@ set_test_type(struct magic *mstart, struct magic *m)
 	case FILE_MSDOSTIME:
 	case FILE_BEMSDOSTIME:
 	case FILE_LEMSDOSTIME:
+	case FILE_OCTAL:
 		mstart->flag |= BINTEST;
 		break;
 	case FILE_STRING:
@@ -1694,6 +1698,7 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
 		case FILE_CLEAR:
 		case FILE_DER:
 		case FILE_GUID:
+		case FILE_OCTAL:
 			break;
 		default:
 			if (ms->flags & MAGIC_CHECK)
@@ -2168,6 +2173,9 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line,
 			case 'I':
 				m->in_type = FILE_BEID3;
 				break;
+			case 'o':
+				m->in_type = FILE_OCTAL;
+				break;
 			case 'q':
 				m->in_type = FILE_LEQUAD;
 				break;
@@ -2832,6 +2840,7 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
 	case FILE_NAME:
 	case FILE_USE:
 	case FILE_DER:
+	case FILE_OCTAL:
 		*p = getstr(ms, m, *p, action == FILE_COMPILE);
 		if (*p == NULL) {
 			if (ms->flags & MAGIC_CHECK)
diff --git a/src/file.h b/src/file.h
index 69aad1dc..5b86bdc4 100644
--- a/src/file.h
+++ b/src/file.h
@@ -278,7 +278,8 @@ struct magic {
 #define				FILE_MSDOSTIME		56
 #define				FILE_LEMSDOSTIME	57
 #define				FILE_BEMSDOSTIME	58
-#define				FILE_NAMES_SIZE		59 /* size of array to contain all names */
+#define				FILE_OCTAL		59
+#define				FILE_NAMES_SIZE		60 /* size of array to contain all names */
 
 #define IS_STRING(t) \
 	((t) == FILE_STRING || \
@@ -289,7 +290,8 @@ struct magic {
 	 (t) == FILE_SEARCH || \
 	 (t) == FILE_INDIRECT || \
 	 (t) == FILE_NAME || \
-	 (t) == FILE_USE)
+	 (t) == FILE_USE || \
+	 (t) == FILE_OCTAL)
 
 #define FILE_FMT_NONE 0
 #define FILE_FMT_NUM  1 /* "cduxXi" */
@@ -510,6 +512,7 @@ protected const char *file_fmtdate(char *, size_t, uint16_t);
 protected const char *file_fmttime(char *, size_t, uint16_t);
 protected const char *file_fmtvarint(const unsigned char *, int, char *,
     size_t);
+protected const char *file_fmtnum(const char *, char *, size_t, int);
 protected struct magic_set *file_ms_alloc(int);
 protected void file_ms_free(struct magic_set *);
 protected int file_default(struct magic_set *, size_t);
diff --git a/src/print.c b/src/print.c
index ee8cb5af..03fbf382 100644
--- a/src/print.c
+++ b/src/print.c
@@ -214,6 +214,9 @@ file_mdump(struct magic *m)
 			(void)fprintf(stderr, "%s,",
 			    file_fmttime(tbuf, sizeof(tbuf), m->value.h));
 			break;
+		case FILE_OCTAL:
+			(void)fprintf(stderr, "%s",
+				file_fmtnum(m->value.s, tbuf, sizeof(tbuf), 8));
 		case FILE_DEFAULT:
 			/* XXX - do anything here? */
 			break;
@@ -340,3 +343,19 @@ out:
 	return buf;
 
 }
+
+protected const char *
+file_fmtnum(const char *us, char *buf, size_t blen, int base)
+{
+	char *endptr;
+	uint64_t val;
+
+	val = strtoull(us, &endptr, base);
+	if (*endptr) {
+		strlcpy(buf, "*Invalid number*", blen);
+		return buf;
+	}
+
+	snprintf(buf, blen, "%" INT64_T_FORMAT "u", CAST(unsigned long long, val));
+	return buf;
+}
diff --git a/src/softmagic.c b/src/softmagic.c
index 4c288b4a..8993007a 100644
--- a/src/softmagic.c
+++ b/src/softmagic.c
@@ -816,6 +816,11 @@ mprint(struct magic_set *ms, struct magic *m)
 		    file_fmttime(tbuf, sizeof(tbuf), p->h)) == -1)
 			return -1;
 		break;
+	case FILE_OCTAL:
+		file_fmtnum(ms->ms_value.s, buf, sizeof(buf), 8);
+		if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
+			return -1;
+		break;
 	default:
 		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
 		return -1;
@@ -864,6 +869,7 @@ moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
   	case FILE_PSTRING:
   	case FILE_BESTRING16:
   	case FILE_LESTRING16:
+	case FILE_OCTAL:
 		if (m->reln == '=' || m->reln == '!') {
 			o = ms->offset + m->vallen;
 		} else {
@@ -1174,7 +1180,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip)
 		return 1;
 	case FILE_STRING:
 	case FILE_BESTRING16:
-	case FILE_LESTRING16: {
+	case FILE_LESTRING16:
+	case FILE_OCTAL: {
 		/* Null terminate and eat *trailing* return */
 		p->s[sizeof(p->s) - 1] = '\0';
 		return 1;
@@ -1661,6 +1668,11 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
 					return 0;
 				off = SEXT(sgn,64,LE64(q));
 				break;
+			case FILE_OCTAL:
+				if (OFFSET_OOB(nbytes, offset, m->vallen))
+					return 0;
+				off = SEXT(sgn,64,strtoull(p->s, NULL, 8));
+				break;
 			default:
 				if ((ms->flags & MAGIC_DEBUG) != 0)
 					fprintf(stderr, "bad op=%d\n", op);
@@ -1728,6 +1740,11 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
 				return 0;
 			offset = do_ops(m, SEXT(sgn,64,BE64(p)), off);
 			break;
+		case FILE_OCTAL:
+			if (OFFSET_OOB(nbytes, offset, m->vallen))
+				return 0;
+			offset = do_ops(m, SEXT(sgn,64,strtoull(p->s, NULL, 8)), off);
+			break;
 		default:
 			if ((ms->flags & MAGIC_DEBUG) != 0)
 				fprintf(stderr, "bad in_type=%d\n", in_type);
@@ -1812,6 +1829,7 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
 	case FILE_STRING:
 	case FILE_PSTRING:
 	case FILE_SEARCH:
+	case FILE_OCTAL:
 		if (OFFSET_OOB(nbytes, offset, m->vallen))
 			return 0;
 		break;
@@ -2170,6 +2188,7 @@ magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache)
 
 	case FILE_STRING:
 	case FILE_PSTRING:
+	case FILE_OCTAL:
 		l = 0;
 		v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
 		    sizeof(p->s), m->str_flags);
-- 
2.37.3



More information about the File mailing list