1 /*
2  *  Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3  *  Copyright (C) 2013 Sourcefire, Inc.
4  *
5  *  Authors: David Raynor <draynor@sourcefire.com>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  */
21 
22 #ifndef __HFSPLUS_H
23 #define __HFSPLUS_H
24 
25 #if HAVE_CONFIG_H
26 #include "clamav-config.h"
27 #endif
28 
29 #include "clamav-types.h"
30 
31 /* Structures based on Apple Technote 1150 */
32 
33 /* volume attributes that may affect reading */
34 enum hfsVolAttributes {
35     /* hfsVolumeHardwareLockBit       =  7, */
36     hfsVolumeUnmountedBit    = 8,
37     hfsVolumeSparedBlocksBit = 9,
38     /* hfsVolumeNoCacheRequiredBit    = 10, */
39     hfsBootVolumeInconsistentBit = 11,
40     hfsCatalogNodeIDsReusedBit   = 12,
41     hfsVolumeJournaledBit        = 13
42     /* hfsVolumeSoftwareLockBit       = 15 */
43 };
44 
45 /* reserved CatalogNodeID values */
46 enum {
47     hfsRootParentID           = 1,
48     hfsRootFolderID           = 2,
49     hfsExtentsFileID          = 3,
50     hfsCatalogFileID          = 4,
51     hfsBadBlockFileID         = 5,
52     hfsAllocationFileID       = 6,
53     hfsStartupFileID          = 7,
54     hfsAttributesFileID       = 8,
55     hfsRepairCatalogFileID    = 14,
56     hfsBogusExtentFileID      = 15,
57     hfsFirstUserCatalogNodeID = 16
58 };
59 
60 #ifndef HAVE_ATTRIB_PACKED
61 #define __attribute__(x)
62 #endif
63 
64 #ifdef HAVE_PRAGMA_PACK
65 #pragma pack(2)
66 #endif
67 
68 #ifdef HAVE_PRAGMA_PACK_HPPA
69 #pragma pack 2
70 #endif
71 
72 /* Basic HFS+ structures */
73 struct hfsUniStr255 {
74     uint16_t length;
75     uint16_t unicode[255];
76 } __attribute__((__packed__));
77 typedef struct hfsUniStr255 hfsUniStr255;
78 
79 struct hfsPlusExtentDescriptor {
80     uint32_t startBlock;
81     uint32_t blockCount;
82 } __attribute__((__packed__));
83 typedef struct hfsPlusExtentDescriptor hfsPlusExtentDescriptor;
84 typedef hfsPlusExtentDescriptor hfsPlusExtentRecord[8];
85 
86 struct hfsPlusForkData {
87     uint64_t logicalSize;
88     uint32_t clumpSize;
89     uint32_t totalBlocks;
90     hfsPlusExtentRecord extents;
91 } __attribute__((__packed__));
92 typedef struct hfsPlusForkData hfsPlusForkData;
93 
94 /* HFS+ Volume Header (512 bytes) */
95 struct hfsPlusVolumeHeader {
96     uint16_t signature; /* H+ for HFS+, HX for HFSX */
97     uint16_t version;
98     uint32_t attributes;
99     uint32_t lastMountedVersion;
100     uint32_t journalInfoBlock;
101 
102     uint32_t createDate;
103     uint32_t modifyDate;
104     uint32_t backupDate;
105     uint32_t checkedDate;
106 
107     uint32_t fileCount;
108     uint32_t folderCount;
109 
110     uint32_t blockSize;
111     uint32_t totalBlocks;
112     uint32_t freeBlocks;
113 
114     uint32_t nextAllocation;
115     uint32_t rsrcClumpSize;
116     uint32_t dataClumpSize;
117     uint32_t nextCatalogID; /* Next unused catalog ID */
118 
119     uint32_t writeCount;
120     uint64_t encodingsBitmap;
121 
122     uint32_t finderInfo[8]; /* for Finder */
123 
124     hfsPlusForkData allocationFile;
125     hfsPlusForkData extentsFile;
126     hfsPlusForkData catalogFile;
127     hfsPlusForkData attributesFile;
128     hfsPlusForkData startupFile;
129 } __attribute__((__packed__));
130 typedef struct hfsPlusVolumeHeader hfsPlusVolumeHeader;
131 
132 #define HFS_FILETREE_ALLOCATION 1
133 #define HFS_FILETREE_EXTENTS 2
134 #define HFS_FILETREE_CATALOG 3
135 #define HFS_FILETREE_ATTRIBUTES 4
136 #define HFS_FILETREE_STARTUP 5
137 
138 /* BSD object info (16 bytes) */
139 /* important parts for scanning are fileMode and the special part */
140 struct hfsPlusBSDInfo {
141     uint32_t ownerID;
142     uint32_t groupID;
143     uint8_t adminFlags;
144     uint8_t ownerFlags;
145     uint16_t fileMode;
146     union {
147         uint32_t iNodeNum;
148         uint32_t linkCount;
149         uint32_t rawDevice;
150     } special;
151 } __attribute__((__packed__));
152 typedef struct hfsPlusBSDInfo hfsPlusBSDInfo;
153 
154 #define HFS_MODE_TYPEMASK 0170000
155 #define HFS_MODE_DIRECTORY 0040000
156 #define HFS_MODE_FILE 0100000
157 #define HFS_MODE_SOFTLINK 0120000
158 
159 /******************************/
160 /* Node and tree structures   */
161 /******************************/
162 
163 /* B-tree node descriptor (14 bytes) */
164 struct hfsNodeDescriptor {
165     uint32_t fLink;
166     uint32_t bLink;
167     int8_t kind;
168     uint8_t height;
169     uint16_t numRecords;
170     uint16_t reserved;
171 } __attribute__((__packed__));
172 typedef struct hfsNodeDescriptor hfsNodeDescriptor;
173 
174 /* Node kinds are int8_t */
175 #define HFS_NODEKIND_LEAF -1
176 #define HFS_NODEKIND_INDEX 0
177 #define HFS_NODEKIND_HEADER 1
178 #define HFS_NODEKIND_MAP 2
179 
180 /* B-tree header record (106 bytes) */
181 struct hfsHeaderRecord {
182     uint16_t treeDepth;
183     uint32_t rootNode;
184     uint32_t leafRecords;
185     uint32_t firstLeafNode;
186     uint32_t lastLeafNode;
187     uint16_t nodeSize;
188     uint16_t maxKeyLength;
189     uint32_t totalNodes;
190     uint32_t freeNodes;
191     uint16_t reserved1;
192     uint32_t clumpSize;
193     uint8_t btreeType;
194     uint8_t keyCompareType;
195     uint32_t attributes;
196     uint32_t reserved3[16];
197 } __attribute__((__packed__));
198 typedef struct hfsHeaderRecord hfsHeaderRecord;
199 
200 #define HFS_HEADERATTR_MASK 0x00000006
201 #define HFS_HEADERATTR_BIGKEYS 0x00000002
202 #define HFS_HEADERATTR_VARKEYS 0x00000004
203 
204 struct hfsPlusCatalogKey {
205     uint16_t keyLength;
206     uint32_t parentID; /* CNID */
207     hfsUniStr255 nodeName;
208 } __attribute__((__packed__));
209 typedef struct hfsPlusCatalogKey hfsPlusCatalogKey;
210 
211 struct hfsPlusCatalogFolder {
212     int16_t recordType;
213     uint16_t flags;
214     uint32_t valence;
215     uint32_t folderID; /* CNID */
216     uint32_t dates[5];
217     hfsPlusBSDInfo permissions;
218     uint16_t userInfo[8];   /* FolderInfo */
219     uint16_t finderInfo[8]; /* ExtendedFolderInfo */
220     uint32_t textEncoding;
221     uint32_t reserved;
222 } __attribute__((__packed__));
223 typedef struct hfsPlusCatalogFolder hfsPlusCatalogFolder;
224 
225 struct hfsPlusCatalogFile {
226     int16_t recordType;
227     uint16_t flags;
228     uint32_t reserved1;
229     uint32_t fileID; /* CNID */
230     uint32_t dates[5];
231     hfsPlusBSDInfo permissions;
232     uint16_t userInfo[8];   /* FileInfo */
233     uint16_t finderInfo[8]; /* ExtendedFileInfo */
234     uint32_t textEncoding;
235     uint32_t reserved2;
236     hfsPlusForkData dataFork;
237     hfsPlusForkData resourceFork;
238 };
239 typedef struct hfsPlusCatalogFile hfsPlusCatalogFile;
240 
241 struct hfsPlusCatalogThread {
242     int16_t recordType;
243     int16_t reserved;
244     uint32_t parentID; /* CNID */
245     hfsUniStr255 nodeName;
246 } __attribute__((__packed__));
247 typedef struct hfsPlusCatalogThread hfsPlusCatalogThread;
248 
249 #define HFSPLUS_RECTYPE_FOLDER 0x0001
250 #define HFSPLUS_RECTYPE_FILE 0x0002
251 #define HFSPLUS_RECTYPE_FOLDERTHREAD 0x0003
252 #define HFSPLUS_RECTYPE_FILETHREAD 0x0004
253 #define HFSPLUS_RECTYPE_INLINE_DATA_ATTRIBUTE 0x0010
254 /* HFS types are similar
255 #define HFS_RECTYPE_FOLDER       0x0100
256 #define HFS_RECTYPE_FILE         0x0200
257 #define HFS_RECTYPE_FOLDERTHREAD 0x0300
258 #define HFS_RECTYPE_FILETHREAD   0x0400
259  */
260 
261 #define HFS_HARD_LINK_FILE_TYPE 0x686C6E6B /* hlnk */
262 
263 /* Extents structures */
264 struct hfsPlusExtentKey {
265     uint16_t keyLength;
266     uint8_t forkType;
267     uint8_t pad;
268     uint32_t fileID; /* CNID */
269     uint32_t startBlock;
270 } __attribute__((__packed__));
271 typedef struct hfsPlusExtentKey hfsPlusExtentKey;
272 
273 #define HFSPLUS_FORKTYPE_DATA 0x00
274 #define HFSPLUS_FORKTYPE_RSRC 0xFF
275 
276 /* Attribute structures */
277 struct hfsPlusAttributeKey {
278     uint16_t keyLength;
279     uint16_t pad;
280     uint32_t cnid;
281     uint32_t startBlock;
282     uint16_t nameLength;
283 } __attribute__((__packed__));
284 typedef struct hfsPlusAttributeKey hfsPlusAttributeKey;
285 
286 struct hfsPlusAttributeRecord {
287     uint32_t recordType;
288     uint32_t reserved1;
289     uint32_t reserved2;
290     uint32_t attributeSize;
291 } __attribute__((__packed__));
292 typedef struct hfsPlusAttributeRecord hfsPlusAttributeRecord;
293 
294 struct hfsPlusCompressionHeader {
295     uint32_t magic;
296     uint32_t compressionType;
297     uint64_t fileSize;
298 } __attribute__((__packed__));
299 typedef struct hfsPlusCompressionHeader hfsPlusCompressionHeader;
300 
301 /* Resource structures */
302 struct hfsPlusResourceHeader {
303     uint32_t dataOffset;
304     uint32_t mapOffset;
305     uint32_t dataLength;
306     uint32_t mapLength;
307 } __attribute__((__packed__));
308 typedef struct hfsPlusResourceHeader hfsPlusResourceHeader;
309 
310 struct hfsPlusResourceMap {
311     uint8_t reserved1[16];
312     uint32_t reserved2;
313     uint16_t reserved3;
314     uint16_t resourceForkAttributes;
315     uint16_t typeListOffset;
316     uint16_t nameListOffset;
317     int16_t typeCount;
318 } __attribute__((__packed__));
319 typedef struct hfsPlusResourceMap hfsPlusResourceMap;
320 
321 struct hfsPlusResourceType {
322     char type[4];
323     uint16_t instanceCount;
324     uint16_t referenceListOffset;
325 } __attribute__((__packed__));
326 typedef struct hfsPlusResourceType hfsPlusResourceType;
327 
328 struct hfsPlusReferenceEntry {
329     uint16_t resourceId;
330     int16_t resourceNameOffset;
331     uint8_t resourceAttributes;
332     uint8_t resourceDataOffset[3];
333     uint32_t reserved1;
334 } __attribute__((__packed__));
335 typedef struct hfsPlusReferenceEntry hfsPlusReferenceEntry;
336 
337 struct hfsPlusResourceBlockTable {
338     uint32_t offset;
339     uint32_t length;
340 } __attribute__((__packed__));
341 typedef struct hfsPlusResourceBlockTable hfsPlusResourceBlockTable;
342 
343 #define HFSPLUS_COMPRESSION_INLINE 0x03
344 #define HFSPLUS_COMPRESSION_RESOURCE 0x04
345 
346 #ifdef HAVE_PRAGMA_PACK
347 #pragma pack()
348 #endif
349 
350 #ifdef HAVE_PRAGMA_PACK_HPPA
351 #pragma pack
352 #endif
353 
354 #define HFS_VOL_INCONSISTENT(hdr) \
355     ((hdr->attributes & (1 << hfsBootVolumeInconsistentBit)) || !(hdr->attributes & (1 << hfsVolumeUnmountedBit)))
356 
357 /* Maximum number of catalog leaf nodes to scan for records */
358 #define HFSPLUS_NODE_LIMIT 1000
359 
360 cl_error_t cli_scanhfsplus(cli_ctx *ctx);
361 
362 #endif
363