diff --git a/README.md b/README.md index 761f37a..5f068d5 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | ARM VTOR | | [`patterns/arm_cm_vtor.hexpat`](patterns/arm_cm_vtor.hexpat) | ARM Cortex M Vector Table Layout | | Bencode | `application/x-bittorrent` | [`patterns/bencode.hexpat`](patterns/bencode.hexpat) | Bencode encoding, used by Torrent files | | BMP | `image/bmp` | [`patterns/bmp.hexpat`](patterns/bmp.hexpat) | OS2/Windows Bitmap files | +| BIN | | [`patterns/selinux.hexpat`](patterns/selinux.pat) | SE Linux modules | | BSON | `application/bson` | [`patterns/bson.hexpat`](patterns/bson.hexpat) | BSON (Binary JSON) format | | BSP | | [`patterns/bsp_goldsrc.hexpat`](patterns/bsp_goldsrc.hexpat) | GoldSrc engine maps format (used in Half-Life 1) | | CCHVA | | [`patterns/cchva.hexpat`](patterns/cchva.hexpat) | Command and Conquer Voxel Animation | @@ -74,6 +75,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | PCAP | `application/vnd.tcpdump.pcap` | [`patterns/pcap.hexpat`](patterns/pcap.hexpat) | pcap header and packets | | PCX | `application/x-pcx` | [`patterns/pcx.hexpat`](patterns/pcx.hexpat) | PCX Image format | | PE | `application/x-dosexec` | [`patterns/pe.hexpat`](patterns/pe.hexpat) | PE header, COFF header, Standard COFF fields and Windows Specific fields | +| PP | [`patterns/selinuxpp.hexpat`](patterns/selinuxpp.pat) | SE Linux package | | PFS0 | | [`patterns/pfs0.hexpat`](patterns/pfs0.hexpat) | Nintendo Switch PFS0 archive (NSP files) | | PIF | `image/pif` | [`patterns/pif.hexpat`](patterns/pif.hexpat) | PIF Image Format | | PNG | `image/png` | [`patterns/png.hexpat`](patterns/png.hexpat) | PNG image files | diff --git a/patterns/selinux.hexpat b/patterns/selinux.hexpat new file mode 100644 index 0000000..6372a9f --- /dev/null +++ b/patterns/selinux.hexpat @@ -0,0 +1,713 @@ +#include +#pragma pattern_limit 13107200 +#pragma endian little + +u32 version; +u32 symbols_count; +u32 object_contexts_count; +u32 type_primary_names_count = 0; +bool boundary_feature; + +using Header; + +enum magics: u32 { + kernel = 0xf97cff8c, + module = 0xf97cff8d, +}; + + +enum policy_types: u32 { + kernel = 0, + base = 1, + module = 2, +}; + +policy_types type_g; + +enum targets: u32 { + selinux = 0, + xen = 1, +}; + +targets target; + +struct list { + u32 count; + T item[count]; +}; + +struct symbols_list { + u32 primary_names_count; + list [[inline]]; +}; + + + +struct permission { + u32 length; + u32 value; + char key[length]; +}; + + +struct extensible_bitmap_node { + u32 startbit; + u64 map; +}; +struct extensible_bitmap { + u32 mapsize; + std::assert(mapsize == 0x40 , "Incorrect mapsize"); + u32 highbit; + std::assert(!(highbit & 0x3F) , "Incorrect highbit"); + u32 count; + std::assert(!((highbit > 0) && (count == 0)) , "Incorrect bitmap"); + extensible_bitmap_node node[count]; +}; + + +struct type_set { + extensible_bitmap types; + extensible_bitmap negset; + u32 flag; +}; + +enum expression_types: u32 { + not = 1, + and = 2, + or = 3, + attr = 4, + names = 5, +}; + +struct expression { + expression_types type_; + u32 attribute; + u32 operator; + if (type_ == expression_types::names) { + extensible_bitmap names; + if ((type_g == policy_types::kernel && version >= 29) || + (type_g != policy_types::kernel)) + type_set type_names; + } +}; + +struct constraint { + u32 permissions; + list [[inline]]; +}; + +struct mls_range { + u32 items; + u32 sensitivity0; + if (items > 1) + u32 sensitivity1; + extensible_bitmap category0; + if (items > 1) + extensible_bitmap category1; +}; + +struct role_set { + extensible_bitmap roles; + u32 flags; +}; + +struct mls_level { + u32 sensitivity; + extensible_bitmap category; +}; + +struct semantic_category { + u32 low; + u32 high; +}; + +struct mls_semantic_level { + u32 sensitivity; + list [[inline]]; +}; + +struct mls_semantic_range { + mls_semantic_level level0; + mls_semantic_level level1; +}; + + +struct context_s { + u32 user; + u32 role; + u32 type_; + if (((type_g == policy_types::kernel) && (version >= 19)) || ((type_g == policy_types::base) && (version >= 5))) + mls_range mls_range; +}; + + +struct common { + u32 length; + u32 value; + u32 primary_names_count; + u32 elements_count; + char key[length]; + permission permission[elements_count]; +}; +using commons = symbols_list; + +struct class { + u32 key_length; + u32 common_key_length; + u32 value; + u32 primary_names_count; + u32 elements_count; + u32 constraints_count; + char key[key_length]; + char common_key[common_key_length]; + permission permissions[elements_count]; + constraint constraints[constraints_count]; + if (((type_g == policy_types::kernel) && (version >= 19)) || (type_g == policy_types::base && version >= 5)) + u32 validatetrans_count; + if ((type_g == policy_types::kernel && version >= 19) || (type_g == policy_types::base && version >= 5)) + constraint validatetrans[validatetrans_count]; + if ((type_g == policy_types::kernel && version >= 27) || (type_g == policy_types::base && version >= 15)) { + u32 default_user; + u32 default_role; + u32 default_range; + } + if ((type_g == policy_types::kernel && version >= 28) || (type_g == policy_types::base && version >= 16)) + u32 default_type; +}; +using classes = symbols_list; + + +struct role_s { + u32 length; + u32 value; + u32 bounds; + char key[length]; + extensible_bitmap dominates; + if (type_g == policy_types::kernel) + extensible_bitmap types; + else + type_set types; + if ((type_g != policy_types::kernel && version >= 13)) { + u32 flavor; + extensible_bitmap roles; + } +}; +using roles = symbols_list; + + +struct type_s { + u32 length; + u32 value; + if ((boundary_feature && (type_g != policy_types::kernel && version >= 10)) || !boundary_feature) + u32 primary; + if (boundary_feature) { + u32 properties; + u32 bounds; + } + if (!boundary_feature && (type_g != policy_types::kernel)) + u32 flavor; + if (!boundary_feature && (type_g != policy_types::kernel && version >= 8)) + u32 flags; + if (type_g != policy_types::kernel) + extensible_bitmap types; + char key[length]; +}; +struct types_s { + u32 primary_names_count; + type_primary_names_count = primary_names_count; + list [[inline]]; +}; + +struct user_s { + u32 length; + u32 value; + if (boundary_feature) + u32 bounds; + char key[length]; + + if (type_g == policy_types::kernel) + extensible_bitmap roles; + else + role_set roles; + + if ((type_g == policy_types::kernel && version >= 19) || (type_g == policy_types::module && version >= 5 && version < 6) || (type_g == policy_types::base && version >= 5 && version < 6)) { + mls_range exp_range; + mls_level exp_dftlevel; + } + + if ((type_g == policy_types::module || type_g == policy_types::base) && (version >= 6)) { + mls_semantic_range range; + mls_semantic_range dfltlevel; + } +}; +using users = symbols_list; + +struct bool_ { // conditional boolean + u32 value; + u32 state; + u32 length; + char key[length]; + if ((type_g != policy_types::kernel && version >= 14)) + u32 flags; +}; +using bools = symbols_list; + +struct level { + u32 length; + u32 isalias; + char key[length]; + mls_level level; +}; +using sensitivity_levels = symbols_list; + +struct category { + u32 length; + u32 value; + u32 isalias; + char key[length]; +}; +using categories = symbols_list; + + +struct symbols { + commons commons; + classes classes; + roles roles; + types_s types; + users users; + if (symbols_count >= 6) + bools bools; + if (symbols_count >= 7) + sensitivity_levels levels; + if (symbols_count >= 8) + categories cats; +}; + +struct module_header { + u32 name_length; + std::assert(name_length >= 1, "Invalid 'name_length' in module header."); + char name[name_length]; + u32 version_length; + std::assert(version_length >= 1, "Invalid 'version_length' in module header."); + char version[version_length]; +}; + + +struct access_vector_old { + u32 total; + u32 source_type; + u32 target_type; + u32 target_class; + u32 value; + u32 data[8]; +}; +struct access_vector { + u16 source_type; + u16 target_type; + u16 target_class; + u16 specified; + + if ((specified & 0x700) != 0) { + u8 xperms_specified; + u8 xperms_drivers; + u32 xperms_perms[8]; + } + else + u32 data; +}; + + + +struct avrule_item { + u32 tclass; + u32 data; +}; +struct avrule { + u32 specified; + u32 flags; + type_set stypes; + type_set ttypes; + + u32 length; + avrule_item avrule_item[length]; + + if ((specified & (0x0100 | 0x0200 | 0x0400 | 0x0800)) != 0) { + u8 xperms_specified; + u8 xperms_driver; + + list perms[[inline]]; + } +}; +struct avrule_list { + u32 length; + avrule avrule[length]; +}; + + +struct conditional_node_item { + u32 expr_type; + u32 boolean; +}; + +struct access_vector_table_s { + if (version < 20) + list access_vector_table; + else + list access_vector_table; +} [[inline]]; + +using cond_av_list = access_vector_table_s; + +struct conditional_node { + u32 current_state; + u32 length; + conditional_node_item item[length]; + + if (type_g == policy_types::kernel) { + cond_av_list true_list; + cond_av_list false_list; + } else { + avrule_list avtrue_list; + avrule_list avfalse_list; + if (version >= 14) + u32 flags; + } +}; +struct conditional_list { + u32 length; + conditional_node conditional_node[length]; +}; + + +struct role_trans_item { + u32 role; + u32 type_; + u32 new_role; + if (type_g == policy_types::kernel && version >= 26) + u32 tclass; +}; +using role_trans = list; + +struct role_allow_item { + u32 role; + u32 new_role; +}; +using role_allow = list; + +struct filename_trans_item_old { + u32 length; + char name[length]; + u32 stype; + u32 ttype; + u32 tclass; + u32 otype; +}; +struct filename_trans_item_item { + extensible_bitmap stypes; + u32 otype; +}; +struct filename_trans_item { + u32 length; + char name[length]; + u32 ttype; + u32 tclass; + list types [[inline]]; +}; + + +struct role_trans_rule_item { + role_set roles; + role_set types; + if (version >= 12) + extensible_bitmap classes; + u32 new_role; +}; +using role_trans_rule = list; + +struct role_allow_rule_item { + role_set roles; + role_set new_roles; +}; +using role_allow_rule = list; + + +struct scope_s { + u32 length; + char key[length]; + + u32 scope; + + u32 decl_ids_len; + std::assert(decl_ids_len >= 1, "Invalid 'decl_ids_len'"); + u32 decl_id[decl_ids_len]; +}; +struct scope_index { + extensible_bitmap scope[symbols_count]; + u32 class_perms_len; + extensible_bitmap class_perms_map[class_perms_len]; +}; +using scope_list = list; + + +struct filename_trans_rule_item { + u32 length; + char name[length]; + type_set stypes; + type_set ttypes; + u32 tclass; + u32 otype; + + if (version >= 21) + u32 flags; +}; +using filename_trans_rule = list; + + +struct range_trans_rule_item { + type_set stypes; + type_set ttypes; + extensible_bitmap tclasses; + mls_semantic_range trange; +}; +using range_trans_rule = list; + +struct avrule_decl { + u32 decl_id; + u32 enabled; + conditional_list cond_list; + avrule_list avrules; + role_trans_rule role_tr_rules; + role_allow_rule role_allow_rules; + + if (version >= 11) + filename_trans_rule filename_trans_rules; + + if (version >= 6) + range_trans_rule range_tr_rules; + scope_index required; + scope_index declared; + symbols symbols; +}; + +struct avrule_block_item { + u32 num_decls; + if (num_decls > 0) + avrule_decl avrule_decl[num_decls]; +}; +using avrule_block = list; + + +struct initial_sid { + u32 sid0; + context_s context0; +}; +struct filesystem { + u32 length; + char key[length]; + context_s context0; + context_s context1; +}; +struct port { + u32 protocol; + u32 low_port; + u32 high_port; + context_s context; +}; +struct node { + u32 addr; + u32 mask; + context_s context; +}; +struct fsuse { + u32 behavior; + u32 length; + char name[length]; + context_s context; +}; +struct node6 { + u32 addr[4]; + u32 mask[4]; + context_s context; +}; +struct ibpkey { + u32 low_pkey; + u32 high_pkey; + context_s context; +}; +struct ibpendport { + u32 length; + u32 port; + char dev_name[length]; + context_s context; +}; + + +struct ocontext_selinux { + if (object_contexts_count < 1) break; + list initial_sids; + if (object_contexts_count < 2) break; + list filesystems; + if (object_contexts_count < 3) break; + list ports; + if (object_contexts_count < 4) break; + list network_interfaces; // same type + if (object_contexts_count < 5) break; + list nodes; + if (object_contexts_count < 6) break; + list fsuses; + if (object_contexts_count < 7) break; + list nodes6; + if (object_contexts_count < 8) break; + list ibpkeys; + if (object_contexts_count < 9) break; + list ibpendports; +}; + + +struct xen_isid { + u32 sid0; + context_s context0; +}; + +struct xen_pirq { + u32 pirq; + context_s context0; +}; + +struct xen_ioport { + u32 low_port; + u32 high_port; + context_s context0; +}; + +struct xen_iomem { + if (version >= 30) { + u64 low_iomem; + u64 high_iomem; + } else { + u32 low_iomem; + u32 high_iomem; + } + context_s context; +}; + +struct xen_pcidevice { + u32 device; + context_s context; +}; + +struct xen_devicetree { + u32 length; + char name[length]; + context_s context; +}; + + +struct ocontext_xen { + if (object_contexts_count < 1) break; + list xen_isids; + if (object_contexts_count < 2) break; + list xen_pirqs; + if (object_contexts_count < 3) break; + list xen_ioports; + if (object_contexts_count < 4) break; + list xen_iomems; + if (object_contexts_count < 5) break; + list xen_pcidevices; + if (object_contexts_count < 6) break; + list xen_devicetrees; + if (object_contexts_count < 7) break; +}; + + +struct genfs2_item { + u32 length; + char name[length]; + u32 sclass; + context_s context0; +}; +struct genfs_item { + u32 length; + char fstype[length]; + list [[inline]]; +}; + +struct range_item { + u32 source_type; + u32 target_type; + if (type_g == policy_types::kernel && version >= 21) + u32 target_class; + mls_range range_tr; +}; + +struct Header { + magics magic; + std::assert(magic == magics::kernel || magic == magics::module , "Unexpected magic"); + u32 policydb_str_len; + char policydb_str[policydb_str_len]; + std::assert(policydb_str == "SE Linux" || policydb_str == "SE Linux Module" || policydb_str == "XenFlask", "Unexpected signature"); + if (policydb_str == "XenFlask") + target = targets::xen; + else + target = targets::selinux; + std::assert((magic == magics::kernel && (policydb_str == "SE Linux" || policydb_str == "XenFlask")) + || (magic == magics::module && policydb_str == "SE Linux Module"), "Non matching magic and signature"); + if (magic == magics::module) + u32 policy_subtype; + if (magic == magics::kernel) + type_g = policy_types::kernel; + else + if (policy_subtype == policy_types::module) + type_g = policy_types::module; + else + type_g = policy_types::base; + u32 __policyvers; + version = __policyvers; + boundary_feature = (type_g == policy_types::kernel && version >= 24) || (type_g != policy_types::kernel && version >= 9); + std::assert((magic == magics::kernel && 15 <= version && version <= 33) || (magic != magics::kernel && 4 <= version && version <= 21), "Non matching type_g != and type"); + u32 config; + u32 symbols_count_; + symbols_count = symbols_count_; + std::assert(0 <= symbols_count && symbols_count <= 9, "Invalid 'symbols_count' value."); + u32 object_contexts_count_; + object_contexts_count = object_contexts_count_; + std::assert(0 <= object_contexts_count && object_contexts_count <= 9, "Invalid 'object_contexts_count' value."); + if (magic == magics::module) + module_header module_header; + + if ((type_g == policy_types::kernel && version >= 22) || (version >= 7)) + extensible_bitmap policycaps; + if (type_g == policy_types::kernel && version >= 23) + extensible_bitmap permissive_map; + symbols symbols; + if (type_g == policy_types::kernel) { + access_vector_table_s access_vector_table; + } + if (type_g == policy_types::kernel && version >= 16) + conditional_list conditional_list; + if (type_g == policy_types::kernel) { + role_trans role_trans; + role_allow role_allow; + if (version >= 25) { + if (version < 33) + list filename_trans; + else + list filename_trans; + } + } else { + list avrule_block; + list scope_list[symbols_count]; + } + if (target == targets::selinux) + ocontext_selinux ocontext_selinux; + else + ocontext_xen ocontext_xen; + list genfs; + if (((type_g == policy_types::kernel) && (version >= 19)) || ((type_g == policy_types::base) && (version == 5))) + list range; + if (type_g == policy_types::kernel) + extensible_bitmap type_attr_map[type_primary_names_count]; +}; + + +Header header @ 0; diff --git a/patterns/selinuxpp.hexpat b/patterns/selinuxpp.hexpat new file mode 100644 index 0000000..ad08786 --- /dev/null +++ b/patterns/selinuxpp.hexpat @@ -0,0 +1,28 @@ +// SE Linux Policy Package +// Extension: PP +// https://github.com/SELinuxProject/selinux/blob/master/libsepol/src/module.c + +#pragma endian little +#include + +enum section_types : u32 { + file_context = 0xf97cff90, + module = 0xf97cff8d, + user = 0x097cff91, + user_extra = 0x097cff92, + netfilter = 0x097cff93, +}; + +struct section_s { + section_types *type : u32; +}; + +struct header_s { + u32 magic; + std::assert(magic == 0xf97cff8f, "invalid magic"); + u32 version; + u32 sections_count; + section_s sections[sections_count]; +}; + +header_s header @ 0x00; diff --git a/tests/patterns/test_data/selinux.hexpat.bin b/tests/patterns/test_data/selinux.hexpat.bin new file mode 100644 index 0000000..26e1cc4 Binary files /dev/null and b/tests/patterns/test_data/selinux.hexpat.bin differ diff --git a/tests/patterns/test_data/selinuxpp.hexpat.pp b/tests/patterns/test_data/selinuxpp.hexpat.pp new file mode 100644 index 0000000..63475a5 Binary files /dev/null and b/tests/patterns/test_data/selinuxpp.hexpat.pp differ