-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Create HVCI table for Windows Device Guard #5426
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An initial pass. Some of our styling may have changed since I've been reviewing actively, so we'll wanna make sure we get someone else from the core team to also stamp this before we get too far along :)
specs/windows/hvci_status.table
Outdated
Column("version", TEXT, "The version number of the Device Guard build."), | ||
Column("instance_identifier", TEXT, "The instance ID of Device Guard."), | ||
Column("vbs_status", TEXT, "The status of the virtualization based security settings."), | ||
Column("code_integirty_policy_enforcement_status", TEXT, "The status of the code integirty policy enforcement settings."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/integirty/integrity/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
(BSTR)L"ROOT\\MICROSOFT\\WINDOWS\\DEVICEGUARD"); | ||
const std::vector<WmiResultItem>& wmiResults = wmiSystemReq.results(); | ||
if (wmiResults.empty()) { | ||
LOG(WARNING) << "Error retreiving information from WMI."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for data loss we prefer LOG(ERROR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
umcipolicymethod); | ||
|
||
std::string vbsmethod_str; | ||
std::map<long, std::string> vbsmethods; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be a std::map
? Perhaps this could just be a statically defined array or vector of std::string
, so:
std::vector<std::string> vbs_methods {
"VBS_NOT_ENABLED",
"VBS_ENABLED_AND_NOT_RUNNING",
"VBS_ENABLED_AND_RUNNING",
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also move this up outside of the for
loop, so that we're not redefining it every pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was mapping this because the WMI output returned a number, that correlated to a particular setting status (0 = this, 1 = that), but they seem to be in order from 0 to n, so this seems far simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
std::map<long, std::string> vbsmethods; | ||
|
||
std::string codepolicystatusmethod_str; | ||
std::map<long, std::string> codepolicystatusmethods; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same note as vbs_methods
for both this and the umcipolicymethods
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
return results; | ||
} | ||
for (const auto& data : wmiResults) { | ||
long vbsmethod; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and throughout, feel free to use snake_case
for variable names to break things up a bit, so vbs_method
, code_policy_status_method
, umci_policy_method
. Also, considering method
is repeated maybe just omit it for brevity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
} | ||
for (const auto& data : wmiResults) { | ||
long vbsmethod; | ||
long codepolicystatusmethod; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and throughout, the variable declaration is pretty far away from it's use. It can be a little clearer if the variable is right next to it's use point, so for something like this you could do:
long code_policy_status;
data.GetLong("CodeIntegrityPolicyEnforcementStatus", code_policy_status);
// do something with code_policy_status
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
umcipolicymethods[1] = "AUDIT_MODE"; | ||
umcipolicymethods[2] = "ENFORCED_MODE"; | ||
|
||
if (vbsmethods.find(vbsmethod) != vbsmethods.end()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's save this value so that you don't grab it twice. In fact you could just make this a ternary:
auto vbs_meth = vbsmethods.find(vbsmethod);
r["vbs_status"] = vbs_meth != vbs_methods.end() ? vbs_meth->second : "UNKNOWN";
Here and throughout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
r["code_integirty_policy_enforcement_status"] = codepolicystatusmethod_str; | ||
r["umci_policy_status"] = umcipolicymethod_str; | ||
|
||
// stuff goes before here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
Fix typo with one of the umcipolicy, remove VectorOfStrings call. Fix"integrity" spelling issues. Remove map calls to use arrays. Switch to vectors instead of array methods. Add conditional statements to use "unknown" for out-of-range values. Remove extraneous comment.
…into hvci-table-actual
Fix typo with one of the umcipolicy, remove VectorOfStrings call. Fix"integrity" spelling issues. Remove map calls to use arrays. Switch to vectors instead of array methods. Add conditional statements to use "unknown" for out-of-range values. Remove extraneous comment.
…into hvci-table-actual
0097458
to
adfa790
Compare
adfa790
to
6f9e2fd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to target experimental which will change a but the generation function. Whenever problem provide the valid values on the column description mentioning that UNKNOWN is returned on error. Finally please add tests similar to the other tests we have on the tests/integration directory.
namespace osquery { | ||
namespace tables { | ||
|
||
std::vector<std::string> vbs_methods = {"VBS_NOT_ENABLED", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to split this into enabled and running and make them booleans?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this case we need to track the three distinctive states. It may be possible for VBS to be running, but the configurations may be incorrect, and thus not run. It's also part of the expected status from the Microsoft docs: https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-exploit-guard/enable-virtualization-based-protection-of-code-integrity#virtualizationbasedsecuritystatus
"OFF", "AUDIT_MODE", "ENFORCED_MODE"}; | ||
|
||
QueryData genHVCIStatus(QueryContext& context) { | ||
Row r; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move inside the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're suggesting that I move 13-20 to line 30, I received previous feedback move most of my code outside the loop, since I would be recreating variables in each loop iteration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think I'm gunna say my bad on this one and let's go with @fmanco's suggestion here :) Thinking through this, my concern would be if logic ever changes and we're not updating the values for every column in the row we might get stale data being set. That's my bad, sorry about that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries, I just moved them back into the loop.
…into hvci-table-actual
I've correct my PR to be compatible with Buck, and also included an integration test for the new table. |
Friendly bump on this PR :) Thanks! |
Hello, could someone please take a look at my PR? Thank you :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This lgtm, @nullbrx would you mind fixing the one comment to move the Row r
back inside the loop? And we should be good to merge assuming CI goes through ok. Thanks for your patience with us!
"OFF", "AUDIT_MODE", "ENFORCED_MODE"}; | ||
|
||
QueryData genHVCIStatus(QueryContext& context) { | ||
Row r; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think I'm gunna say my bad on this one and let's go with @fmanco's suggestion here :) Thinking through this, my concern would be if logic ever changes and we're not updating the values for every column in the row we might get stale data being set. That's my bad, sorry about that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requesting changes for the CI build failures and also for the not about moving Row r
back into the loop :)
specs/BUCK
Outdated
@@ -745,7 +745,11 @@ osquery_gentable_cxx_library( | |||
"windows", | |||
), | |||
( | |||
"windows/pipes.table", | |||
_SPECS_LOCATION + "/windows/hvci_status.table", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the _SPECS_LOCATION
bit here, make it look like the ones above, I think CI is failing over this.
specs/BUCK
Outdated
"windows", | ||
), | ||
( | ||
_SPECS_LOCATION + "/windows/pipes.table", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm betting you might need to remove this _SPECS_LOCATION
as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed!
@muffins I'm affecting the Linux build somehow - let me know if I need to sync some things up :) |
Addressing `clang-format` nits, moving the `Row r` into the main loop.
@nullbrx I made the changes, looks like it was a |
I created a new table to track HVCI settings on a machine, utilizing the WMI class
Win32_DeviceGuard
. This is useful in determining if a host is configured to use Device Guard or running, and displays various code integrity settings enforced on the machine. In addition, this table returns the machine's unique Instance Identifier.Currently, this table does not return the available or required security properties of a machine.
This is my first pull request for osquery (and GitHub!) so please let me know if there is a better way to implement this.
Context: