+bool SecStaticCode::checkfix30814861(string path, bool addition) {
+ // <rdar://problem/30814861> v2 resource rules don't match v1 resource rules
+
+ //// Condition 1: Is the app an iOS app that was built with an SDK lower than 9.0?
+
+ // We started signing correctly in 2014, 9.0 was first seeded mid-2016.
+
+ CFRef<CFDictionaryRef> inf = diskRepInformation();
+ try {
+ CFDictionary info(diskRepInformation(), errSecCSNotSupported);
+ uint32_t platform =
+ cfNumber(info.get<CFNumberRef>(kSecCodeInfoDiskRepVersionPlatform, errSecCSNotSupported), 0);
+ uint32_t sdkVersion =
+ cfNumber(info.get<CFNumberRef>(kSecCodeInfoDiskRepVersionSDK, errSecCSNotSupported), 0);
+
+ if (platform != PLATFORM_IOS || sdkVersion >= 0x00090000) {
+ return false;
+ }
+ } catch (const MacOSError &error) {
+ return false;
+ }
+
+ //// Condition 2: Is it a .sinf/.supf/.supp file at the right location?
+
+ static regex_t pathre_sinf;
+ static regex_t pathre_supp_supf;
+ static dispatch_once_t once;
+
+ dispatch_once(&once, ^{
+ os_assert_zero(regcomp(&pathre_sinf,
+ "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|())SC_Info/[^/]+\\.sinf$",
+ REG_EXTENDED | REG_NOSUB));
+ os_assert_zero(regcomp(&pathre_supp_supf,
+ "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|())SC_Info/[^/]+\\.(supf|supp)$",
+ REG_EXTENDED | REG_NOSUB));
+ });
+
+ // .sinf is added, .supf/.supp are modified.
+ const regex_t &pathre = addition ? pathre_sinf : pathre_supp_supf;
+
+ const int result = regexec(&pathre, path.c_str(), 0, NULL, 0);
+
+ if (result == REG_NOMATCH) {
+ return false;
+ } else if (result != 0) {
+ // Huh?
+ secerror("unexpected regexec result %d for path '%s'", result, path.c_str());
+ return false;
+ }
+
+ //// Condition 3: Do the v1 rules actually exclude the file?
+
+ dispatch_once(&mCheckfix30814861builder1_once, ^{
+ // Create the v1 resource builder lazily.
+ CFDictionaryRef rules1 = cfget<CFDictionaryRef>(resourceDictionary(), "rules");
+ const string base = cfString(resourceBase());
+
+ mCheckfix30814861builder1 = new ResourceBuilder(base, base, rules1, false, mTolerateErrors);
+ });
+
+ ResourceBuilder::Rule const * const matchingRule = mCheckfix30814861builder1->findRule(path);
+
+ if (matchingRule == NULL || !(matchingRule->flags & ResourceBuilder::omitted)) {
+ return false;
+ }
+
+ //// All matched, this file is a check-fixed sinf/supf/supp.
+
+ return true;
+
+}