Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly handle kernel addresses in an x86 stack trace #241

Merged
merged 1 commit into from
Aug 13, 2024
Merged

Correctly handle kernel addresses in an x86 stack trace #241

merged 1 commit into from
Aug 13, 2024

Conversation

mihai12p
Copy link
Contributor

@mihai12p mihai12p commented Aug 5, 2024

On an x86 application, ULONG_PTR is 4 bytes long, which means it cannot handle 8-byte long kernel addresses used by a 64-bit system.

@mihai12p
Copy link
Contributor Author

mihai12p commented Aug 5, 2024

@microsoft-github-policy-service agree

@kylereedmsft
Copy link
Member

Hi there,
Can you elaborate a little on this scenario? What's the krabs host architecture (x86?) and system architecture?

I'm looking at the code in schema.hpp and your change does not work correctly in the case that the frames are 32bit.
The current design is that we send two values in the case of the 64 bit frames and only one value in the case of a 32bit frame.

The following function also needs to be updated so that in the 64bit case only one value is pushed and in the 32bit case, the address is widened before it is pushed.

    inline std::vector<ULONG_PTR> schema::stack_trace() const
    {
        std::vector<ULONG_PTR> call_stack;
        if (record_.ExtendedDataCount != 0) {
            for (USHORT i = 0; i < record_.ExtendedDataCount; i++)
            {
                auto item = record_.ExtendedData[i];
                if (item.ExtType == EVENT_HEADER_EXT_TYPE_STACK_TRACE64) {
                    auto stacktrace = reinterpret_cast<PEVENT_EXTENDED_ITEM_STACK_TRACE64>(item.DataPtr);
                    auto stack_length = (item.DataSize - sizeof(ULONG64)) / sizeof(ULONG64);
                    for (size_t j = 0; j < stack_length; j++)
                    {
                        call_stack.push_back(stacktrace->Address[j]);
                    }
                }
                else if (item.ExtType == EVENT_HEADER_EXT_TYPE_STACK_TRACE32) {
                    auto stacktrace = reinterpret_cast<PEVENT_EXTENDED_ITEM_STACK_TRACE32>(item.DataPtr);
                    auto stack_length = (item.DataSize - sizeof(ULONG64)) / sizeof(ULONG);
                    for (size_t j = 0; j < stack_length; j++)
                    {
                        call_stack.push_back(stacktrace->Address[j]);
                    }
                }
            }
        }

        return call_stack;
    }

@mihai12p
Copy link
Contributor Author

Hi there,

I was testing on an x64 system with an x86 (WoW64) application. The issue I encountered is that 8-byte long addresses (particularly kernel addresses due to the x64 system) are being truncated because of the ULONG_PTR vector type, which is 4 bytes long in an x86 application.

When the header type is x64, the stack_length corresponds to the number of stack addresses, each being ULONG64 (8 bytes). In the loop, call_stack.push_back(stacktrace->Address[j]); only pushes the lower DWORD of the 8-byte address because call_stack values are of type ULONG_PTR. This is where the truncation occurs.

Regarding the function you mentioned, I believe it does not need to be updated, as the upcast to ULONG64 will happen automatically in the case of 4-byte addresses.

My proposed solution is to change the vector to contain only 8-byte long values. This way, it can accommodate both 4-byte and 8-byte addresses without issues.

Please let me know if I’m overlooking something. I’ve tested this approach, and it behaves as expected.

@kylereedmsft
Copy link
Member

Ok, I looked closer at the stack track function and the two types EVENT_EXTENDED_ITEM_STACK_TRACE32 and EVENT_EXTENDED_ITEM_STACK_TRACE64. You're right, the function is correct.

Widening the vector should work. I'm not sure why we used ULONG_PTR here instead of ULONG or ULONG64.

Looks good. Thanks for the PR!

kylereedmsft
kylereedmsft previously approved these changes Aug 13, 2024
Copy link
Member

@kylereedmsft kylereedmsft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thanks for the PR.

@swannman
Copy link
Member

@mihai12p would you mind updating the version numbers and release notes in the .nuspec files so we can publish an updated version after merging your change? Thanks!

@swannman
Copy link
Member

Also, looks like we have a build failure - have you taken a look at the compilation error?

@mihai12p
Copy link
Contributor Author

I’ve fixed the build issues and updated the release notes as requested.

I’m looking forward to more improvements as I’ll be using krabsetw extensively. Thank you!

@swannman swannman self-requested a review August 13, 2024 21:45
@swannman swannman merged commit 6b3152d into microsoft:master Aug 13, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants