Skip to content

Conversation

@sgress454
Copy link
Contributor

@sgress454 sgress454 commented Mar 28, 2025

Fixes #7627
Fixes #5896
Fixes fleetdm/fleet#26583

Fixes issues with SMC key readings used by the temperature_sensors, power_sensors and fan_speed_sensors tables.

SMC keys are already mysterious (there is no known definitive reference on the keys) and each new Apple product that comes out seems to have its own opinions about what data type keys should use. At some point the temperature keys started using the flt and ioft types which we were not handling.

Big shout out to @directionless for doing some digging on a previous ticket and leading me to https://github.com/dkorunic/iSMC which at least has a good listing of known types and clues as to how to convert them. I've updated the code to handle flt and ioft as well all of the known fp*, sp*, ui* and si* types. I also added tests for the conversions.

Before:
image

After:
image

@sgress454 sgress454 requested review from a team as code owners March 28, 2025 21:36
#include <osquery/logger/logger.h>

#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string.hpp>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

for string trimming

Comment on lines +385 to +392
inline uint64_t strtoull(const char* str, size_t size, size_t base) {
uint64_t total = 0;
for (size_t i = 0; i < size; i++) {
total += static_cast<uint64_t>(static_cast<unsigned char>(str[i]))
<< (size - 1 - i) * 8;
}
return total;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Companion to strtoul, but for 64 bit ints.

Copy link
Member

Choose a reason for hiding this comment

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

Other parts of our code use std::strtoull. Should this?

Copy link
Contributor Author

@sgress454 sgress454 Mar 31, 2025

Choose a reason for hiding this comment

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

I don't think so. The std:strtoull function does what you'd probably expect from the name: it takes a numeric string and interprets it as a number, e.g. the string "12345" becomes the unsigned long 12345. The strtoul function defined in smc_keys.cpp does something else entirely: it treats a string as a set of bytes representing an integer with big-endian encoding. It's functionally the same as byte-swapping a string and memcpying the bytes into a new uint32_t, except it would work equally well on machines that actually use big-endian encoding (I don't think that was a concern even nine years ago when this code was written, but 🤷 ).

I don't know why the function here was called strtoul, but for consistency I named the 64-bit version the same thing. I'd be happy to rename them both, but without knowing the history I prefer to stay low-touch.

Copy link
Member

Choose a reason for hiding this comment

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

I agreee consistency with the local function makes sense, though the divergence from std:: seems unfortunate.

return total;
}

double getConvertedValue(const std::string& smcType,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed this (and all related vars) from float to double to handle 64-bit types. We don't utilize any in tables right now, but there are definitely some 64-bit SMC keys (18 on my system) and this future-proofs us.

@sgress454 sgress454 force-pushed the 26583-fix-smc-readings branch from 931df9b to 77218cb Compare March 28, 2025 21:41
Copy link
Member

@directionless directionless left a comment

Choose a reason for hiding this comment

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

nice! A couple of small questions...

Comment on lines +385 to +392
inline uint64_t strtoull(const char* str, size_t size, size_t base) {
uint64_t total = 0;
for (size_t i = 0; i < size; i++) {
total += static_cast<uint64_t>(static_cast<unsigned char>(str[i]))
<< (size - 1 - i) * 8;
}
return total;
}
Copy link
Member

Choose a reason for hiding this comment

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

Other parts of our code use std::strtoull. Should this?

Comment on lines +460 to +462
else if ((type[0] == 's' || type[0] == 'u') && type[1] == 'i') {
uint64_t intVal = strtoull(val.c_str(), size, 16);
if (type[0] == 's') {
Copy link
Member

Choose a reason for hiding this comment

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

Why combine the s and u logic if it's just split apart on line 462?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's combining the si and ui logic, both of which start by interpreting the value as a big-endian int. What we do with that int depends on whether it's signed or unsigned.

Copy link
Member

@directionless directionless Mar 31, 2025

Choose a reason for hiding this comment

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

Yeah.. I guess I'd duplicate the strtoull over the nested if But 🤷 I'll merge as is

Comment on lines +385 to +392
inline uint64_t strtoull(const char* str, size_t size, size_t base) {
uint64_t total = 0;
for (size_t i = 0; i < size; i++) {
total += static_cast<uint64_t>(static_cast<unsigned char>(str[i]))
<< (size - 1 - i) * 8;
}
return total;
}
Copy link
Member

Choose a reason for hiding this comment

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

I agreee consistency with the local function makes sense, though the divergence from std:: seems unfortunate.

Comment on lines +460 to +462
else if ((type[0] == 's' || type[0] == 'u') && type[1] == 'i') {
uint64_t intVal = strtoull(val.c_str(), size, 16);
if (type[0] == 's') {
Copy link
Member

@directionless directionless Mar 31, 2025

Choose a reason for hiding this comment

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

Yeah.. I guess I'd duplicate the strtoull over the nested if But 🤷 I'll merge as is

@directionless directionless merged commit 26ed513 into osquery:master Mar 31, 2025
22 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

2 participants