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 */