[HN Gopher] Viable ROP-free roadmap for i386/armv8/riscv64/alpha...
___________________________________________________________________
Viable ROP-free roadmap for i386/armv8/riscv64/alpha/sparc64
Author : zdw
Score : 104 points
Date : 2023-09-25 14:37 UTC (1 days ago)
(HTM) web link (marc.info)
(TXT) w3m dump (marc.info)
| ComputerGuru wrote:
| OT: I wonder whether Apple or Firefox's "reading mode" algorithms
| (both broken for this link) will gain the ability to handle these
| plaintext, fixed-width, hard line ended, htmlified email archives
| before the owners of any of these sites like marc.info adapt to
| use more user friendly formatting that can reflow in a narrower-
| width browser window...
| [deleted]
| jerrysievert wrote:
| I'm on safari 16.6 and reader mode seems to work just fine on
| this site.
| circuit10 wrote:
| I'm on Safari on iOS 15.7.4 and Reader Mode opens but just
| shows the long lines with a horizontal scroll and no wrapping
| still
| thenicofu wrote:
| Same on safari 15.6
| [deleted]
| prmoustache wrote:
| my firefox do not propose reading mode because ... the page
| itself is pretty much in reading mode already with the line
| breaks to limit line length.
|
| Nothing is broken as I see it.
| ComputerGuru wrote:
| It's not very user friendly on mobile.
| rzzzt wrote:
| You can force reader view by entering "about:reader?url=<page
| URL>" into the address bar, but it can not decide what should
| be displayed for this page. IIUC this check runs on all
| visited pages and the button is only shown when it succeeds.
| recursive wrote:
| I see margin-left: $small.
|
| Reader mode would help with that.
| musha68k wrote:
| Somewhat related: did Power arch really reach it's "EOL" by now?
| IIRC IBM was still doing _something_ with it at least? Anyone in
| the know?
|
| > So amd64 isn't as good as arm64, riscv64, mips64, powerpc, or
| powerpc64.
| kjs3 wrote:
| https://www.ibm.com/power? Too obscure?
|
| On the embedded side, NXP (former Freescale former Motorola)
| makes them, as does 'Macom' (former AMCC via some hedge fund
| gymnastics...never heard of them either). Others like Xilinx
| probably still have licenses to produce. And you can still get
| the rad-hard RAD750 from BEA systems, for your outer space or
| post-apocalypse needs.
| miki123211 wrote:
| Why do Open BSD developers in 2023 care about architectures like
| alpha and sparc64? What are their use cases? Why would anybody
| pick those over Intel / ARM? What do those architectures provide
| that makes people care? Is it just existing hardware that people
| already have and don't want to throw away, or is there an actual
| reason one would buy such a processor over the more popular
| competition? I get the arguments for Riscv for example, but the
| rest are a mystery for me.
|
| I'm not criticizing here, but actually seeking to understand.
| chasil wrote:
| Big-endian CPUs were once the dominant clients in TCP/IP
| networking, and these machines define the hton and ntoh C
| macros as no-ops. This means that the network itself is big-
| endian.
|
| Here is an old HP-UX machine running on PA-RISC:
| # grep ntoh /usr/include/netinet/in.h #ifndef ntohl
| #define ntohl(x) (x) #define ntohs(x) (x)
|
| On x86_64, this is a byte-swap: $ grep bswap
| /usr/include/netinet/*.h
| /usr/include/netinet/in.h:# define ntohl(x) __bswap_32 (x)
| /usr/include/netinet/in.h:# define ntohs(x) __bswap_16 (x)
| /usr/include/netinet/in.h:# define htonl(x) __bswap_32 (x)
| /usr/include/netinet/in.h:# define htons(x) __bswap_16 (x)
|
| SPARC is big-endian, and the memory is not in the same order as
| it is on x86. This can coax bugs out of software that are
| otherwise not seen on little-endian systems.
|
| Alpha is litte-endian, but it has its own exotic problems.
| KMag wrote:
| > Alpha is litte-endian, but it has its own exotic problems.
|
| At least some models of the Alpha were bi-endian, selectable
| via a pin on the package, IIRC. I believe the Cray T3E ran
| the chips big-endian.
| chasil wrote:
| I think MIPS and POWER could also do this.
| my123 wrote:
| Arm (both 32 and 64-bit) supports both BE and LE.
| Switchable at runtime so that you can have a BE VM on an
| LE host just fine.
|
| Apple Arm chips however are LE only, but all of Arm's
| Cortex-A/Neoverse and NVIDIA's cores support both LE and
| BE operation.
| [deleted]
| johnklos wrote:
| There are a lot of mistakes that make it in to common code when
| people only test with one architecture.
|
| Also, the environmental cost of manufacturing new hardware is
| often greater than even a decade of running less efficient,
| older hardware longer.
|
| To add to that, Alphas and older Sun systems are actually
| proper server hardware. There are differences that you may
| never learn about in the x86 world. I've been running an
| AlphaServer DS25 for years now, and it's worlds better hardware
| quality than any x86 server product you can buy now.
| miki123211 wrote:
| Better in what sense?
|
| How would you characterize the differences?
| saagarjha wrote:
| I am having trouble believing that the environmental impact
| of a running a server from _2002_ is lower than buying a
| machine that is 2-3 orders of magnitude more efficient.
| Findecanor wrote:
| Theo De Raadt has expressed that compiling and testing on CPUs
| that are "not boring" helps them to find bugs earlier.
| kjs3 wrote:
| Well, for one thing people still sell sparc machines. But
| beyond that, they care to catch bugs that an architecture
| monoculture misses/ignores. For example, the OpenBSD folks have
| said a number of times SPARC64 is a good way to catch memory
| alignment problems. Diversity in testing is a good thing.
| aomix wrote:
| Running on many many architectures is an another way of testing
| code robustness. Code that runs on X could crash on Y because
| it always had a bug that the quirks of X hid. The weirder the
| architecture the better, kind of.
|
| Or somebody may just think it'd be a fun challenge to do and so
| it supports it. That's all.
| MobiusHorizons wrote:
| The use of an illegal instruction to cause the crash is
| interesting, especially given the speculative execution angle. I
| naively would have expected branch prediction to do a good job
| given that the branch is never taken in typical operation, but I
| guess that only applies to frequently run code
| stefan_ wrote:
| I wouldn't expect a CPU to speculatively execute something like
| "int 3" either, given compilers will frequently place it in
| between real functions (for alignment).
| phire wrote:
| It makes sense now that I think about it.
|
| We usually base our intuition on the older and simpler branch
| predictors of 10-20 years ago, where the location of the branch
| and it's taken/not-taken history are tightly coupled. In those,
| a never-taken branch is either unknown (which counts as a non-
| taken prediction) or the branch is known and correctly
| predicted.
|
| But modern branch predictors decoupled the branch location and
| branch history. They hash the sequence of the last few branches
| and use that hash to index into the branch history table,
| allowing the a single branch to have multiple different
| histories depending on the control flow leading up to it. That
| significantly improves branch prediction for hot code, the
| predictor can now track things like a branch that will always
| be taken during the first iteration of a loop, or a branch will
| always be taken if the function was called from one location
| but not another. They can even track the relationships between
| indirect branches in vtables.
|
| But Hash collisions are expected, especially outside of hot
| code. So it should be quite common for never-taken branches in
| warmish code to be known, but predicted as taken due to a
| collision.
| fweimer wrote:
| It's unclear whether this matters, though. Some CPUs speculate
| through unconditional control flow as if it is never going to
| happen.
| pizzalife wrote:
| Removing RET instructions won't make your program unexploitable.
| Especially on architectures like x86_64 where you can get so many
| possible gadgets from a standard library.
|
| Trying to make software mechanisms like this that span multiple
| architectures feels like a relic of the past. These days you need
| to use processor-specific features like ARM pointer
| authentication.
| H8crilA wrote:
| It's not meant to be 100% reliable. Also they clearly state
| that variable length instruction architectures (like x86) are
| harder to protect. And if you can use something better then
| great, use it. You can then disable this mechanism.
| saagarjha wrote:
| This misses the point of how ROP works, and is in fact why
| previous attempts at ROP gadget reduction were flawed: it
| only takes a handful of gadgets to make a chain. Trying to
| protect control flow requires more sound approaches than
| this.
| tedunangst wrote:
| At the time, Todd was testing with whatever the popular rop
| compiler was, and it wasn't able to chain anything using
| libc. Even on amd64 you can restrict which gadgets are
| available. Maybe you can find other approaches with a
| careful hand search, but I think knocking out the biggest
| exploit generator is hardly flawed in a practical sense.
| saagarjha wrote:
| People don't generate exploits using popular ROP
| compilers.
| Joker_vD wrote:
| Say, if hardware checked that RET transfers control to a
| place that's immediately preceded by a CALL instruction,
| would that help?
| cryptonector wrote:
| A shadow stack of return addresses would help.
| saagarjha wrote:
| It would help but it wouldn't solve ROP. I think it would
| probably be less useful than gadget reduction, honestly,
| since there are a lot of useful sequences after a call
| instruction.
| deadbeeves wrote:
| That would disable certain mechanisms that are
| occasionally useful. For example, to implement user-mode
| context switches and function hooking.
| IshKebab wrote:
| ARM's Branch Target Identification does something similar
| to that (but for jumps & calls, not returns).
| fullspectrumdev wrote:
| Not to mention there are other methods, like JMP oriented
| programming (someone's even written some papers on that, and
| tools for it).
|
| Also worth noting: the mov being Turing complete paper.
| titzer wrote:
| All of this complexity is one of the key reasons that Wasm does
| not have an addressable stack (it is fully virtualized in the
| execution semantics). That moves the management of stack-
| allocated data structures up a level, but guarantees that the
| machine has control flow integrity (CFI) built in.
| Findecanor wrote:
| Code compiled to WASM typically also have a stack in the linear
| memory for storing the program's data structures and values
| that would need to be dereferenced, thus without any
| protection. Only the "local" variables and the operand stack
| are protected.
|
| "Control-Flow Integrity" can have a general sense, or a
| specific sense. In the general sense, it means that function
| pointers and return addresses are protected -- and WASM
| protects the raw function pointers.
|
| In code compiled to WASM, a function pointer is represented as
| an integer indexing into a single global list with all
| functions. The "call_indirect" op checks only that the index is
| within bounds and that the function type signature of the
| function you look up matches.
|
| In the specific sense, as in the 2005 paper titled "Control-
| Flow Integrity: Principles, Implementations, and Applications",
| it refers to the code also enforcing that a _right_ function
| pointer is used at each indirect call site. Each site has a
| list of allowed function pointers. WASM does not do this.
|
| (Sorry for the long post but I just don't want people to get
| confused and believe that WASM is safer than it is)
| H8crilA wrote:
| Wait, it's not about addressability, but essentially about type
| confusion - typically data that is not actually a code pointer
| suddenly gets used as such by `ret`. If you are running on a
| machine that can push an integer but pop it as something else
| you're still in trouble. BTW, signed pointers are essentially a
| type check mechanism, where forging types is hard.
| Joker_vD wrote:
| The activation records don't have to be stored in one piece:
| it's entirely possible to have a call stack that stores only
| return addresses _and_ a data stack that stores frames of
| local variables (that 's how you'd normally program e.g. on
| 6502). Which is a scenario that x64 arguably supports too,
| having separate RSP and RBP registers, with RBP-addressing
| being nice and easy and RSP-relative addressing encoded very
| cumbersomely.
| Vogtinator wrote:
| There's AMD shadow stack and Intel CET which do that as
| well. For compatibility, the return address is also on the
| data stack, but verified with the address stack.
| titzer wrote:
| CET complicates software virtual machines in several
| ways, e.g. deoptimization and exception handling. It's
| the wrong solution to a software problem that should
| never have arisen and just makes software even more
| complicated. An unfortunate metastasis of running unsafe
| code without checks for too long.
| johnklos wrote:
| Funny that you use the term "x64", which is a technically
| incorrect way to refer to 64 bit x86 / amd64. If anything,
| "x64" refers to Alpha: 21064, 21164, 21264, 21364.
| Joker_vD wrote:
| If the thing is widely being known as "x64", then "x64"
| _is_ that thing 's name. That's what the word "name"
| means.
|
| And if you want to be picking nits, it's actually EM64T
| or at the very worst, IA-32e. Then again, there are
| actually two versions of this ISA and Intel is currently
| calling its version "Intel 64" (and AMD used to call
| their pre-release version "x86-64", by the way), but
| definitely not "64-bit x86".
|
| Edit: Oh hey, you're the same guy who made that silly
| argument 11 months ago [0]. Never mind me then.
|
| [0] https://news.ycombinator.com/item?id=33097250
| johnklos wrote:
| This is in a thread that's about various CPUs INCLUDING
| Alpha.
|
| Good job ;)
| kjs3 wrote:
| I sure hope you don't call those boxes full of
| electronics being discussed 'computers' since that's
| obviously a technically incorrect way to refer to
| them[1].
|
| [1] https://en.wikipedia.org/wiki/Computer_(occupation)
| Findecanor wrote:
| Clang/LLVM supports such a scheme. It saves other variables
| that don't need to be dereferenced there too. Many
| utilities on several BSDs are compiled with it, but are
| necessarily statically linked.
| <https://clang.llvm.org/docs/SafeStack.html>
|
| It is also the default on Fuchsia, which therefore supports
| shared libraries. <https://fuchsia.dev/fuchsia-
| src/concepts/kernel/safestack>
|
| The problem with these software-based approaches is that it
| is security-by-obscurity, which breaks if the address to
| the safe stack would leak. Like ASLR, it is considered more
| or less broken on 32-bit systems where it is easier to
| allocate significant portions of the address space to find
| where it is _not_ and then do educated guesses. However,
| there have been a few papers using Intel 's MPK or even CET
| to protect it properly, at some performance cost of course.
|
| It was also the model that Itanium used. You got the return
| address in a register and because register windows were
| saved to a separate stack, it thus saved the return address
| there too.
| circuit10 wrote:
| It does make implementing a custom garbage collector harder
| though, maybe they could have come up with a compromise where
| there's a way to walk over local variables on the stack but
| instead they're building GC into the runtime, which is also a
| good solution but having both options might have been nice
| because a custom one can be more flexible and supported by
| runtimes that don't have GC
| titzer wrote:
| We've discussed engine support for stack walking for
| application-level GC within linear memory, but there hasn't
| been a clear win (at least in my mind) over just using a
| shadow stack, which doesn't require walking frames, just
| scanning a memory segment. Opening up the contents of
| executing stack frames imposes a _ton_ of constraints on the
| engine and complexity (e.g. engine now has to maintain
| mappings, support frame modification, etc), that have
| implications for basically all execution tiers. It doesn 't
| seem like the right tradeoff to me.
|
| I've implemented a shadow stack for Virgil, so I am aware of
| how much it sucks. But that doesn't suck as bad as coming up
| with a stack walking protocol and then modifying every Wasm
| engine in existence to support that.
| circuit10 wrote:
| Actually yes, it sounded good at first but it makes
| optimisation and determinism harder for the engines so it's
| probably better not to have it
___________________________________________________________________
(page generated 2023-09-26 23:01 UTC)