libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

forensics.h (10550B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2026 Vidyut Samanta and Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19  */
     20 /**
     21  * @file plugins/forensics.h
     22  * @brief helpers shared by the plugins that read provenance out of
     23  *        binary headers
     24  * @author Christian Grothoff
     25  *
     26  * These plugins all do the same handful of things -- pull a fixed-size
     27  * header out of the stream, pick integers out of it in a documented
     28  * byte order, and hand back strings that came from an untrusted file.
     29  * Doing that once here rather than sixteen times keeps the bounds
     30  * checks and the UTF-8 validation in one place.
     31  */
     32 #ifndef FORENSICS_H
     33 #define FORENSICS_H
     34 
     35 #include "extractor.h"
     36 
     37 
     38 /**
     39  * Longest string we will ever hand to the caller.  Values in these
     40  * formats are identifiers and paths, not documents; anything longer is
     41  * either padding or an attempt to make us allocate.
     42  */
     43 #define EXTRACTOR_FORENSIC_MAX_STRING 1024
     44 
     45 /**
     46  * Upper bound on how many items of the same repeating kind (archive
     47  * members, permissions, mail headers) a plugin should report.  A first
     48  * pass over a large volume wants a characterisation, not a listing.
     49  */
     50 #define EXTRACTOR_FORENSIC_MAX_ITEMS 64
     51 
     52 
     53 /**
     54  * Read exactly @a len bytes at @a offset into @a buf.
     55  *
     56  * `ec->read()' may return short reads and hands back a pointer that is
     57  * only valid until the next call, so every caller would otherwise need
     58  * this loop.
     59  *
     60  * @param ec extraction context
     61  * @param offset absolute position to read from, -1 to read at the
     62  *        current position without seeking
     63  * @param buf where to copy the data to
     64  * @param len number of bytes to read
     65  * @return 1 on success, 0 if the file is too short or seeking failed
     66  */
     67 int
     68 EXTRACTOR_forensic_read_ (struct EXTRACTOR_ExtractContext *ec,
     69                           int64_t offset,
     70                           void *buf,
     71                           size_t len);
     72 
     73 
     74 /**
     75  * Check that @a data is well-formed UTF-8.
     76  *
     77  * `EXTRACTOR_common_convert_to_utf8()' silently passes the input
     78  * through when iconv rejects it, so a plugin that trusts it will emit
     79  * whatever bytes the file contained.  Validate before emitting.
     80  *
     81  * @param data bytes to check
     82  * @param len number of bytes in @a data
     83  * @return 1 if @a data is valid UTF-8, 0 if not
     84  */
     85 int
     86 EXTRACTOR_forensic_utf8_valid_ (const char *data,
     87                                 size_t len);
     88 
     89 
     90 /**
     91  * Strip trailing spaces and NUL bytes from a fixed-width field.
     92  *
     93  * @param data the field
     94  * @param len width of the field
     95  * @return length of the field with the padding removed
     96  */
     97 size_t
     98 EXTRACTOR_forensic_trim_ (const char *data,
     99                           size_t len);
    100 
    101 
    102 /**
    103  * Parse a NUL- or space-terminated octal number, as used by tar.
    104  *
    105  * @param data the field
    106  * @param len width of the field
    107  * @param[out] value where to store the result
    108  * @return 1 on success, 0 if the field does not hold an octal number
    109  */
    110 int
    111 EXTRACTOR_forensic_parse_octal_ (const char *data,
    112                                  size_t len,
    113                                  uint64_t *value);
    114 
    115 
    116 /**
    117  * Shannon entropy of a buffer, in bits per byte.
    118  *
    119  * @param data the buffer
    120  * @param len number of bytes in @a data
    121  * @return entropy between 0.0 and 8.0, 0.0 for an empty buffer
    122  */
    123 double
    124 EXTRACTOR_forensic_entropy_ (const unsigned char *data,
    125                              size_t len);
    126 
    127 
    128 /**
    129  * Emit a printf-formatted value.
    130  *
    131  * @param ec extraction context
    132  * @param plugin name to report the data under
    133  * @param type meta data type
    134  * @param fmt printf format string
    135  * @return 1 if the caller should stop extracting, 0 to continue
    136  */
    137 int
    138 EXTRACTOR_forensic_emit_ (struct EXTRACTOR_ExtractContext *ec,
    139                           const char *plugin,
    140                           enum EXTRACTOR_MetaType type,
    141                           const char *fmt,
    142                           ...)
    143 __attribute__ ((format (printf, 4, 5)));
    144 
    145 
    146 /**
    147  * Emit a string that came out of the file.
    148  *
    149  * Trailing padding is stripped, control characters are replaced, the
    150  * result is capped at #EXTRACTOR_FORENSIC_MAX_STRING and dropped
    151  * entirely if it is empty or not valid UTF-8.
    152  *
    153  * @param ec extraction context
    154  * @param plugin name to report the data under
    155  * @param type meta data type
    156  * @param data the string, need not be NUL-terminated
    157  * @param len number of bytes in @a data
    158  * @return 1 if the caller should stop extracting, 0 to continue
    159  */
    160 int
    161 EXTRACTOR_forensic_emit_text_ (struct EXTRACTOR_ExtractContext *ec,
    162                                const char *plugin,
    163                                enum EXTRACTOR_MetaType type,
    164                                const char *data,
    165                                size_t len);
    166 
    167 
    168 /**
    169  * Emit a UTF-16LE string that came out of the file, converting it to
    170  * UTF-8.  Used by the Windows formats and by binary property lists.
    171  *
    172  * @param ec extraction context
    173  * @param plugin name to report the data under
    174  * @param type meta data type
    175  * @param data the string
    176  * @param bytes number of bytes (not code units) in @a data
    177  * @return 1 if the caller should stop extracting, 0 to continue
    178  */
    179 int
    180 EXTRACTOR_forensic_emit_utf16le_ (struct EXTRACTOR_ExtractContext *ec,
    181                                   const char *plugin,
    182                                   enum EXTRACTOR_MetaType type,
    183                                   const unsigned char *data,
    184                                   size_t bytes);
    185 
    186 
    187 /**
    188  * Emit a time expressed as seconds since the Unix epoch, as ISO 8601 in
    189  * UTC.  Implausible values (before 1980, after 2100) are dropped: they
    190  * are almost always a misparse or a zeroed field.
    191  *
    192  * @param ec extraction context
    193  * @param plugin name to report the data under
    194  * @param type meta data type
    195  * @param when seconds since 1970-01-01
    196  * @return 1 if the caller should stop extracting, 0 to continue
    197  */
    198 int
    199 EXTRACTOR_forensic_emit_unix_time_ (struct EXTRACTOR_ExtractContext *ec,
    200                                     const char *plugin,
    201                                     enum EXTRACTOR_MetaType type,
    202                                     int64_t when);
    203 
    204 
    205 /**
    206  * Emit a Windows FILETIME (100ns units since 1601-01-01) as ISO 8601.
    207  *
    208  * @param ec extraction context
    209  * @param plugin name to report the data under
    210  * @param type meta data type
    211  * @param filetime the FILETIME value
    212  * @return 1 if the caller should stop extracting, 0 to continue
    213  */
    214 int
    215 EXTRACTOR_forensic_emit_filetime_ (struct EXTRACTOR_ExtractContext *ec,
    216                                    const char *plugin,
    217                                    enum EXTRACTOR_MetaType type,
    218                                    uint64_t filetime);
    219 
    220 
    221 /**
    222  * Emit a byte count, as a plain decimal number of bytes.
    223  *
    224  * @param ec extraction context
    225  * @param plugin name to report the data under
    226  * @param type meta data type
    227  * @param bytes the value
    228  * @return 1 if the caller should stop extracting, 0 to continue
    229  */
    230 int
    231 EXTRACTOR_forensic_emit_size_ (struct EXTRACTOR_ExtractContext *ec,
    232                                const char *plugin,
    233                                enum EXTRACTOR_MetaType type,
    234                                uint64_t bytes);
    235 
    236 
    237 /**
    238  * Emit a byte string in lower-case hexadecimal.
    239  *
    240  * @param ec extraction context
    241  * @param plugin name to report the data under
    242  * @param type meta data type
    243  * @param data the bytes
    244  * @param len number of bytes in @a data, at most 64
    245  * @return 1 if the caller should stop extracting, 0 to continue
    246  */
    247 int
    248 EXTRACTOR_forensic_emit_hex_ (struct EXTRACTOR_ExtractContext *ec,
    249                               const char *plugin,
    250                               enum EXTRACTOR_MetaType type,
    251                               const unsigned char *data,
    252                               size_t len);
    253 
    254 
    255 /**
    256  * Emit a 16-byte GUID/UUID in the usual 8-4-4-4-12 spelling.
    257  *
    258  * @param ec extraction context
    259  * @param plugin name to report the data under
    260  * @param type meta data type
    261  * @param guid the 16 bytes
    262  * @param mixed_endian 1 if the first three fields are little-endian, as
    263  *        in a Microsoft GUID; 0 for a big-endian RFC 4122 UUID
    264  * @return 1 if the caller should stop extracting, 0 to continue
    265  */
    266 int
    267 EXTRACTOR_forensic_emit_guid_ (struct EXTRACTOR_ExtractContext *ec,
    268                                const char *plugin,
    269                                enum EXTRACTOR_MetaType type,
    270                                const unsigned char *guid,
    271                                int mixed_endian);
    272 
    273 
    274 /* Integer accessors.  The formats below all document their byte order,
    275    so read it explicitly rather than casting a struct over the buffer:
    276    that also sidesteps every alignment question. */
    277 
    278 static inline uint16_t
    279 EXTRACTOR_forensic_le16_ (const unsigned char *p)
    280 {
    281   return (uint16_t) (((uint16_t) p[0])
    282                      | (((uint16_t) p[1]) << 8));
    283 }
    284 
    285 
    286 static inline uint32_t
    287 EXTRACTOR_forensic_le32_ (const unsigned char *p)
    288 {
    289   return ((uint32_t) p[0])
    290          | (((uint32_t) p[1]) << 8)
    291          | (((uint32_t) p[2]) << 16)
    292          | (((uint32_t) p[3]) << 24);
    293 }
    294 
    295 
    296 static inline uint64_t
    297 EXTRACTOR_forensic_le64_ (const unsigned char *p)
    298 {
    299   return ((uint64_t) EXTRACTOR_forensic_le32_ (p))
    300          | (((uint64_t) EXTRACTOR_forensic_le32_ (p + 4)) << 32);
    301 }
    302 
    303 
    304 static inline uint16_t
    305 EXTRACTOR_forensic_be16_ (const unsigned char *p)
    306 {
    307   return (uint16_t) (((uint16_t) p[1])
    308                      | (((uint16_t) p[0]) << 8));
    309 }
    310 
    311 
    312 static inline uint32_t
    313 EXTRACTOR_forensic_be32_ (const unsigned char *p)
    314 {
    315   return ((uint32_t) p[3])
    316          | (((uint32_t) p[2]) << 8)
    317          | (((uint32_t) p[1]) << 16)
    318          | (((uint32_t) p[0]) << 24);
    319 }
    320 
    321 
    322 static inline uint64_t
    323 EXTRACTOR_forensic_be64_ (const unsigned char *p)
    324 {
    325   return (((uint64_t) EXTRACTOR_forensic_be32_ (p)) << 32)
    326          | ((uint64_t) EXTRACTOR_forensic_be32_ (p + 4));
    327 }
    328 
    329 
    330 #endif
    331 /* end of forensics.h */