mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
serialization: obfuscate the serialized search paths
We noticed some Swift clients rely on the serialized search paths in the module to find dependencies and droping these paths altogether can lead to build failures like rdar://85840921. This change teaches the serialization to obfuscate the search paths and the deserialization to recover them. This allows clients to keep accessing these paths without exposing them when shipping the module to other users.
This commit is contained in:
@@ -361,6 +361,7 @@ ModuleFile::getModuleName(ASTContext &Ctx, StringRef modulePath,
|
||||
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
|
||||
modulePath.str(), std::move(newBuf), nullptr, nullptr,
|
||||
/*isFramework*/ isFramework, Ctx.SILOpts.EnableOSSAModules,
|
||||
Ctx.SearchPathOpts.DeserializedPathRecoverer,
|
||||
loadedModuleFile);
|
||||
Name = loadedModuleFile->Name.str();
|
||||
return std::move(moduleBuf.get());
|
||||
@@ -999,6 +1000,13 @@ Optional<CommentInfo> ModuleFile::getCommentForDecl(const Decl *D) const {
|
||||
return getCommentForDeclByUSR(USRBuffer.str());
|
||||
}
|
||||
|
||||
void ModuleFile::collectSerializedSearchPath(
|
||||
llvm::function_ref<void(StringRef)> callback) const {
|
||||
for (auto path: Core->SearchPaths) {
|
||||
callback(path.Path);
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleFile::collectBasicSourceFileInfo(
|
||||
llvm::function_ref<void(const BasicSourceFileInfo &)> callback) const {
|
||||
if (Core->SourceFileListData.empty())
|
||||
|
||||
@@ -743,7 +743,8 @@ public:
|
||||
Optional<Fingerprint> loadFingerprint(const IterableDeclContext *IDC) const;
|
||||
void collectBasicSourceFileInfo(
|
||||
llvm::function_ref<void(const BasicSourceFileInfo &)> callback) const;
|
||||
|
||||
void collectSerializedSearchPath(
|
||||
llvm::function_ref<void(StringRef)> callback) const;
|
||||
|
||||
// MARK: Deserialization interface
|
||||
|
||||
|
||||
@@ -84,7 +84,8 @@ static bool enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor,
|
||||
/// Returns true on success.
|
||||
static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
|
||||
SmallVectorImpl<uint64_t> &scratch,
|
||||
ExtendedValidationInfo &extendedInfo) {
|
||||
ExtendedValidationInfo &extendedInfo,
|
||||
PathObfuscator &pathRecoverer) {
|
||||
while (!cursor.AtEndOfStream()) {
|
||||
Expected<llvm::BitstreamEntry> maybeEntry = cursor.advance();
|
||||
if (!maybeEntry) {
|
||||
@@ -119,7 +120,7 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
|
||||
unsigned kind = maybeKind.get();
|
||||
switch (kind) {
|
||||
case options_block::SDK_PATH:
|
||||
extendedInfo.setSDKPath(blobData);
|
||||
extendedInfo.setSDKPath(pathRecoverer.recover(blobData));
|
||||
break;
|
||||
case options_block::XCC:
|
||||
extendedInfo.addExtraClangImporterOption(blobData);
|
||||
@@ -171,7 +172,8 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
|
||||
static ValidationInfo validateControlBlock(
|
||||
llvm::BitstreamCursor &cursor, SmallVectorImpl<uint64_t> &scratch,
|
||||
std::pair<uint16_t, uint16_t> expectedVersion, bool requiresOSSAModules,
|
||||
ExtendedValidationInfo *extendedInfo) {
|
||||
ExtendedValidationInfo *extendedInfo,
|
||||
PathObfuscator &pathRecoverer) {
|
||||
// The control block is malformed until we've at least read a major version
|
||||
// number.
|
||||
ValidationInfo result;
|
||||
@@ -202,7 +204,7 @@ static ValidationInfo validateControlBlock(
|
||||
result.status = Status::Malformed;
|
||||
return result;
|
||||
}
|
||||
if (!readOptionsBlock(cursor, scratch, *extendedInfo)) {
|
||||
if (!readOptionsBlock(cursor, scratch, *extendedInfo, pathRecoverer)) {
|
||||
result.status = Status::Malformed;
|
||||
return result;
|
||||
}
|
||||
@@ -465,10 +467,11 @@ ValidationInfo serialization::validateSerializedAST(
|
||||
result.status = Status::Malformed;
|
||||
return result;
|
||||
}
|
||||
PathObfuscator localObfuscator;
|
||||
result = validateControlBlock(
|
||||
cursor, scratch,
|
||||
{SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR},
|
||||
requiresOSSAModules, extendedInfo);
|
||||
requiresOSSAModules, extendedInfo, localObfuscator);
|
||||
if (result.status == Status::Malformed)
|
||||
return result;
|
||||
} else if (dependencies &&
|
||||
@@ -938,7 +941,7 @@ getActualImportControl(unsigned rawValue) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ModuleFileSharedCore::readModuleDocIfPresent() {
|
||||
bool ModuleFileSharedCore::readModuleDocIfPresent(PathObfuscator &pathRecoverer) {
|
||||
if (!this->ModuleDocInputBuffer)
|
||||
return true;
|
||||
|
||||
@@ -977,7 +980,7 @@ bool ModuleFileSharedCore::readModuleDocIfPresent() {
|
||||
info = validateControlBlock(
|
||||
docCursor, scratch, {SWIFTDOC_VERSION_MAJOR, SWIFTDOC_VERSION_MINOR},
|
||||
RequiresOSSAModules,
|
||||
/*extendedInfo*/ nullptr);
|
||||
/*extendedInfo*/ nullptr, pathRecoverer);
|
||||
if (info.status != Status::Valid)
|
||||
return false;
|
||||
// Check that the swiftdoc is actually for this module.
|
||||
@@ -1083,7 +1086,7 @@ bool ModuleFileSharedCore::readDeclLocsBlock(llvm::BitstreamCursor &cursor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModuleFileSharedCore::readModuleSourceInfoIfPresent() {
|
||||
bool ModuleFileSharedCore::readModuleSourceInfoIfPresent(PathObfuscator &pathRecoverer) {
|
||||
if (!this->ModuleSourceInfoInputBuffer)
|
||||
return true;
|
||||
|
||||
@@ -1121,7 +1124,8 @@ bool ModuleFileSharedCore::readModuleSourceInfoIfPresent() {
|
||||
infoCursor, scratch,
|
||||
{SWIFTSOURCEINFO_VERSION_MAJOR, SWIFTSOURCEINFO_VERSION_MINOR},
|
||||
RequiresOSSAModules,
|
||||
/*extendedInfo*/ nullptr);
|
||||
/*extendedInfo*/ nullptr,
|
||||
pathRecoverer);
|
||||
if (info.status != Status::Valid)
|
||||
return false;
|
||||
// Check that the swiftsourceinfo is actually for this module.
|
||||
@@ -1196,7 +1200,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
|
||||
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
|
||||
std::unique_ptr<llvm::MemoryBuffer> moduleSourceInfoInputBuffer,
|
||||
bool isFramework, bool requiresOSSAModules,
|
||||
serialization::ValidationInfo &info)
|
||||
serialization::ValidationInfo &info, PathObfuscator &pathRecoverer)
|
||||
: ModuleInputBuffer(std::move(moduleInputBuffer)),
|
||||
ModuleDocInputBuffer(std::move(moduleDocInputBuffer)),
|
||||
ModuleSourceInfoInputBuffer(std::move(moduleSourceInfoInputBuffer)),
|
||||
@@ -1247,7 +1251,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
|
||||
info = validateControlBlock(
|
||||
cursor, scratch,
|
||||
{SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR},
|
||||
RequiresOSSAModules, &extInfo);
|
||||
RequiresOSSAModules, &extInfo, pathRecoverer);
|
||||
if (info.status != Status::Valid) {
|
||||
error(info.status);
|
||||
return;
|
||||
@@ -1372,7 +1376,8 @@ ModuleFileSharedCore::ModuleFileSharedCore(
|
||||
bool isSystem;
|
||||
input_block::SearchPathLayout::readRecord(scratch, isFramework,
|
||||
isSystem);
|
||||
SearchPaths.push_back({blobData, isFramework, isSystem});
|
||||
SearchPaths.push_back({pathRecoverer.recover(blobData), isFramework,
|
||||
isSystem});
|
||||
break;
|
||||
}
|
||||
case input_block::MODULE_INTERFACE_PATH: {
|
||||
@@ -1572,8 +1577,8 @@ ModuleFileSharedCore::ModuleFileSharedCore(
|
||||
return;
|
||||
}
|
||||
// Read source info file.
|
||||
readModuleSourceInfoIfPresent();
|
||||
if (!readModuleDocIfPresent()) {
|
||||
readModuleSourceInfoIfPresent(pathRecoverer);
|
||||
if (!readModuleDocIfPresent(pathRecoverer)) {
|
||||
info.status = error(Status::MalformedDocumentation);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ private:
|
||||
SmallVector<Dependency, 8> Dependencies;
|
||||
|
||||
struct SearchPath {
|
||||
StringRef Path;
|
||||
std::string Path;
|
||||
bool IsFramework;
|
||||
bool IsSystem;
|
||||
};
|
||||
@@ -374,7 +374,7 @@ private:
|
||||
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
|
||||
std::unique_ptr<llvm::MemoryBuffer> moduleSourceInfoInputBuffer,
|
||||
bool isFramework, bool requiresOSSAModules,
|
||||
serialization::ValidationInfo &info);
|
||||
serialization::ValidationInfo &info, PathObfuscator &pathRecoverer);
|
||||
|
||||
/// Change the status of the current module.
|
||||
Status error(Status issue) {
|
||||
@@ -464,7 +464,7 @@ private:
|
||||
/// Loads data from #ModuleDocInputBuffer.
|
||||
///
|
||||
/// Returns false if there was an error.
|
||||
bool readModuleDocIfPresent();
|
||||
bool readModuleDocIfPresent(PathObfuscator &pathRecoverer);
|
||||
|
||||
/// Reads the source loc block, which contains USR to decl location mapping.
|
||||
///
|
||||
@@ -474,7 +474,7 @@ private:
|
||||
/// Loads data from #ModuleSourceInfoInputBuffer.
|
||||
///
|
||||
/// Returns false if there was an error.
|
||||
bool readModuleSourceInfoIfPresent();
|
||||
bool readModuleSourceInfoIfPresent(PathObfuscator &pathRecoverer);
|
||||
|
||||
/// Read an on-disk decl hash table stored in
|
||||
/// \c sourceinfo_block::DeclUSRSLayout format.
|
||||
@@ -510,12 +510,13 @@ public:
|
||||
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
|
||||
std::unique_ptr<llvm::MemoryBuffer> moduleSourceInfoInputBuffer,
|
||||
bool isFramework, bool requiresOSSAModules,
|
||||
PathObfuscator &pathRecoverer,
|
||||
std::shared_ptr<const ModuleFileSharedCore> &theModule) {
|
||||
serialization::ValidationInfo info;
|
||||
auto *core = new ModuleFileSharedCore(
|
||||
std::move(moduleInputBuffer), std::move(moduleDocInputBuffer),
|
||||
std::move(moduleSourceInfoInputBuffer), isFramework,
|
||||
requiresOSSAModules, info);
|
||||
requiresOSSAModules, info, pathRecoverer);
|
||||
if (!moduleInterfacePath.empty()) {
|
||||
ArrayRef<char> path;
|
||||
core->allocateBuffer(path, moduleInterfacePath);
|
||||
|
||||
@@ -1077,9 +1077,11 @@ void Serializer::writeHeader(const SerializationOptions &options) {
|
||||
options_block::XCCLayout XCC(Out);
|
||||
|
||||
const auto &PathRemapper = options.DebuggingOptionsPrefixMap;
|
||||
const auto &PathObfuscator = options.PathObfuscator;
|
||||
auto sdkPath = M->getASTContext().SearchPathOpts.SDKPath;
|
||||
SDKPath.emit(
|
||||
ScratchRecord,
|
||||
PathRemapper.remapPath(M->getASTContext().SearchPathOpts.SDKPath));
|
||||
PathObfuscator.obfuscate(PathRemapper.remapPath(sdkPath)));
|
||||
auto &Opts = options.ExtraClangOptions;
|
||||
for (auto Arg = Opts.begin(), E = Opts.end(); Arg != E; ++Arg) {
|
||||
StringRef arg(*Arg);
|
||||
@@ -1157,16 +1159,17 @@ void Serializer::writeInputBlock(const SerializationOptions &options) {
|
||||
input_block::ModuleInterfaceLayout ModuleInterface(Out);
|
||||
|
||||
if (options.SerializeOptionsForDebugging) {
|
||||
const auto &PathObfuscator = options.PathObfuscator;
|
||||
const auto &PathMapper = options.DebuggingOptionsPrefixMap;
|
||||
const SearchPathOptions &searchPathOpts = M->getASTContext().SearchPathOpts;
|
||||
// Put the framework search paths first so that they'll be preferred upon
|
||||
// deserialization.
|
||||
for (auto &framepath : searchPathOpts.FrameworkSearchPaths)
|
||||
SearchPath.emit(ScratchRecord, /*framework=*/true, framepath.IsSystem,
|
||||
PathMapper.remapPath(framepath.Path));
|
||||
PathObfuscator.obfuscate(PathMapper.remapPath(framepath.Path)));
|
||||
for (auto &path : searchPathOpts.ImportSearchPaths)
|
||||
SearchPath.emit(ScratchRecord, /*framework=*/false, /*system=*/false,
|
||||
PathMapper.remapPath(path));
|
||||
PathObfuscator.obfuscate(PathMapper.remapPath(path)));
|
||||
}
|
||||
|
||||
// Note: We're not using StringMap here because we don't need to own the
|
||||
|
||||
@@ -404,7 +404,9 @@ llvm::ErrorOr<ModuleDependencies> SerializedModuleLoaderBase::scanModuleFile(
|
||||
bool isFramework = false;
|
||||
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
|
||||
modulePath.str(), std::move(moduleBuf.get()), nullptr, nullptr,
|
||||
isFramework, isRequiredOSSAModules(), loadedModuleFile);
|
||||
isFramework, isRequiredOSSAModules(),
|
||||
Ctx.SearchPathOpts.DeserializedPathRecoverer,
|
||||
loadedModuleFile);
|
||||
|
||||
const std::string moduleDocPath;
|
||||
const std::string sourceInfoPath;
|
||||
@@ -730,7 +732,9 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
|
||||
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
|
||||
moduleInterfacePath, std::move(moduleInputBuffer),
|
||||
std::move(moduleDocInputBuffer), std::move(moduleSourceInfoInputBuffer),
|
||||
isFramework, isRequiredOSSAModules(), loadedModuleFileCore);
|
||||
isFramework, isRequiredOSSAModules(),
|
||||
Ctx.SearchPathOpts.DeserializedPathRecoverer,
|
||||
loadedModuleFileCore);
|
||||
SerializedASTFile *fileUnit = nullptr;
|
||||
|
||||
if (loadInfo.status == serialization::Status::Valid) {
|
||||
@@ -1555,3 +1559,8 @@ void SerializedASTFile::collectBasicSourceFileInfo(
|
||||
llvm::function_ref<void(const BasicSourceFileInfo &)> callback) const {
|
||||
File.collectBasicSourceFileInfo(callback);
|
||||
}
|
||||
|
||||
void SerializedASTFile::collectSerializedSearchPath(
|
||||
llvm::function_ref<void(StringRef)> callback) const {
|
||||
File.collectSerializedSearchPath(callback);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user