a) there is a very good reason why everyone sets segments to maximal size and it's exactly the fact that this crap is *not* free. It's turned off as an optimisation when processor sees that limit is set to maximum.
b) on amd64 segment limits are not verified in 64bit mode. End of story.
c) segments can be changed only when you are running in ring 0, at which point the game is really over. You can switch between the segments present in GDT + your LDT, but that's it. Said that, on anything that runs Linux kernel you will have segments spanning the entire user address space in GDT, making the segment-based protection only as good as your code sanitizer. And x86 instruction set is not well-suited for analysis, to put it mildly; it's not RISC. Prohibiting jumps into the middle of instruction is nice, but how do you prohibit return into the same? And with that added into the mix, you can construct far ret as part of the immediate constant, bugger the stack frame, hit normal ret (which is going to be in the allowed set), "return" to that far ret and there you are - %cs:%eip is set to your data. Arbitrary jump to other code segment... You are still within the same process, of course, but the sandbox boundary is broken through. At the very least you can read any data anywhere in your process' address space, segmentation be damned.