Skip to content

Commit 26fc627

Browse files
authored
Fix a use-after-free bug on Win32 when calling lookupSymbol() (#62484)
1 parent 0b74e7b commit 26fc627

14 files changed

+243
-141
lines changed

stdlib/public/core/KeyPath.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,8 +3893,15 @@ internal func _instantiateKeyPathBuffer(
38933893

38943894
#if SWIFT_ENABLE_REFLECTION
38953895

3896-
@_silgen_name("swift_keyPath_dladdr")
3897-
fileprivate func keypath_dladdr(_: UnsafeRawPointer) -> UnsafePointer<CChar>?
3896+
@_silgen_name("swift_keyPath_copySymbolName")
3897+
fileprivate func keyPath_copySymbolName(
3898+
_: UnsafeRawPointer
3899+
) -> UnsafePointer<CChar>?
3900+
3901+
@_silgen_name("swift_keyPath_freeSymbolName")
3902+
fileprivate func keyPath_freeSymbolName(
3903+
_: UnsafePointer<CChar>?
3904+
) -> Void
38983905

38993906
@_silgen_name("swift_keyPathSourceString")
39003907
fileprivate func demangle(
@@ -3908,7 +3915,10 @@ fileprivate func dynamicLibraryAddress<Base, Leaf>(
39083915
) -> String {
39093916
let getter: ComputedAccessorsPtr.Getter<Base, Leaf> = pointer.getter()
39103917
let pointer = unsafeBitCast(getter, to: UnsafeRawPointer.self)
3911-
if let cString = keypath_dladdr(UnsafeRawPointer(pointer)) {
3918+
if let cString = keyPath_copySymbolName(UnsafeRawPointer(pointer)) {
3919+
defer {
3920+
keyPath_freeSymbolName(cString)
3921+
}
39123922
if let demangled = demangle(name: cString)
39133923
.map({ pointer in
39143924
defer {

stdlib/public/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ set(swift_runtime_sources
5454
ImageInspectionCOFF.cpp
5555
ImageInspectionStatic.cpp
5656
ImageInspectionWasm.cpp
57+
SymbolInfo.cpp
5758
KeyPaths.cpp
5859
KnownMetadata.cpp
5960
Metadata.cpp

stdlib/public/runtime/Errors.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
8383
std::string &symbolName, uintptr_t &addrOut) {
8484
// If we failed to find a symbol and thus dlinfo->dli_sname is nullptr, we
8585
// need to use the hex address.
86-
bool hasUnavailableAddress = syminfo.symbolName == nullptr;
86+
bool hasUnavailableAddress = syminfo.getSymbolName() == nullptr;
8787

8888
if (hasUnavailableAddress) {
8989
return false;
9090
}
9191

9292
// Ok, now we know that we have some sort of "real" name. Set the outAddr.
93-
addrOut = uintptr_t(syminfo.symbolAddress);
93+
addrOut = uintptr_t(syminfo.getSymbolAddress());
9494

9595
// First lets try to demangle using cxxabi. If this fails, we will try to
9696
// demangle with swift. We are taking advantage of __cxa_demangle actually
@@ -109,7 +109,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
109109
dwFlags |= UNDNAME_32_BIT_DECODE;
110110
#endif
111111

112-
return UnDecorateSymbolName(syminfo.symbolName.get(), szUndName,
112+
return UnDecorateSymbolName(syminfo.getSymbolName(), szUndName,
113113
sizeof(szUndName), dwFlags);
114114
});
115115

@@ -120,7 +120,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
120120
#else
121121
int status;
122122
char *demangled =
123-
abi::__cxa_demangle(syminfo.symbolName.get(), 0, 0, &status);
123+
abi::__cxa_demangle(syminfo.getSymbolName(), 0, 0, &status);
124124
if (status == 0) {
125125
assert(demangled != nullptr &&
126126
"If __cxa_demangle succeeds, demangled should never be nullptr");
@@ -135,7 +135,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
135135
// Otherwise, try to demangle with swift. If swift fails to demangle, it will
136136
// just pass through the original output.
137137
symbolName = demangleSymbolAsString(
138-
syminfo.symbolName.get(), strlen(syminfo.symbolName.get()),
138+
syminfo.getSymbolName(), strlen(syminfo.getSymbolName()),
139139
Demangle::DemangleOptions::SimplifiedUIDemangleOptions());
140140
return true;
141141
}
@@ -155,7 +155,7 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
155155
// library name here. Avoid using StringRef::rsplit because its definition
156156
// is not provided in the header so that it requires linking with
157157
// libSupport.a.
158-
llvm::StringRef libraryName{syminfo.fileName};
158+
llvm::StringRef libraryName{syminfo.getFilename()};
159159
libraryName = libraryName.substr(libraryName.rfind('/')).substr(1);
160160

161161
// Next we get the symbol name that we are going to use in our backtrace.
@@ -170,7 +170,8 @@ void swift::dumpStackTraceEntry(unsigned index, void *framePC,
170170
if (foundSymbol) {
171171
offset = ptrdiff_t(uintptr_t(framePC) - symbolAddr);
172172
} else {
173-
offset = ptrdiff_t(uintptr_t(framePC) - uintptr_t(syminfo.baseAddress));
173+
auto baseAddress = syminfo.getBaseAddress();
174+
offset = ptrdiff_t(uintptr_t(framePC) - uintptr_t(baseAddress));
174175
symbolAddr = uintptr_t(framePC);
175176
symbolName = "<unavailable>";
176177
}

stdlib/public/runtime/ImageInspection.h

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,38 +35,9 @@
3535
#include <Windows.h>
3636
#endif
3737

38-
namespace swift {
38+
#include "SymbolInfo.h"
3939

40-
/// This is a platform independent version of Dl_info from dlfcn.h
41-
#if defined(__cplusplus)
42-
43-
template <typename T>
44-
struct null_deleter {
45-
void operator()(T *) const {}
46-
void operator()(typename std::remove_cv<T>::type *value) const {}
47-
};
48-
49-
template <typename T>
50-
struct free_deleter {
51-
void operator()(T *value) const {
52-
free(const_cast<typename std::remove_cv<T>::type *>(value));
53-
}
54-
void operator()(typename std::remove_cv<T>::type *value) const {
55-
free(value);
56-
}
57-
};
58-
59-
struct SymbolInfo {
60-
const char *fileName;
61-
void *baseAddress;
62-
#if defined(_WIN32)
63-
std::unique_ptr<const char, free_deleter<const char>> symbolName;
64-
#else
65-
std::unique_ptr<const char, null_deleter<const char>> symbolName;
66-
#endif
67-
void *symbolAddress;
68-
};
69-
#endif
40+
namespace swift {
7041

7142
/// Load the metadata from the image necessary to find protocols by name.
7243
void initializeProtocolLookup();
@@ -112,8 +83,6 @@ void addImageAccessibleFunctionsBlockCallbackUnsafe(const void *baseAddress,
11283
const void *start,
11384
uintptr_t size);
11485

115-
int lookupSymbol(const void *address, SymbolInfo *info);
116-
11786
#if defined(_WIN32)
11887
/// Configure the environment to allow calling into the Debug Help library.
11988
///

stdlib/public/runtime/ImageInspectionCOFF.cpp

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,46 +27,6 @@
2727

2828
using namespace swift;
2929

30-
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
31-
#if defined(__CYGWIN__)
32-
Dl_info dlinfo;
33-
if (dladdr(address, &dlinfo) == 0) {
34-
return 0;
35-
}
36-
37-
info->fileName = dlinfo.dli_fname;
38-
info->baseAddress = dlinfo.dli_fbase;
39-
info->symbolName = dli_info.dli_sname;
40-
info->symbolAddress = dli_saddr;
41-
return 1;
42-
#elif defined(_WIN32)
43-
return _swift_win32_withDbgHelpLibrary([&] (HANDLE hProcess) {
44-
static const constexpr size_t kSymbolMaxNameLen = 1024;
45-
46-
if (!hProcess) {
47-
return 0;
48-
}
49-
50-
SYMBOL_INFO_PACKAGE symbol = {};
51-
symbol.si.SizeOfStruct = sizeof(SYMBOL_INFO);
52-
symbol.si.MaxNameLen = MAX_SYM_NAME;
53-
if (SymFromAddr(hProcess, reinterpret_cast<const DWORD64>(address),
54-
nullptr, &symbol.si) == FALSE) {
55-
return 0;
56-
}
57-
58-
info->fileName = NULL;
59-
info->baseAddress = reinterpret_cast<void *>(symbol.si.ModBase);
60-
info->symbolName.reset(_strdup(symbol.si.Name));
61-
info->symbolAddress = reinterpret_cast<void *>(symbol.si.Address);
62-
63-
return 1;
64-
});
65-
#else
66-
return 0;
67-
#endif // defined(__CYGWIN__) || defined(_WIN32)
68-
}
69-
7030
#if defined(_WIN32)
7131
static LazyMutex mutex;
7232
static HANDLE dbgHelpHandle = nullptr;

stdlib/public/runtime/ImageInspectionCommon.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ static void fixupMetadataSectionBaseAddress(swift::MetadataSections *sections) {
6565
// We need to fix up the base address. We'll need a known-good address in
6666
// the same image: `sections` itself will work nicely.
6767
swift::SymbolInfo symbolInfo;
68-
if (lookupSymbol(sections, &symbolInfo) && symbolInfo.baseAddress) {
69-
sections->baseAddress.store(symbolInfo.baseAddress,
68+
if (lookupSymbol(sections, &symbolInfo) && symbolInfo.getBaseAddress()) {
69+
sections->baseAddress.store(symbolInfo.getBaseAddress(),
7070
std::memory_order_relaxed);
7171
}
7272
}
@@ -192,8 +192,8 @@ const char *
192192
swift_getMetadataSectionName(const swift::MetadataSections *section) {
193193
swift::SymbolInfo info;
194194
if (lookupSymbol(section, &info)) {
195-
if (info.fileName) {
196-
return info.fileName;
195+
if (info.getFilename()) {
196+
return info.getFilename();
197197
}
198198
}
199199
return "";
@@ -205,7 +205,7 @@ void swift_getMetadataSectionBaseAddress(const swift::MetadataSections *section,
205205
void const **out_expected) {
206206
swift::SymbolInfo info;
207207
if (lookupSymbol(section, &info)) {
208-
*out_actual = info.baseAddress;
208+
*out_actual = info.getBaseAddress();
209209
} else {
210210
*out_actual = nullptr;
211211
}

stdlib/public/runtime/ImageInspectionELF.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,6 @@
2020

2121
#if defined(__ELF__)
2222

23-
#include "swift/shims/MetadataSections.h"
2423
#include "ImageInspection.h"
25-
#include <dlfcn.h>
26-
27-
using namespace swift;
28-
29-
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
30-
Dl_info dlinfo;
31-
if (dladdr(address, &dlinfo) == 0) {
32-
return 0;
33-
}
34-
35-
info->fileName = dlinfo.dli_fname;
36-
info->baseAddress = dlinfo.dli_fbase;
37-
info->symbolName.reset(dlinfo.dli_sname);
38-
info->symbolAddress = dlinfo.dli_saddr;
39-
return 1;
40-
}
4124

4225
#endif // defined(__ELF__)

stdlib/public/runtime/ImageInspectionMachO.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -171,20 +171,5 @@ void swift::initializeAccessibleFunctionsLookup() {
171171
addImageAccessibleFunctionsBlockCallbackUnsafe>);
172172
}
173173

174-
#if SWIFT_STDLIB_HAS_DLADDR
175-
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
176-
Dl_info dlinfo;
177-
if (dladdr(address, &dlinfo) == 0) {
178-
return 0;
179-
}
180-
181-
info->fileName = dlinfo.dli_fname;
182-
info->baseAddress = dlinfo.dli_fbase;
183-
info->symbolName.reset(dlinfo.dli_sname);
184-
info->symbolAddress = dlinfo.dli_saddr;
185-
return 1;
186-
}
187-
#endif
188-
189174
#endif // defined(__APPLE__) && defined(__MACH__) &&
190175
// !defined(SWIFT_RUNTIME_STATIC_IMAGE_INSPECTION)

stdlib/public/runtime/ImageInspectionWasm.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,4 @@
2323

2424
using namespace swift;
2525

26-
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
27-
// Currently, Wasm doesn't have a standard stable ABI for exporting address <->
28-
// symbol table, it's work in progress. Also, there is no API to access such
29-
// information from Wasm binary side. It's accessible only from host VM.
30-
// See https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
31-
// Seems reasonable to use a stub for now.
32-
return 0;
33-
}
34-
3526
#endif // defined(__wasm__)

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,13 +1105,11 @@ _gatherGenericParameters(const ContextDescriptor *context,
11051105

11061106
str += "_gatherGenericParameters: context: ";
11071107

1108-
#if SWIFT_STDLIB_HAS_DLADDR
11091108
SymbolInfo contextInfo;
11101109
if (lookupSymbol(context, &contextInfo)) {
1111-
str += contextInfo.symbolName.get();
1110+
str += contextInfo.getSymbolName();
11121111
str += " ";
11131112
}
1114-
#endif
11151113

11161114
char *contextStr;
11171115
swift_asprintf(&contextStr, "%p", context);

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ static const char *class_getName(const ClassMetadata* type) {
124124
}
125125

126126
template<> void ProtocolConformanceDescriptor::dump() const {
127+
SymbolInfo info;
127128
auto symbolName = [&](const void *addr) -> const char * {
128-
SymbolInfo info;
129129
int ok = lookupSymbol(addr, &info);
130-
if (!ok)
130+
if (!ok || !info.getSymbolName())
131131
return "<unknown addr>";
132-
return info.symbolName.get();
132+
return info.getSymbolName();
133133
};
134134

135135
switch (auto kind = getTypeKind()) {

stdlib/public/runtime/ReflectionMirror.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,14 +1114,18 @@ id swift_reflectionMirror_quickLookObject(OpaqueValue *value, const Metadata *T)
11141114
}
11151115
#endif
11161116

1117-
SWIFT_CC(swift)
1118-
SWIFT_RUNTIME_STDLIB_INTERNAL const char *swift_keyPath_dladdr(void *address) {
1117+
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
1118+
const char *swift_keyPath_copySymbolName(void *address) {
11191119
SymbolInfo info;
1120-
if (lookupSymbol(address, &info) == 0) {
1121-
return 0;
1122-
} else {
1123-
return info.symbolName.get();
1120+
if (lookupSymbol(address, &info) && info.getSymbolName()) {
1121+
return strdup(info.getSymbolName());
11241122
}
1123+
return 0;
1124+
}
1125+
1126+
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
1127+
void swift_keyPath_freeSymbolName(const char *symbolName) {
1128+
free(const_cast<char *>(symbolName));
11251129
}
11261130

11271131
SWIFT_CC(swift)

0 commit comments

Comments
 (0)