3 ms·
> So POSIX will probably add a sister to dlsym that returns a generic function pointer type like (void (*)(void)). I think that change would be a mistake: it m
by quotemstr 10y ago
> So POSIX will probably add a sister to dlsym that returns a generic function pointer type like (void (*)(void)).
I think that change would be a mistake: it makes no practical difference on the machines for which POSIX is intended, so this sister function would bloat the API only to satisfy pedantic concerns that don't really matter. Besides, POSIX systems have to keep the traditional dlsym around for compatibility, which further erodes the advantage of your proposed function.
Right now, POSIX mandates by implication that interconversation of function and data pointers works, and I think that's a perfectly reasonable state of affairs. There is nothing wrong with POSIX constraining the C standard.
- wahern 10y agoA year ago I'd probably agree with you. But since then I've researched various avenues of software hardening and I think the future of C programming will begin to increasingly leverage the restriction. For example, C++ class vtables are a prime target for heap overflow attacks because they store function pointers on the heap. And with the anti-ROP measures coming around the corner it's a target that will be increasingly used to create and execute a ROP chain. So, for example, I can easily imagine new compiler modes and coding styles that outright ban casting function pointers to object pointers, and ban casting pointers to function pointers to other object pointers. PaX and W^X don't help you here as the issue isn't writing over code, but writing over pointers to code. Banning those conversions is neither sufficient nor necessary, but nonetheless a very plausible and practical counter-measure. In that context dlsym sticks out like a sore thumb. One of the easiest solutions is to just standardize a routine for returning a function pointer. That's arguably better than forcing compilers to understand the semantics of dlsym. Note that implementations can still support mixing pointer types, and POSIX could even still require it so existing software can continue using dlsym the same way. But it would simplify things for the tooling and runtimes that enforce the distinction. Given that it makes POSIX more consistent with the C standard, it's a win-win.
- quotemstr 10y ago> C++ class vtables are a prime target for heap overflow attacks because they store function pointers on the heap Is that so? The actual pointers should be in .data. The pointer to the vtable is on the heap (or on the stack, or wherever your object lives). In any case, you should be able to use something like [1] to place constraints on indirect calls, right? There are lots of approaches to double checking function calls that don't involve increasing function pointer size. Besides, there are lots of bits of code that depend on function- and data-pointer interconvertibility --- people can stuff function pointers in raw void* cookies to callbacks. Rather than make the effort to make existing code work in this (in practice, new) subset of customary (as opposed to standard) C, wouldn't it be better to just write components in a language that's memory-safe to start with? [1] https://gcc.gnu.org/wiki/cauldron2012?action=AttachFile&do=get&target=cmtice.pdf https://gcc.gnu.org/wiki/cauldron2012?action=AttachFile&do=g...
- wahern 10y agoI didn't mean to imply that you needed to increase function pointer size or otherwise change pointer representations to add such counter-measures. I mentioned tagged pointers in the ancestor post as a classic justification for restricting conversions between object and function pointers. Restricting void conversions for function pointers is just a pragmatic example where part of the burden of implementing and enforcing new language features can be paid by reference to the C standard and the license it affords. It's loosely related to tagged pointers in that both depend on software not abusing the type system too thoroughly. And as problematic as C's type system is, it's not without rhyme or reason. We don't _need_ to rely on the the C standard in any way, shape, or form to implement counter measures. But the function of a language standard is to be a locus for these things, and to help ease the burden of coordinating and implementing changes, and pushing adoption among a wide and diverse community. As for simply just switching to some other language, I don't think that's even remotely realistic. C isn't going away anytime soon, and neither are people going to stop writing new C code anytime soon. People rave about a language like Rust, but there is no language called "Rust". It's constantly being updated, claimed guarantees regarding compatibility notwithstanding. You simply cannot rely on Rust to create a large and complex ecosystem of software yet, and probably won't for awhile. Conversely, when authors of a language like Go adamantly refuse to evolve the language out of legitimate concern for compatibility, people flip out. Language maintainers are damned if they do, damned if they don't. There's no simple answer or approach. C has survived for as long as it has partly _because_ undefined and unspecified behavior provide space for it to slowly evolve through controlled experimentation. And it will continue doing so (and should do so) on its descent just as it did on its ascent.