Loading...
other-tools/os_macho_rules.cpp dyld-1340 /dev/null
--- dyld/dyld-1340/other-tools/os_macho_rules.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2024 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-// OS
-#include <TargetConditionals.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <uuid/uuid.h>
-#include <mach-o/dyld_introspection.h>
-#include <mach-o/dyld_priv.h>
-#include <SoftLinking/WeakLinking.h>
-
-// STL
-#include <vector>
-#include <tuple>
-#include <set>
-#include <unordered_set>
-#include <string>
-
-// mach_o
-#include "Header.h"
-#include "Version32.h"
-#include "Universal.h"
-#include "Architecture.h"
-#include "Image.h"
-#include "Error.h"
-#include "SplitSeg.h"
-#include "ChainedFixups.h"
-#include "FunctionStarts.h"
-#include "Misc.h"
-#include "Instructions.h"
-#include "FunctionVariants.h"
-
-// common
-#include "Defines.h"
-#include "FileUtils.h"
-
-// other_tools
-#include "MiscFileUtils.h"
-#include "os_macho_rules.h"
-
-using mach_o::Header;
-using mach_o::Version32;
-using mach_o::Image;
-using mach_o::Fixup;
-using mach_o::Symbol;
-using mach_o::Platform;
-using mach_o::PlatformAndVersions;
-using mach_o::ChainedFixups;
-using mach_o::Architecture;
-using mach_o::Error;
-using mach_o::Universal;
-using mach_o::Image;
-
-
-// some binaries are not for customer OS installs, so need less checks done
-static bool debugVariantPath(CString path)
-{
-    static CString debugSuffixes[] = { "_asan.dylib", "_asan", "_debug.dylib", "_debug", "_profile", "_profile.dylib",
-                                       "_trace", "_trace.dylib", "_tsan", "_tsan.dylib", "_ubsan" , "_ubsan.dylib" };
-    for (CString suffix : debugSuffixes) {
-        if ( path.ends_with(suffix) )
-            return true;
-    }
-    return false;
-}
-
-static void verifyOSDylibInstallName(const Image& image, CString installLocationInDstRoot, CString verifierDstRoot, std::vector<VerifierError>& errors)
-{
-    // Don't allow @rpath to be used as -install_name for OS dylibs
-    CString installName = image.header()->installName();
-    if ( installName.starts_with("@rpath/") ) {
-        errors.emplace_back("os_dylib_rpath_install_name");
-        errors.back().message = Error("-install_name uses @rpath in arch %s", image.header()->archName());
-    }
-    else if ( installName.contains("//") ) {
-        errors.emplace_back("os_dylib_bad_install_name");
-        errors.back().message = Error("-install_name does not match install location in arch %s", image.header()->archName());
-    }
-    else {
-        // Verify -install_name matches actual path of dylib
-        if ( installLocationInDstRoot != installName ) {
-            // see if install name is a symlink to actual file
-            bool symlinkToDylib = false;
-            char absDstRootPath[PATH_MAX];
-            if ( ::realpath(verifierDstRoot.c_str(), absDstRootPath) != nullptr ) {
-                char fullInstallNamePath[PATH_MAX];
-                strlcpy(fullInstallNamePath, absDstRootPath, PATH_MAX);
-                strlcat(fullInstallNamePath, installName.c_str(), PATH_MAX);
-                char absInstallNamePath[PATH_MAX];
-                if ( ::realpath(fullInstallNamePath, absInstallNamePath) != NULL ) {
-                    char fullLocationName[PATH_MAX];
-                    strlcpy(fullLocationName, absDstRootPath, PATH_MAX);
-                    strlcat(fullLocationName, installLocationInDstRoot.c_str(), PATH_MAX);
-                    char absFullLocationNamePath[PATH_MAX];
-                    if ( ::realpath(fullLocationName, absFullLocationNamePath) != NULL ) {
-                        if ( strcmp(absInstallNamePath, absFullLocationNamePath) == 0 )
-                            symlinkToDylib = true;
-                    }
-                }
-            }
-            if ( !symlinkToDylib ) {
-                errors.emplace_back("os_dylib_bad_install_name");
-                errors.back().message = Error("-install_name does not match install location in arch %s", image.header()->archName());
-            }
-        }
-    }
-}
-
-static void verifyOSDylibNoRpaths(const Image& image, std::vector<VerifierError>& errors)
-{
-    // Don't allow OS dylibs to add rpaths
-    __block bool definesRPaths = false;
-    image.header()->forEachRPath(^(const char* rPath, bool& stop) {
-        definesRPaths = true;
-    });
-    if ( definesRPaths ) {
-        errors.emplace_back("os_dylib_rpath");
-        errors.back().message = Error("contains LC_RPATH load command in arch %s", image.header()->archName());
-    }
-}
-
-static void verifyOSDylibNotMergeable(const Image& image, std::vector<VerifierError>& errors)
-{
-    // Don't allow OS dylibs to have mergable info by default
-    uint32_t aiFileOffset;
-    uint32_t aiSize;
-    if ( image.header()->hasAtomInfo(aiFileOffset, aiSize) ) {
-        bool allowAtomInfo = false;
-        // rdar://136999565 (Teach mach-o verifier about LC_ATOM_INFO)
-#if LD_DEFAULT_ADD_MERGEABLE_METADATA
-        allowAtomInfo = true;
-#endif
-        if ( getenv("LD_DEFAULT_ADD_MERGEABLE_METADATA") != nullptr )
-            allowAtomInfo = true;
-        if ( !allowAtomInfo ) {
-            errors.emplace_back("os_dylib_mergeable");
-            errors.back().message = Error("is a mergable dylib for arch %s", image.header()->archName());
-        }
-    }
-}
-
-static void verifyOSDylibDoesNotExportMain(const Image& image, std::vector<VerifierError>& errors)
-{
-    if ( image.hasExportsTrie() ) {
-        Symbol symbol;
-        if ( image.exportsTrie().hasExportedSymbol("_main", symbol) ) {
-            errors.emplace_back("os_dylib_exports_main");
-            errors.back().message = Error("dylibs should not export '_main' symbol in arch %s", image.header()->archName());
-        }
-    }
-}
-
-static void verifyNoFlatLookups(const Image& image, std::vector<VerifierError>& errors)
-{
-    if ( !image.header()->usesTwoLevelNamespace() ) {
-        errors.emplace_back("os_dylib_flat_namespace");
-        errors.back().message = Error("built with -flat_namespace in arch %s", image.header()->archName());
-        return;
-    }
-
-    if ( image.hasChainedFixups() ) {
-        Error err = image.chainedFixups().forEachBindTarget(^(int libOrdinal, const char* symbolName, int64_t addend, bool weakImport, bool& stop) {
-            if ( libOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) {
-                errors.emplace_back("os_dylib_undefined_dynamic_lookup");
-                errors.back().message = Error("built with -undefined dynamic_lookup for symbol %s in arch %s", symbolName, image.header()->archName());
-            }
-        });
-    }
-    else if ( image.hasSymbolTable() ) {
-        image.symbolTable().forEachUndefinedSymbol(^(const Symbol& symbol, uint32_t symbolIndex, bool& stop) {
-            int   libOrdinal;
-            bool  weakImport;
-            if ( symbol.isUndefined(libOrdinal, weakImport) ) {
-                if ( (uint8_t)libOrdinal == DYNAMIC_LOOKUP_ORDINAL ) {
-                    errors.emplace_back("os_dylib_undefined_dynamic_lookup");
-                    errors.back().message = Error("built with -undefined dynamic_lookup for symbol %s in arch %s", symbol.name().c_str(), image.header()->archName());
-                }
-            }
-        });
-    }
-}
-
-static void verifyiOSMac(const Image& image, CString installLocationInDstRoot, std::vector<VerifierError>& errors)
-{
-    if ( installLocationInDstRoot.starts_with("/System/iOSSupport/") ) {
-        // everything in /System/iOSSupport/ should be iOSMac only
-        PlatformAndVersions pvs = image.header()->platformAndVersions();
-        if ( pvs.platform != Platform::macCatalyst ) {
-            errors.emplace_back("macos_in_ios_support");
-            errors.back().message = Error("non-catalyst in /System/iOSSupport/ in arch %s", image.header()->archName());
-        }
-    }
-    else {
-        // maybe some day warn about iOSMac only stuff not in /System/iOSSupport/
-    }
-}
-
-static void checkDylib(const Image& image, CString installLocationInDstRoot, CString verifierDstRoot, std::vector<VerifierError>& errors)
-{
-    if ( Header::isSharedCacheEligiblePath(installLocationInDstRoot.c_str()) ) {
-        verifyOSDylibInstallName(image, installLocationInDstRoot, verifierDstRoot, errors);
-        verifyOSDylibNoRpaths(image, errors);
-        verifyOSDylibDoesNotExportMain(image, errors);
-        verifyOSDylibNotMergeable(image, errors);
-    }
-}
-
-// used by machocheck tool and by unit tests
-void os_macho_verifier(CString path, std::span<const uint8_t> buffer, CString verifierDstRoot,
-                       const std::vector<CString>& mergeRootPaths, std::vector<VerifierError>& errors)
-{
-    Image image(buffer.data(), buffer.size(), Image::MappingKind::wholeSliceMapped);
-    if ( Error err = image.validate() ) {
-        errors.emplace_back("os_dylib_malformed");
-        errors.back().message = std::move(err);
-        return;
-    }
-
-    // don't run checks on dylibs that will not be in customer OS installs
-    if ( debugVariantPath(path) )
-        return;
-
-    // don't run checks on dylibs that are embedded in an app bundle
-    if ( path.contains(".app/") )
-        return;
-
-    // dylib specific checks
-    if ( path.starts_with(verifierDstRoot) ) {
-        CString installLocationInDstRoot = path.substr(verifierDstRoot.size());
-        if ( image.header()->isDylib() ) {
-            if ( mergeRootPaths.empty() ) {
-                checkDylib(image, installLocationInDstRoot, verifierDstRoot, errors);
-            }
-            else {
-                // merge roots are when the project puts the binary in $DSTROOT/usr/lib,
-                // but B&I moves it to /Applications/Xcode.app/Content/Toolchains/Foo.xctoolchain/usr/lib
-                for (CString mergeRoot : mergeRootPaths) {
-                    char fullerPath[PATH_MAX];
-                    strlcpy(fullerPath, mergeRoot.c_str(), PATH_MAX);
-                    strlcat(fullerPath, installLocationInDstRoot.c_str(), PATH_MAX);
-                    checkDylib(image, fullerPath, verifierDstRoot, errors);
-                }
-            }
-        }
-        verifyiOSMac(image, installLocationInDstRoot, errors);
-    }
-    verifyNoFlatLookups(image, errors);
-}
-
-
-
-
-
-