Skip to content

Conversation

@zwass
Copy link
Member

@zwass zwass commented Apr 17, 2025

A refactor of the readFile function (in #8410) caused all parsing of shortcut files to fail. The test had a bug that caused the relevant checks to be skipped.

Fixes #8599

A misusage of the readFile function caused all parsing of shortcut files to fail.

Fixes osquery#8599
if (isPlatform(PlatformType::TYPE_WINDOWS)) {
auto link_path = boost::filesystem::path(expected_path);

if (row.at("path").rfind(".lnk") != std::string::npos) {
Copy link
Member Author

@zwass zwass Apr 17, 2025

Choose a reason for hiding this comment

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

This was a bug in the test that would always be false so the shortcut functionality was never tested (because the loop iterates only through the kFilenameList and not the shortcut files)

@zwass
Copy link
Member Author

zwass commented Apr 18, 2025

There seem to be some slightly different paths on one of the Windows runners (RUNNER~1 vs. runneradmin). I'm not sure what is the best way to deal with this in CI. Perhaps skip that part of the test?

Smjert
Smjert previously approved these changes Apr 18, 2025
Copy link
Member

@Smjert Smjert left a comment

Choose a reason for hiding this comment

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

Just a comment on performance, but overall looks good.

auto status =
readFile(link, header_size_field_bytes, kShellLinkHeaderSizeFieldSize);
std::string link_content;
auto status = readFile(link, link_content);
Copy link
Member

Choose a reason for hiding this comment

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

Did you test the performance of the table after this change, especially trying to list files are big in size?

I'm not sure how many file types end up using this readFile, but even with the max read size, this might cause the table to be slower because now it will attempt to read them fully, while we only wanted to read a small portion of them.

The original implementation of readFile (which I changed through another PR and apparently missed this use) exposed a number of bytes to read.

Furthermore its use was so that the non-blocking behavior was used (vs a simpler read), to avoid any hanging trying to read special files, but in hindsight I think we have still the issue with the COM interface above, which means that if performance is an issue, this could be substituted by a plain read of the header bytes.

Copy link
Member Author

@zwass zwass Apr 22, 2025

Choose a reason for hiding this comment

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

Ooh that makes sense that there used to be another overload for the readFile function. I didn't test the performance of this. I see the PR (#8410) where it was removed. Maybe we should just re-add the number of bytes overload in this PR?

@Smjert
Copy link
Member

Smjert commented Apr 18, 2025

There seem to be some slightly different paths on one of the Windows runners (RUNNER~1 vs. runneradmin). I'm not sure what is the best way to deal with this in CI. Perhaps skip that part of the test?

Sorry I missed this; I think the test could try to use GetLongPathNameW (https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlongpathnamew) to resolve the shell link path to a long path.

I would not use this directly in the table code since this walks the filesystem afaik.

@zwass
Copy link
Member Author

zwass commented May 13, 2025

@Smjert I added back the optimization to read only the first 4 bytes. I also added an additional optimization that will skip all this logic if it's not a .lnk file.

Still need to fix the test.

@zwass
Copy link
Member Author

zwass commented May 14, 2025

Finally got the test working!

@zwass
Copy link
Member Author

zwass commented May 19, 2025

@Smjert please take a look when you can

ASSERT_TRUE(link_index.has_value());
const auto& row = data.at(link_index.value());

auto short_path = directory.string();
Copy link
Member

Choose a reason for hiding this comment

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

Here we need to first go from UTF8 -> UTF16 with stringToWString.
But we also need the name of the file here; they can be shortened too.

// Transform the expected path to a "full path" using GetLongPathNameW
wchar_t long_path[MAX_PATH];
auto result = GetLongPathNameW(
std::wstring(short_path.begin(), short_path.end()).c_str(),
Copy link
Member

Choose a reason for hiding this comment

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

and then here we have a short_path variable that's already a std::wstring

long_path,
MAX_PATH);
EXPECT_EQ(row.at("shortcut_target_path"),
wstringToString(long_path) + "\\" + test_file_name);
Copy link
Member

Choose a reason for hiding this comment

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

After the changes above, we don't need to append test_file_name anymore

@zwass
Copy link
Member Author

zwass commented May 22, 2025

@Smjert I made your requested revisions. Test is still passing locally. Hopefully it also works on CI.

@zwass zwass requested a review from Smjert May 29, 2025 16:52
@zwass
Copy link
Member Author

zwass commented May 29, 2025

It's now building and passing tests on CI. I'm not sure how it could have still been passing locally per my last comment -- I must not have actually built the newly modified files. But now it's working.

@zwass zwass merged commit 7c357da into osquery:master Jun 3, 2025
22 checks passed
@zwass zwass deleted the fix-lnk-parsing branch June 3, 2025 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows shortcut (.lnk) file info is not returned

2 participants