Skip to content

Commit

Permalink
Make EventPipeProviderCallbackData own the filter data (#42307)
Browse files Browse the repository at this point in the history
Fixes a use after free issue in EventPipe, where the EventPipeProviderCallbackData would cache a pointer to the filter data string on EventPipeSessionProvider, but disabling the session would free all of the EventPipeSessionProviders.
  • Loading branch information
davmason authored Sep 17, 2020
1 parent 254627c commit 873d963
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 30 deletions.
4 changes: 2 additions & 2 deletions src/coreclr/src/vm/eventpipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1041,9 +1041,9 @@ HANDLE EventPipe::GetWaitHandle(EventPipeSessionID sessionID)
return pSession ? pSession->GetWaitEvent()->GetHandleUNHOSTED() : 0;
}

void EventPipe::InvokeCallback(EventPipeProviderCallbackData eventPipeProviderCallbackData)
void EventPipe::InvokeCallback(EventPipeProviderCallbackData *pEventPipeProviderCallbackData)
{
EventPipeProvider::InvokeCallback(eventPipeProviderCallbackData);
EventPipeProvider::InvokeCallback(pEventPipeProviderCallbackData);
}

EventPipeEventInstance *EventPipe::BuildEventMetadataEvent(EventPipeEventInstance &instance, unsigned int metadataId)
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/src/vm/eventpipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class EventPipe
}

while (eventPipeProviderCallbackDataQueue.TryDequeue(&eventPipeProviderCallbackData))
InvokeCallback(eventPipeProviderCallbackData);
InvokeCallback(&eventPipeProviderCallbackData);
}

// Returns the a number 0...N representing the processor number this thread is currently
Expand All @@ -158,7 +158,7 @@ class EventPipe
}

private:
static void InvokeCallback(EventPipeProviderCallbackData eventPipeProviderCallbackData);
static void InvokeCallback(EventPipeProviderCallbackData *pEventPipeProviderCallbackData);

// Get the event used to write metadata to the event stream.
static EventPipeEventInstance *BuildEventMetadataEvent(EventPipeEventInstance &instance, unsigned int metadataId);
Expand Down
5 changes: 2 additions & 3 deletions src/coreclr/src/vm/eventpipecommontypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

void EventPipeProviderCallbackDataQueue::Enqueue(EventPipeProviderCallbackData *pEventPipeProviderCallbackData)
{
SListElem<EventPipeProviderCallbackData> *listnode = new SListElem<EventPipeProviderCallbackData>(); // throws
listnode->m_Value = *pEventPipeProviderCallbackData;
SListElem<EventPipeProviderCallbackData> *listnode = new SListElem<EventPipeProviderCallbackData>(std::move(*pEventPipeProviderCallbackData)); // throws
list.InsertTail(listnode);
}

Expand All @@ -19,7 +18,7 @@ bool EventPipeProviderCallbackDataQueue::TryDequeue(EventPipeProviderCallbackDat
return false;

SListElem<EventPipeProviderCallbackData> *listnode = list.RemoveHead();
*pEventPipeProviderCallbackData = listnode->m_Value;
*pEventPipeProviderCallbackData = std::move(listnode->m_Value);
delete listnode;
return true;
}
Expand Down
125 changes: 117 additions & 8 deletions src/coreclr/src/vm/eventpipecommontypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,20 +98,129 @@ typedef void (*EventPipeCallback)(
EventFilterDescriptor *FilterData,
void *CallbackContext);

struct EventPipeProviderCallbackData
class EventPipeProviderCallbackData
{
LPCWSTR pFilterData;
EventPipeCallback pCallbackFunction;
bool enabled;
INT64 keywords;
EventPipeEventLevel providerLevel;
void* pCallbackData;
public:
EventPipeProviderCallbackData():
m_pFilterData(nullptr),
m_pCallbackFunction(nullptr),
m_enabled(false),
m_keywords(0),
m_providerLevel(EventPipeEventLevel::LogAlways),
m_pCallbackData(nullptr),
m_pProvider(nullptr)
{

}

EventPipeProviderCallbackData(LPCWSTR pFilterData,
EventPipeCallback pCallbackFunction,
bool enabled,
INT64 keywords,
EventPipeEventLevel providerLevel,
void* pCallbackData,
EventPipeProvider *pProvider) :
m_pFilterData(nullptr),
m_pCallbackFunction(pCallbackFunction),
m_enabled(enabled),
m_keywords(keywords),
m_providerLevel(providerLevel),
m_pCallbackData(pCallbackData),
m_pProvider(pProvider)
{
if (pFilterData != nullptr)
{
// This is the only way to create an EventPipeProviderCallbackData that will copy the
// filter data. The copying is intentional, because sessions die before callbacks happen
// so we cannot cache a pointer to the session's filter data.
size_t bufSize = wcslen(pFilterData) + 1;
m_pFilterData = new WCHAR[bufSize];
wcscpy_s(m_pFilterData, bufSize, pFilterData);
}
}

EventPipeProviderCallbackData(EventPipeProviderCallbackData &&other)
: EventPipeProviderCallbackData()
{
*this = std::move(other);
}

EventPipeProviderCallbackData &operator=(EventPipeProviderCallbackData &&other)
{
std::swap(m_pFilterData, other.m_pFilterData);
m_pCallbackFunction = other.m_pCallbackFunction;
m_enabled = other.m_enabled;
m_keywords = other.m_keywords;
m_providerLevel = other.m_providerLevel;
m_pCallbackData = other.m_pCallbackData;
m_pProvider = other.m_pProvider;

return *this;
}

// We don't want to be unintentionally copying and deleting the filter data any more
// than we have to. Moving (above) is fine, but copying should be avoided.
EventPipeProviderCallbackData(const EventPipeProviderCallbackData &other) = delete;
EventPipeProviderCallbackData &operator=(const EventPipeProviderCallbackData &other) = delete;

~EventPipeProviderCallbackData()
{
if (m_pFilterData != nullptr)
{
delete[] m_pFilterData;
m_pFilterData = nullptr;
}
}

LPCWSTR GetFilterData() const
{
return m_pFilterData;
}

EventPipeCallback GetCallbackFunction() const
{
return m_pCallbackFunction;
}

bool GetEnabled() const
{
return m_enabled;
}

INT64 GetKeywords() const
{
return m_keywords;
}

EventPipeEventLevel GetProviderLevel() const
{
return m_providerLevel;
}

void *GetCallbackData() const
{
return m_pCallbackData;
}

EventPipeProvider *GetProvider() const
{
return m_pProvider;
}

private:
WCHAR *m_pFilterData;
EventPipeCallback m_pCallbackFunction;
bool m_enabled;
INT64 m_keywords;
EventPipeEventLevel m_providerLevel;
void* m_pCallbackData;
EventPipeProvider *m_pProvider;
};

class EventPipeProviderCallbackDataQueue
{
public:
void Enqueue(EventPipeProviderCallbackData* pEventPipeProviderCallbackData);
void Enqueue(EventPipeProviderCallbackData *pEventPipeProviderCallbackData);
bool TryDequeue(EventPipeProviderCallbackData* pEventPipeProviderCallbackData);

private:
Expand Down
28 changes: 14 additions & 14 deletions src/coreclr/src/vm/eventpipeprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ void EventPipeProvider::AddEvent(EventPipeEvent &event)
event.RefreshState();
}

/* static */ void EventPipeProvider::InvokeCallback(EventPipeProviderCallbackData eventPipeProviderCallbackData)
/* static */ void EventPipeProvider::InvokeCallback(EventPipeProviderCallbackData *pEventPipeProviderCallbackData)
{
CONTRACTL
{
Expand All @@ -205,12 +205,12 @@ void EventPipeProvider::AddEvent(EventPipeEvent &event)
}
CONTRACTL_END;

LPCWSTR pFilterData = eventPipeProviderCallbackData.pFilterData;
EventPipeCallback pCallbackFunction = eventPipeProviderCallbackData.pCallbackFunction;
bool enabled = eventPipeProviderCallbackData.enabled;
INT64 keywords = eventPipeProviderCallbackData.keywords;
EventPipeEventLevel providerLevel = eventPipeProviderCallbackData.providerLevel;
void *pCallbackData = eventPipeProviderCallbackData.pCallbackData;
LPCWSTR pFilterData = pEventPipeProviderCallbackData->GetFilterData();
EventPipeCallback pCallbackFunction = pEventPipeProviderCallbackData->GetCallbackFunction();
bool enabled = pEventPipeProviderCallbackData->GetEnabled();
INT64 keywords = pEventPipeProviderCallbackData->GetKeywords();
EventPipeEventLevel providerLevel = pEventPipeProviderCallbackData->GetProviderLevel();
void *pCallbackData = pEventPipeProviderCallbackData->GetCallbackData();

bool isEventFilterDescriptorInitialized = false;
EventFilterDescriptor eventFilterDescriptor{};
Expand Down Expand Up @@ -286,13 +286,13 @@ EventPipeProviderCallbackData EventPipeProvider::PrepareCallbackData(
}
CONTRACTL_END;

EventPipeProviderCallbackData result;
result.pFilterData = pFilterData;
result.pCallbackFunction = m_pCallbackFunction;
result.enabled = (m_sessions != 0);
result.providerLevel = providerLevel;
result.keywords = keywords;
result.pCallbackData = m_pCallbackData;
EventPipeProviderCallbackData result(pFilterData,
m_pCallbackFunction,
(m_sessions != 0),
keywords,
providerLevel,
m_pCallbackData,
this);
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/vm/eventpipeprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class EventPipeProvider
LPCWSTR pFilterData);

// Invoke the provider callback.
static void InvokeCallback(EventPipeProviderCallbackData eventPipeProviderCallbackData);
static void InvokeCallback(EventPipeProviderCallbackData *pEventPipeProviderCallbackData);

// Specifies whether or not the provider was deleted, but that deletion
// was deferred until after tracing is stopped.
Expand Down

0 comments on commit 873d963

Please sign in to comment.