473 karma · joined November 25, 2023
However I did not think of observing the ‘castgstatus’ runtime function.
Always nice to be able to compare the DTrace and Ebpf approaches, they both have different strong points.
Assume that the malware has replaced system commands, possibly used a kernel vulnerability to lie to you to hide its presence, so do not do anything in the infected system directly ?
I do not have much experience with it, but I think you can see the kernel call stack with it and I know you can also see the return value (in eax). That would be less effort than qemu + gdb + disabling kernel aslr, etc.
Just one point about testable assembly: I like the Golang guidelines which require to write a Go version before implementing the same in assembly. That way there is a baseline to compare with in terms of correctness and performance. Also the Go project has recently introduced mutation testing and test coverage on assembly code which is very interesting.
Finally about detecting at runtime the presence of simd: I am confused why a third-party dependency or even the std is needed. At least on x64, it’s just one instruction (“cpuid”) and then checking if a bit is set, right?
> Redeclaration does not introduce a new variable; it just assigns a new value to the original
I added a mention about that in the article. Thank you.
However: You absolutely do need a lock file to store a cryptographic hash of each dependency to ensure that what is fetched has not been tampered with. And users are definitely not typing a hash when adding a new dependency to package.json or Cargo.toml.
On the other hand I open sourced my blog and received lots of small contributions to fix typos or such which were nice.
- The batch size needs to be adaptative for performance, latency, and recovering smoothly after downtime.
- The polling timeouts, frequency etc the same.
- You need to avoid hysteresis.
- You want to be super careful about not disturbing the main application by placing heavy load on the database or accidentally locking tables/rows
- You likely want multiple distributed workers in case of a network partition to keep handling events
It’s hard to get right especially when the databases at the time did not support SKIP LOCKED.
In retrospect I wish I had listened to the WAL. Much easier.
If it’s an ARM Mac, under Rosetta. Otherwise directly.
ZFS was not leveraged that much but it saved our beacon once when a table in the production database was accidentally dropped and we could instantly rollback to the previous zfs snapshot (there was a tiny bit of data loss as a result but this did not matter too much for this application - uptime was more important). ZFS was also used for backups I believe.
A few times I used dtrace in production to troubleshoot.
When we introduced Linux to our fleet of FreeBSD servers, every team picked a different distro organically so it was a bit of a zoo. With FreeBSD on the server you only have the one variant.
I still use and like both, but I must say I really like that FreeBSD is a kernel+OS integrated together.
About the file system stuff: modern browsers ship with SQLite which is available to JavaScript (is it available to webassembly? No idea) so I would probably use that instead. Ideally you could use the sqlite API directly in C and emscripten would bridge the calls to the browser SQLite db. Something to investigate.
It’s more useful if you are implementing this in a general programming language, not in the shell, or if you want to know how it works under the hood.
I could also see video games and observability platforms needing to do this, for example Datadog, which must send lots of stack traces with long function names along with numerical data.
TBH it was also news to me, I discovered it randomly while browsing vulnerabilities… Printf also allocates, and a ton of other stdlib functions as well.
As others have said, doing so in pure C and linking dynamically, you can easily remain under 20 KiB, at least on Linux, but Windows should be even simpler since it ships with much more out of the box as part of the OS.
In any event, I salute the effort! You can try the linking options I mentioned at the end of my article, it should help getting the size down.
So essentially the code got faster by switching to smarter regexp engine that can transform (hopefully) the regexp into a FSM. Cool, but what about replacing the regexp with straightforward parsing code written manually? That way it is statically known that this function is fast all of the time.
At least that’s what I would do in a natively compiled language with access to simd, not sure if ruby has access to it and can detect the best variant at runtime.
And I’d argue plain code is simpler to understand, debug, troubleshoot than a complex regexp.
The regexp engine part reminds me of writing scalar code, relying on the compiler doing autovectorization to make it fast. And what very often happens is that the new compiler version changed their heuristics and now there is no autovectorization that kicks in and the performance falls off a cliff . It’s a risky bet.