Mordak
I realized some time ago when I talk to people about rust, I don't really mention memory / thread safety in a security context, I mention them in a reliability context. Compile-time checks mean I basically never spend time debugging runtime crashes, and generally can count on the compiler to catch memory and thread safety issues before the program ever runs, and this saves me time and aggravation in production. I care about security, but I care more about reliability, and rust compile-time checks mean my software is reliable in a way that runtime-checked languages just aren't.
This applies to lots of languages. Every time I hit a runtime crash in python, or ruby, or js I die a little inside. Even though they are memory-safe because they're garbage collected, I still waste time debugging runtime errors.
- Parsing untrusted inputs. nom[1] is a joy to use, and lets you kind of effortlessly and fearlessly process random input from wherever and turn it into useful data structures. If your data is very regular or in a standard format, then serde[3] is very hard to beat if it just boils down to 'derive(Deserialize, Serialize)' on your Rust struct.
- Bulk data processing. rayon[2] makes pegging your machine easy if you have a lot of work do to, and the Rust semantics around thread safety, data ownership, and explicit copying make it kind of trivial to reason about how your data gets from input to output and tuning it to be crazy fast.
- Generic systems language. Maybe this one is personal, but I find it's more productive to write generic cli applications and whatnot in Rust over C, ruby, or python. There are some nice libs to make part of this pleasant (structopt[4]) but this really boils down to reliability. Because Rust makes it obvious where things can fail so I can deal with it I have way higher 'just works' outcomes in Rust than other languages. I might spend slightly more time making it compile, but I spend basically zero time debugging runtime failures and this is kind of indescribably amazing.
[1] https://docs.rs/nom/6.1.0/nom/index.html
The guy who maintains it said in the reddit thread[2] about this same topic that the Google people have been sending him good PRs, which is presumably related to integrating Rust into Chrome.
[1] https://crates.io/crates/cxx [2] https://reddit.com/r/rust/comments/gpdorw/the_chromium_proje...
We built a new project in all "modern C++". It is 100% shared_ptr, unique_ptr, std::string, RAII, etc. It initially targeted C++17 specifically to get all the "modern C++" goodness.
It segfaults. It segfaults all the time. It is entirely routine for us to run a new build through the CI process and find segfaults. We fuzz it and find dozens of segfaults. Segfaults because of uninitialized memory. Segfaults because dereferencing pointers. Segfaults because running off the end of arrays. Segfaults because trusting input from the outside world ("the length of this payload is X bytes").
This is where the "modern C++" people tell me we must be doing it wrong. But the reality is that "modern C++" isn't as safe or as foolproof as the advocates say it is. But don't take my word for it - this whole thread is about Google people coming to the same conclusion.
Meanwhile I can throw a new dev at Rust and watch them go from zero to works in a week or so, and their code doesn't segfault, doesn't panic, and actually does what it is supposed to do the first time. Code reviews are easy because I don't have to ponder the memory safety and correctness of every line of code. Reasoning about unwrap() is trivial. Finding unsafe {} is trivial (and removing it is also usually easy).
Rust and OpenBSD share a lot of technical values though so maybe this isn't surprising. Rust values safety and correctness. OpenBSD values safety and correctness. Rust values 'Just Works' with all the nice things cargo does and the whole 'fearless refactoring / concurrency' thing. OpenBSD values 'Just Works' with sane defaults and the 'batteries included' base system.
FlatBuffers, Protobuf, Cap'n Proto, etc., all require an external schema configuration that you compile into a code chunk that you include into your program. Without this it is impossible to make sense of the data. In our case, the data is semi-structured and changes frequently. The prospect of maintaining a schema registry for all the data users and keeping everyone up to date and backwards compatible is enough of a burden that it was excluded.
Avro also uses schemas, but since the schema is embedded in the file it is self-describing so the reader does not need to do anything special to interpret the data. But Avro's C library is buggy and the python deserialization performance was terrible, so Avro was not selected.
- Msgpack serialization and deserialization is very fast in many languages - often 100x faster then JSON
- Msgpack natively supports encoding binary data
- Msgpack has type extensions, making it trivial to represent common types in an efficient way (eg. IPv4 address, timestamps)
- Msgpack has good libraries available in many languages
If you do not care about those things (no binary data, no need for extended types, not performance critical) then JSON is just fine.
Having used both scons and waf, and also having used make, cmake and cargo, I would take any of the last three over scons or waf in a heartbeat. I think cargo is far and away the nicest to use because there is very little to actually do to build your program. Using waf or scons was always an exercise of 'I added a header file, so now I need to figure out the scons/waf API in order to tell it what to do with it'.
The OpenBSD httpd is privilege separated and chroot()ed, and each component only pledge()s the syscalls it needs. This reduces to just the syscalls needed to do filesystem operations inside the chroot, log, and talk on the internet. In the CGI context, if your application only needs to read / write to stdio to talk to httpd, then you can limit yourself to just stdio, or if it only needs to read files then it can limit itself to just those syscalls. If your application does something outside of your pledge() (eg. exec(), because it got pwned) then the kernel will kill it.
There is an in-between case where you have a console, but do not control the boot loader (so cannot boot bsd.rd) and cannot boot an iso. It sounds like maybe you are in this situation? In this case, you can still follow the upgrade directions as if you do not have a console[1]. Alternately, sometimes when I am in this situation I just download the install kernel (bsd.rd), move it where the boot loader is hard-coded to look (/bsd), and then reboot. The boot loader will boot the install kernel and you can follow the usual / common upgrade procedure on the console.
There is also autoinstall[2], which can automate the upgrade procedure for you and reduces upgrades to just rebooting into bsd.rd and waiting a bit. There is a bit of effort to create the response file, etc., so this may be overkill for a single instance but is very useful for upgrading fleets of machines quickly.
[1] https://www.openbsd.org/faq/upgrade64.html#NoInstKern [2] https://man.openbsd.org/autoinstall
I found that the runtime overhead was about 2% on average, but there are many factors that contribute.
1. We don't silently skip instrumentation. If we can't find a free register then we will force the frame setup code to the front of the function so we can get one. See the diff in PEI::calculateSaveRestoreBlocks().
2. We do spill the calculated value to the stack. This is unavoidable in many cases (non-leaf functions). It would be an optimization to not do this in leaf functions, but this would also mean finding a register that is unused throughout the function. This turns out to be a small number of functions, so we didn't pursue it for the initial implementation.
3. I'm not sure what you mean by the cookies are shared. Do you just mean that they are all in the openbsd.randomdata section? They have to live somewhere. Being able to read arbitrary memory in the openbsd.randomdata section would leak them, yes, though this doesn't seem to have been a problem for the existing stack canary, which lives in the same section. I see that RAP keeps the cookie on a register, which sounds like a neat idea. I'd be curious to see how you manage to rotate the cookie arbitrarily.
4. I'm glad you like the int3 stuffing. :-) We could always make the int3 sled longer if it turns out these rets are still accessible in gadgets that terminate on the return instruction. Have you found any?
Anyway, I'm happy to see your commentary on this. You guys do some nice work! If you have other suggestions for improvement I'd be happy to hear them. You can email me at mortimer@.
> As a compromise, I allowed them to silently patch the vulnerability.
It's pretty easy to argue that OpenBSD doesn't like embargoes, but it's pretty hard to argue that they ignore embargoes and patch whenever they want to. In this specific case, the project asked and received permission to patch early. The fact that the researcher regrets this in hindsight is beside the point.
I like SafeStack, but was disappointed to learn about the limitations with shared libraries. Some SafeStack is better than no SafeStack though, and it can probably be turned on without too much effort.
Actually removing c2/c3 bytes and actively reducing the gadget space is a different endeavour. There has been a bunch of academic work in this regard, with varying levels of success. Some would say it is a fool's errand to try to remove all the ROP gadgets, but that's what fools are for. Stay tuned. :-)
Microsoft's CFG is cool, but works on the other end to this - by protecting CALL instructions instead of RET.
Stack cookies are similar, yes. This mechanism combines two ASLR-randomized values (the caller address and the stack address) to control program flow. Stack canaries use a constant random cookie per object file to detect stack smashing. Retguard raises the bar for successful ROP attacks, just as CFG raises the bar for function pointer corruption attacks.
Full disclosure, I am the author of the clang diff that kicked this off. The appeal of this mechanism is that it is cheap enough to apply in every function, pollutes the ROP gadget space with instructions that permute the next return address, and requires attackers to have more information in order to kick off ROP chains (the address where they are writing their ROP chain). I know about some of the other stuff people are working on (CPI seems promising), and look forward to turning those things on when possible. Meanwhile, this mitigation is cheap, localized inside every function, and doesn't require any program modification in the vast majority of situations (programs that inspect stack frames without consulting the unwind info may have problems), so is fairly easy to turn on everywhere.
But you don't always have stack address leaks. Presently, in order to ROP you need (a) a leaked address to the space where your gadgets live and (b) the ability to write your ROP chain somewhere where the program will return into it. With this scheme, you now also need (c) the exact address where you are writing your ROP chain.
Not all info leak vulnerabilities leak arbitrary memory of the attacker's choosing. If they did, stack canaries would be pretty useless. So for those cases where a stack address leak is unavailable, this raises the bar against ROP.
def do_something(arg1, arg2)
return false if arg1.is_invalid
return false if arg2 < sane
...
end
The trailing `unless` is also handy, and I find it a bit nicer to read compared to a negated `if`.https://github.com/churchers/vm-bhyve
It is nice that there are multiple wrappers around bhyve - competition is good, and it shows a healthy community.
The primary challenge with feeding soldiers in the field is not efficiently delivering nutritionally complete food to them, it is getting them to eat it day after day after day. Soldiers get bored eating the same things over and over again and eventually this drives them to stop eating, which negatively affects their performance.
It was technically feasible to replace rations with meal replacement powders decades ago, but the reason that MREs continue to be a variety of real food items is because they are more likely to be eaten that way. Even with all the variety, most US and Canadian rations include hot sauce to add optional variety to the same set of packaged meals for those who happen to eat a lot of them. This is also why MREs include heater bags - because hot food is more likely to be consumed than cold. Incidentally, this is also why personnel tend to love other nations' ration packs and disparage their own - not because they're better, but because they're not sick of them.
Food Officers take this stuff pretty seriously, and put a lot of effort into delivering nutritionally complete food to soldiers that they will actually enjoy eating. Meal replacement powders don't cut it in this environment.
As for Soylent, the primary use case I have seen is convenience. In this role, it's better than many other convenience foods, so I can see why some people go for it.
As a bit of history, when homebrew first landed, it existed because the author wanted to pass optimization flags to his builds [0], and found the macports build system too complex for this purpose. Homebrew's real strength is the relative transparency of the build system (it is more obvious what will happen when a build launches), which is really a reflection of this initial complaint about macports. At the time, I didn't care about optimization flags and didn't otherwise get a good vibe from the rest of the project, so stuck with macports for the reasons I listed above (less the binary installs, which didn't exist yet). Since then, I've been a bit surprised at how much Homebrew has taken off, but macports has continued to improve as well and I am still very happy with it.
Following current is pretty simple if you're happy to track snapshots, which are updated regularly (usually every week). If you're worried about stability, remember that -current turns into -stable twice a year, so current is pretty stable, and any issues that do crop up get fixed very quickly, because they impact the developers.
I dunno, there was a time when javascript wasn't the only game in town, and it sucked. ActiveX controls for hooking into native libraries, Java applets that assumed you had a JVM installed, subtle differences between javascript and jscript, VBS in the browser.. It was terrible, and the web is better now that they are largely a thing of the past.
I'm not a superfan of javascript, but building cross platform stuff in the browser seems easier now that you can count on its ubiquity and everyone is generally on board. Getting things done might be easier in walled gardens, but those gardens aren't usually cross platform.