News for hackers. Stuff that matters.
Re:Getting Past C by naasking on Tuesday January 03, 2017 @04:49PM (#13313453)
> i just don't understand why are buffer overflows such a huge problem in C when the same thing is going to come up when trying to work with memory in Rust.

False. Buffer overflows in C can overwrite the program's memory, so it can be hijacked and supplanted with the attacker's code. This cannot happen in Rust (unless unsafe code has the vulnerability), or any memory safe language.

Sure you can implement a safe array/buffer abstraction and use it in your C programs that abort on invalid indexing. Now how many actually do this? Very few given the prevalence of C programs on vulnerability disclosure lists.

Re:Getting Past C by jimmaswell on Tuesday January 03, 2017 @06:48PM (#13314411)
How much does that still happen with DEP and such? Don't OSes not let you write to executable regions or execute from stack/heap by default now?
Re:Getting Past C by openasocket on Tuesday January 03, 2017 @08:55PM (#13315052)
It doesn't help as much as you'd think. With a buffer overflow on the stack, you can overwrite the stack's return address to point wherever you want, and overwrite a bit further to set the arguments to whatever you want, as well as any local variables on the stack. That depends, obviously, on what code is already there, but there's a lot you can do. For instance, if the system() libc function is linked, you can overwrite the return address and arguments to call system("some arbitrary shell code").

Check out https://en.wikipedia.org/wiki/Return-oriented_programming for more information.

Re:Getting Past C by imtringued on Wednesday January 04, 2017 @05:14AM (#13317014)
You don't need to execute the stack. Just use ROP to fill the stack with return addresses that point to "gadgets". Gadgets are basically a single assembly instruction at the end of a function like XOR EAX,EAX and then a RET. Every time a RET is executed the CPU will jump to the next gadget. There are usually enough gadgets inside a program to basically do anything you want.

https://www.exploit-db.com/docs/28479.pdf

Re:Getting Past C by Analemma_ on Tuesday January 03, 2017 @07:14PM (#13314541)
DEP only makes attacks harder, not impossible. It's not a magic bullet for a couple reasons: it's opt-out on non-*BSD operating systems so software might not be using it, and it can be circumvented with things like return-to-libc attacks.
Re:Getting Past C by temac on Tuesday January 03, 2017 @07:38PM (#13314681)
I would like to add that there are starting to be mitigations against attacks modifying control flow, for example CFguard under Windows (which will probably be extended to cover ROP also) but like DEP an ASLR those are only mitigations, not something that would make it useless to care about buffer overflow anymore.
Re:Getting Past C by moosingin3space on Tuesday January 03, 2017 @07:43PM (#13314712)
In order for DEP to render such attacks impossible it would need to have permission bits at the byte level. DEP on most OSes is page-level, so the stack page is marked as non-executable, which turns an attack from executing code on the stack to executing code from the text segment - either through ROP gadgets or return-to-libc.
Re:Getting Past C by lossolo on Tuesday January 03, 2017 @04:56PM (#13313495)
I think he means to work with raw memory so using unsafe keyword and in this case he is right. And you can't implement certain things in Rust if you are on the quest for maximum efficiency without using unsafe.
Re:Getting Past C by naasking on Tuesday January 03, 2017 @06:50PM (#13314423)
> And you can't implement certain things in Rust if you are on the quest for maximum efficiency without using unsafe.

Trading efficiency for safety for unaudited code should be difficult. C does not make this difficult. Rust makes this difficult.

Auditing should be supported for this kind of code. C does not support auditing in any meaningful way. Auditing much easier in Rust since it explicitly identifies code that may be unsafe.

In conclusion, I disagree emphatically that C and Rust are somehow equivalent even when you are dropping down to unsafe code.

Re:Getting Past C by lilyball on Tuesday January 03, 2017 @05:11PM (#13313626)
Working with `unsafe` code in Rust has the same potential issue to be sure, but very little (if any) of your Rust code should be `unsafe`. You can usually accomplish what you want without having to drop down into raw C pointers. And everywhere that you do have to do this is explicitly called out with the `unsafe` keyword so it's very easy to audit.
Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @06:28PM (#13314283)
This is throwing the baby out with the bathwater though.

You need unsafe to do some things in Rust, sure. But usually this code is isolated and auditable, and nowhere near the linecount of the rest of the application. Even the operating systems written in Rust have pretty conservative use of unsafe (redox, Phil's OS, etc). Most of your code won't be working with raw memory operations, most of it will work with zero-cost abstractions on top of raw memory.

Re:Getting Past C by lossolo on Tuesday January 03, 2017 @06:54PM (#13314446)
> You need unsafe to do some things in Rust, sure.

And that's what I wrote.

> Most of your code won't be working with raw memory operations, most of it will work with zero-cost abstractions on top of raw memory.

For some web applications sure but industry is not constrained only to writing web applications especially if you want to get into C market space. In HPC or time/space constraint environments this matter.

Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @07:04PM (#13314496)
I'm not talking about web applications. I'm talking about systems programming. Even the operating systems written in Rust use unsafe pretty conservatively. Servo uses unsafe mostly to talk to native libraries. Rust is used more for lower level programming than it is for webapps as far as I can tell.

You might want to define further what you mean by "raw memory here". Rust lets you work with arrays and vectors and the heap safely just fine. These are designed as zero-cost abstractions over raw memory (slices, Vec<T>, Box<T>). The equivalent C (with relevant bounds checks) wouldn't be any faster. Rust does not let you do things like call out directly to malloc/free safely. But that's okay. The existence of these abstractions means that you rarely have to do this.

> And that's what I wrote.

.... huh? that's exactly why I put "sure" there, that means I agree with that statement, what followed was why I disagree with the conclusions.

Re:Getting Past C by moosingin3space on Tuesday January 03, 2017 @08:33PM (#13314961)
To add to this, I wrote a high a performance packet generator with 100% safe Rust code for a past internship. With the right backend, it could generate line-rate for a 10 Gbit/s NIC.
Re:Getting Past C by nothrabannosir on Tuesday January 03, 2017 @05:13PM (#13313646)
You can't implement certain things in C if you are on the quest for maximum efficiency. Thankfully, one rarely is, because efficiency isn't binary. It's about trade-offs.
Re:Getting Past C by lossolo on Tuesday January 03, 2017 @05:30PM (#13313805)
I could say exactly the same for Rust, that it's not enough even using unsafe keyword and I need to go into assembly. Someone could even say that assembly is not enough and we need FPGA and then ASIC etc. But it's not the point here. The point is that for ex. you can't get safety from out of bounds access without bound checking, doesn't matter which language you use. And bound checking for certain hot paths is not acceptable.
Re:Getting Past C by naasking on Tuesday January 03, 2017 @06:47PM (#13314407)
> And bound checking for certain hot paths is not acceptable.

I think the history of exploits proves that it's always acceptable for server code. The only possibly justifiable place to omit bounds checking is isolated, high performance numerical code, as used in scientific simulations. But this code isn't exposed to the public, so its vulnerabilities aren't important.

Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @06:26PM (#13314267)
> doesn't matter which language you use

Idris.

Re:Getting Past C by lossolo on Tuesday January 03, 2017 @06:30PM (#13314297)
Care to elaborate? I don't see how this can be done without trading space/time over solution without bound checking.
Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @06:53PM (#13314442)
It won't work in all cases :) IIRC Idris will move type info to runtime if it can't prove it at compile time.

Basically, in Idris I can have a function concat which takes a Vector<N, T>, a Vector<M,T>, and produces a Vector<N+M, T>. You can have arbitrary expressions there, and even things like a function which returns a different type based on its boolean argument.

So most signatures will just carry dependencies through, but some things are dependent on runtime input and that's when the "N" part of the type will be tracked at runtime. At least, that's how I think it works.

Dependent types help eliminate large swaths of bounds checks. Not all of them, and I'm not sure how much better it does than a good optimizing compiler.

Re:Getting Past C by lossolo on Tuesday January 03, 2017 @07:57PM (#13314772)
> I'm not sure how much better it does than a good optimizing compiler.

It can be done by static analysis by compilers in other languages also. Knowing size at compile time is easy most of the time and we are not talking at all about this case. Your answer that Idris solves that is wrong in the context that this discussion started (dynamically allocated memory/not knowing the size compile time). You still need to trade time/space comparing to solution without bound checking, doesn't matter which language you use.

I am getting info that I am submitting too fast? so answer to your other comment will need to wait.

Re:Getting Past C by Manishearth on Tuesday January 03, 2017 @08:56PM (#13315057)
Yes, it can be done by static analysis, but by making size dependencies part of the API it makes the static analysis much easier and able to cross API boundaries without needing to inline, on the contrary most optimizers will not handle such invariants across a few layers of function calls. Like I said, Idris doesn't solve this problem completely, but it is able to eliminate bounds checks in way more situations because the default is effectively no bounds checking.

The nice thing about dependent types is that in all the cases where you don't need a bounds check -- where a program invariant enforces that you are within bounds -- your code will not contain a bounds check regardless of optimization. Only in the cases where there are runtime dependencies that can't be resolved will there be issues, and in thee cases you need a bounds check anyway.

It's not perfect/complete, and like I said optimizers can get most of the way there anyway. I just wanted to note that there are better solutions for bounds checking.