News for hackers. Stuff that matters.
Re:Curl is C by eddieroger on Monday March 27, 2017 @08:20AM (#13967055)
> Of course that leaves a share of problems that could’ve been avoided if we used another language. Buffer overflows, double frees and out of boundary reads etc, but the bulk of our security problems has not happened due to curl being written in C.

He addressed all of those points in the second short paragraph. None of those are C vulnerabilities, they were mistakes made on the part of the developers, not the language. Avoidance of problems in a safer language doesn't mean when things happen, it's the language's fault.

Re:Curl is C by alkonaut on Monday March 27, 2017 @08:41AM (#13967175)
> None of those are C vulnerabilities, they were mistakes made on the part of the developers, not the language.

The point of type system features e.g. Option types instead of nulls, or linear/affine types avoiding use-after-free is to make programmer mistakes turn into compiler errors. Nothing more. There is no point in talking about whether or not something is the "languages fault" or not. We know C is like juggling knives. It's a tool. It has drawbacks and benefits. Being widespread and fast are the benefits. Not turning many forms of programmer errors into compiler errors is the drawback. That means the programmer can't make mistakes because they will be shipped. But programmers invariably make mistakes.

The grandparent argued that for the sample of issues he looked at, a lot would in fact be avoided by the type system of e.g. Rust - contradicting the argument in the blog post (could be because of the small sample though).

I think it's perhaps less important to focus on the number of issues of each kind, and instead look at the severity of them. If the kinds of issues avoided by better type systems are typically trivial issues, but the kind of issues coming from logic errors are severe security issues - then perhaps the case for stronger type systems isn't so strong after all. But I doubt that's the case.

Re:Curl is C by 321983120931 on Monday March 27, 2017 @09:24AM (#13967481)
You can write Standard ML in C if you so desire and only use tagged unions (which ARE the option types of C).

It is not even that laborious, it just requires some discipline.

Re:Curl is C by Chinjut on Monday March 27, 2017 @02:42PM (#13970476)
Discipline is precisely the thing which shouldn't be required to avoid disaster, if a language is to be well-designed (this is a feature of good design in general).
Re:Curl is C by masklinn on Monday March 27, 2017 @08:27AM (#13967093)
> He addressed all of those points in the second short paragraph. None of those are C vulnerabilities, they were mistakes made on the part of the developers, not the language.

They are absolutely the fault of the language, given other languages would have made these bugs impossible.

Errare humanum est is hardly a new concept, blaming humans for not being computers is inane, and in fact qualifies for in errare perseverare diabolicum as out of misplaced pride you persevere in the core original error of using C.

Re:Curl is C by simias on Monday March 27, 2017 @09:49AM (#13967669)
I agree with the gist of your comment but I think it's a bit harsh to say that using C for curl was an error. If I can trust wikipedia the original release of the library was in 1997, at the time it was a perfectly reasonable choice IMO.

I doubt the library would have reached its current adoption levels if it had been written in any other language (and I presume an other C library would've taken its place).

Re:Curl is C by galdosdi on Monday March 27, 2017 @10:32AM (#13968007)
You're speaking past each other. You're talking about "blame" in a moralistic sense, but the other posters just mean simple causation -- "would this fault have occurred if a safer language was used?"

The former sense would be useful... if you want to sue someone or something I guess? But the latter is more useful in real life, so that's what we're discussing

Re:Curl is C by renox on Tuesday March 28, 2017 @06:52PM (#13981591)
Maybe, maybe not: from Wikipedia the first official validation of GNAT (the Free Ada compiler) was done in 1995. So there were already safer languages available.
Re:Curl is C by pjmlp on Monday March 27, 2017 @08:26AM (#13967085)
These are surely C vulnerabilities and contradict the statement regarding zero policy static analysis errors.

#55 -> OOB write via unchecked multiplication

#54 -> Double free in curl_maprintf

#53 -> Double free in krb5 code

#52 -> glob parser write/read out of bound

Re:Curl is C by the_why_of_y on Monday March 27, 2017 @06:20PM (#13972346)
> These are surely C vulnerabilities

Yes ...

> and contradict the statement regarding zero policy static analysis errors.

Not necessarily - I've found that static analysis tools (Coverity etc.) have limitations, and I'd expect them to find less than half of these kind of bugs - serious fuzzing tends to find more.

The static analysis tool has to work with the type system of the language, and C's type system isn't particularly helpful, so the tool has to find a balance between flagging almost every pointer dereference as "potentially a problem", most of them being false positives, and flagging only the small percentage of actual problems that can be unambiguously proven to be problems with the context available inside a single function definition.

(Just stating generalities, haven't looked at the fixes for these bugs.)

Re:Curl is C by mikulas_florek on Monday March 27, 2017 @04:05PM (#13971213)
Double free is not necessary a C issue, but it can be also a program logic issue - I expect to have an object, but it's already deleted. So it's one of

1. object should not exist and the second free is incorrect 2. object should exist and the first free is incorrect 3. object existance is uncertain and the second free must somehow check that

Although I can double-free only in unsafe languages, the wrong logic behind it can be the same in safe languages. It just have different consequences.

Re:Curl is C by xorblurb on Monday March 27, 2017 @05:37PM (#13972020)
Of course it is a C issue, in the same sense that ALL logic errors are in the case you describe -- so either C issues do not exist or you did not manage to find the correct definition: for ex OOB access is caused by faulty program logic, and the consequences are dramatic in unsafe languages. That is an issue of the language, despite you being able to compute OOB indexes in any language. Same thing for double free; the language issue is that the result is catastrophic, not that you can write for ex faulty logic attempting a liberation too early, or an extra one. (Because in safe languages, the result is not as catastrophic as in unsafe languages).

That is the whole concept of safety.

Re:Curl is C by mikulas_florek on Tuesday March 28, 2017 @04:00AM (#13974886)
Let's take some safe language, e.g. c#

1. object should not exist and the second free is incorrect

In C# I can have to variables pointing to the same object, I null only one of them. The second should be nulled too, but it's not. That's a logic error. So in C# I end up with some object that should not be there, but it is. Which is better - doube-free or undestroyed object - depends on use case.

Re:Curl is C by pjmlp on Tuesday March 28, 2017 @06:51AM (#13975511)
The big difference that you are overlooking is that double free leads to memory corruption, with undefined behavior of program execution.

It can crash right away, in a few seconds, minutes, hours later, or never and just keep generating corrupt data.

Having a reference that the GC doesn't collect doesn't lead to memory corruption, just more being used than it should be.

Re:Curl is C by mikulas_florek on Tuesday March 28, 2017 @08:28AM (#13975968)
> Having a reference that the GC doesn't collect

Using such object is/can be as dangerous.

In fact I find double-free safer because it usually crashes (and in my code I do checks so it almost certainly crashes), while in C# I can happily use such object without knowing it. But as I said, it depends on specific use case.

Re:Curl is C by stymaar on Tuesday March 28, 2017 @12:00PM (#13977711)
> In fact I find double-free safer because it usually crashes (and in my code I do checks so it almost certainly crashes)

You don't know what an undefined behavior is, do you ? You cannot be sure it crashes since the compiler is allowed to do anything with the assumption it doesn't happen. It's absolutely legit for the compiler to remove all the code you added to check a double-free didn't happen because it is assuming that's dead code.

See this post[1] from the LLVM blog which explains why you can't expect anything when you're triggering an UB.

[1]: http://blog.llvm.org/2011/05/what-every-c-programmer-should-...

Re:Curl is C by mikulas_florek on Tuesday March 28, 2017 @02:19PM (#13979176)
I know very well what UB is and I bet there is not a single big program which does not have undefined behaviour. I even rely on UB sometimes, because with well defined set of compilers and systems, it's in reality well defined.

I was talking in general about "unsafe" languages. I use c++ in my projects and use custom allocators everywhere, so there is no problem with UB there. The custom allocators also do the checking against double-free.

Re:Curl is C by xorblurb on Tuesday March 28, 2017 @04:51PM (#13980563)
What do you mean by checking against double-free? Either you pay a high runtime cost, or use unconventional (and somehow impractical in C++) means (e.g. fancy pointers everywhere with a serial number in them), or you can't check reliably. Standard allocators just don't check reliably, and thus do not provide sufficient safety.

Anyway, double-free was only an example. The point is that a language can, or not, provide safety by itself. Not just allow you to create you own enriched subset that is safer than the base language (because you often are interested in safety of 3rd party components not written in your dialect and local idioms of the language)

In the case of C and C++, they are full of UB, and in the general case UB means you are dead. I find that extremely unfortunate, but this is the reality I have to deal with, so I don't pretend it does not exist...

Re:Curl is C by mikulas_florek on Tuesday March 28, 2017 @05:38PM (#13980950)
> What do you mean by checking against double-free?

I pay small runtime cost for the check by having guard values around every allocation. At first I wanted to enable it only in debug builds, but I am too lazy to disable it in release builds, so it's there too. Anyway the overhead is small and I do not allocate often during runtime.

> Anyway, double-free was only an example. The point is that a language can, or not, provide safety by itself.

I can write safe code in modern C++ (and probably in C) and I can write unsafe code in e.g. Rust, only difference is which mode is default for the language. On the other hand I have to be prepared to pay the performance (or other) price for safe code.

> In the case of C and C++, they are full of UB, and in the general case UB means you are dead.

I doubt there is a big C or C++ program without UB, does that mean they are all dead? I do not think so.

> I find that extremely unfortunate, but this is the reality I have to deal with, so I don't pretend it does not exist...

I do not like UB in C++ too, but mostly because it does not make sense on platforms I use. On the other hand I can understand that the language can not make such platform-specific assumptions. I can pretend UB does not exist with some restrictions. UB in reality does not mean that the compiler randomly do whatever he wants, it do whatever he wants but consistently. But as I said it twice, it depends on use case. Am I writing for SpaceX or some medical instruments? Probably not a good idead to ignore UB. Am I making writing a new Unreal Engine? Probably not a good idea to worry much about UB, since I would never finish.

Re:Curl is C by xorblurb on Wednesday March 29, 2017 @03:15PM (#13989622)
> UB in reality does not mean that the compiler randomly do whatever he wants, it do whatever he wants but consistently.

There is nothing consistently consistent about UB. The exact same compiler version can one day transform one particular UB to something, the other day to something else because you changed an unrelated line of code 10 lines under or above, and the day after tomorrow if you change your compiler version or even just any compile option, you get yet another result even when your source code did not changed at all.

EDIT: and I certainly do find extremely unfortunate that compiler authors are choosing to do that to us poor programmers, and that they mostly dropped the other saner interpretation expressively allowed by the standard and practiced by "everybody" 10 years ago; that UB can also be for non portable but well-defined constructs. But, well, compiler authors did that, so let's live with it now.

Re:Curl is C by mikulas_florek on Thursday March 30, 2017 @05:00AM (#13993889)
> There is nothing consistently consistent about UB.

Yet, for years I am memmove-ing objects which should not be memmoved. Or using unions the way they should not be used.

> and that they mostly dropped the other saner interpretation expressively allowed by the standard and practiced by "everybody" 10 years ago

Do you have any example?

> that UB can also be for non portable but well-defined constructs.

Do you mean instead of signed integer overflow being UB it should be defined as 2 complement or something like that?

Re:Curl is C by xorblurb on Thursday March 30, 2017 @04:08PM (#13998480)
> Yet, for years I am memmove-ing objects which should not be memmoved. Or using unions the way they should not be used.

There can be two cases:

A. you rely on additional guarantee of one (or several) of the language implementation you are using (ex: gcc, clang). Each compiler usually has some. They are explicitly documented, otherwise they do not exist.

B. you rely on undocumented internal details of your compiler implementation, that are subject to change at any time, and just have happened to not have changed for several years.

> Do you have any example?

I'm not sure that compiler did "far" (not just intra-basic-block instruction scheduling) time-traveling constraint propagation on UB 10 or 15 years ago. For sure, some of them do now. This means you should better use fno-delete-null-pointer-checks and all its friends, because that might very well save you completely in practice from some technically UB but not well known by your ordinary programmer colleague - so likely to appear in lots of non-trivial code bases.

Simpler example: behavior of signed integer overflow. (Very?) old compilers simply translated to the most natural thing the target ISA did, so in practice you got 2s complement behavior in tons of cases and tons of programs started to rely on that. You just can't rely on that so widely today without special care.

More concerning is the specification of << and >> operators. On virtually all platforms they should map to shifting instructions that interpret unsigned int a << 32 as either 0 or a (and same thing for a>>0), and so regardless of the behavior (a<<b) | (a>>(32-b)) should do a ROL op. Unfortunately, mainly because some processors do one behavior and others do the other one (for a single shift), the standard specified it as UB. Now in the standard spirit, UB can be the sign something that is non-portable but perfectly well-defined. Unfortunately now that compiler authors have collectively all "lost" (or voluntarily burned) that memo, and are actively trying to trap other programmers and kill all their users, either it is already handled as all other UB in their logic (=> nasal daemons) or it is only an event waiting to happen...

Maybe a last example: out-of-bound object access was expected to reach whatever piece of memory is at the position of the intuitively computed address, in the classical C age. This is not the case anymore. Out-of-bound object access now carry the risk of nasal-daemons invocation, regardless of what you know about your hardware.

Other modern features of compilers also have an impact. People used to assume all kind of safe properties at TU boundaries. Those where never specified in the standard, and they have been dropped through the window with WPO. It is likely that some code-bases have "become" incorrect (become even in practice, given they always have been in theory with the most risky interpretations of the standard, that compiler authors are now unfortunately using)

> Do you mean instead of signed integer overflow being UB it should be defined as 2 complement or something like that?

Maybe (or at least implementation specified). I could be mistaking, but I do not expect even 50% of C/C++ programmers knowing that signed overflow is UB, and what it means precisely on modern implementations. I would even be positively surprised if 20% of them know about that.

And before anybody through them at me:

* I'm not buying the performance argument at least for C, because the original intent of UB certainly was not to be yielded this way, but merely to specify the lowest common denominator of various processors -- its insanely idiotic to not be able to express a ROL today because of that turn of events and the modern brain-fucked interpretation of compiler authors -- and more importantly because I happen to know how modern processors work, and I do not expect stronger and safer guarantees to notably slow down anything)

* I'm not buying the "specify the language you want yourself or shut up" argument either, for two at least reasons: - I also have an opinion about safety features in other aspects of my life, yet I'm not an expert in those area (e.g. seat belt). I am an expert in CS/C/C++ programming/System Programming/etc... and I'm a huge user of compilers, in some case in areas where it can have an impact on people health. Given that perspective, I think any argument to just specify my own language or write my own compiler would just be plain stupid. I expect people actually doing that for a living (or as a main voluntary contributor, etc..) to use their brain and think of the risks they impose on everybody with their idiotic interpretations, because regardless of they want it or I want it or not, C and C++ will continue to be used in critical systems. - The C spec is actually kind of fine, although now that compiler author have proven they can't be trusted with it, I admit it should be fixed at the source. But would have them be more reasonable, the C spec would have been continued to be interpreted like in the classical days, and most UB would merely have been implementation defined or "quasi-implementation defined" (in some cases by defining all kind of details like a typical linear memory map, crashing the program in case of access to unmapped are, etc...) in the sense you are thinking of (mostly deterministic -- at least way more than it unfortunately is today). The current C spec do allow that and my argument would be that doing otherwise (except if the performance price is extremely highly unbearable, but the classical implementations have proven it is not!). So I don't even need to write an other less dangerous spec, they should just stop to write dangerous compilers...

Re:Curl is C by caconym_ on Monday March 27, 2017 @04:59PM (#13971722)
I don't want to jump on the "Rust fixes everything" train, but lifetimes, scope-based destructors and reference counted pointers seem like they help with this sort of thing beyond just preventing literal accesses of freed memory; they can make sure objects are around when you need them and that they're destroyed automatically when you don't anymore.

Of course, you don't get it all for free; you have to wrestle with mutability and lifetimes, which can get hairy.

Re:Curl is C by coldtea on Monday March 27, 2017 @09:04AM (#13967330)
>Avoidance of problems in a safer language doesn't mean when things happen, it's the language's fault.

Actually that's exactly what it means.

That's the only way people mean "It's because of C". That a safer language would have prevented those classes of errors"

That's regardless whether a more careful programmer would also have prevented them in C too.

Re:Curl is C by _ph_ on Monday March 27, 2017 @09:03AM (#13967318)
Catching these kind of programmers mistakes is exactly what distinguishes a language as "safer". Be it because they are ruled out by the type system, memory system, or at least the run-time checks.
Re:Curl is C by pdpi on Monday March 27, 2017 @08:47AM (#13967216)
> None of those are C vulnerabilities, they were mistakes made on the part of the developers, not the language.

Would you ever declare a bug to be the language's fault, other than compiler bugs?

Re:Curl is C by trav4225 on Monday March 27, 2017 @09:54AM (#13967703)
Personally, I certainly wouldn't.
Re:Curl is C by irishsultan on Monday March 27, 2017 @10:06AM (#13967783)
A compiler bug isn't the fault of the language though (edit: although on rereading you may not have intended to agree with that part).
Re:Curl is C by pdpi on Monday March 27, 2017 @11:27AM (#13968492)
Yeah, even I only put that in there as a way to handle cases (like Rust) where there is a single implementation of the language, which makes "implementation bugs" and "language bugs" one and the same.
Re:Curl is C by trav4225 on Tuesday March 28, 2017 @01:05PM (#13978368)
yeah, agreed.
Re:Curl is C by wamaral on Monday March 27, 2017 @08:29AM (#13967107)
If the language does not prevent these mistakes from happening where it would be possible to do so, isn't the language at fault?
Re:Curl is C by zeusk on Monday March 27, 2017 @10:15AM (#13967848)
But you can't have your cake and eat it too. The language does not implement those checks because perhaps they're not so trivially implementable in the language.

Sure, rust is "safer" than C, but is it a better language? that's arguable.

Re:Curl is C by Aaargh20318 on Monday March 27, 2017 @11:06AM (#13968302)
> Sure, rust is "safer" than C, but is it a better language? that's arguable.

Obviously there are more aspects to a language than safety, so I'll give you that, but yes Rust is a better language than C in this aspect.

Don't forget that programming languages are meant for humans, not for computers. One of the primary goals of a programming language is to prevent humans from making dumb mistakes.

Re:Curl is C by macintux on Monday March 27, 2017 @11:17AM (#13968391)
> One of the primary goals of a programming language is to prevent humans from making dumb mistakes.

That clearly wasn't the case when C was designed.

Re:Curl is C by anp on Monday March 27, 2017 @11:43AM (#13968645)
I'd wager that using C prevents large classes of errors that would be common place in assembly.

That said, colloquial history seems to say that there were plenty of languages which did a better job at that than C.

Re:Curl is C by fiedzia on Monday March 27, 2017 @08:55AM (#13967263)
> Avoidance of problems in a safer language doesn't mean when things happen, it's the language's fault.

My definition of fault is "what should be changed to prevent such error". And you are not going to change developers.

Re:Curl is C by staticassertion on Monday March 27, 2017 @08:10PM (#13972910)
" ... a programming language designer should be responsible for the mistakes that are made by the programmers using the language. [...] It's very easy to persuade the customers of your language that everything that goes wrong is their fault and not yours. I rejected that..."

- Tony Hoar

I think this is a particularly solid point by Tony Hoare (made during his talk on 'the billion dollar mistake', null).

We find it very easy to blame developers for mistakes that really shouldn't have been possible to make ta all.

Re:Curl is C by flogic on Monday March 27, 2017 @09:24PM (#13973227)
I think there needs to be a grain of salt with the billion dollar mistake thing. The really dangerous part isn't dereferencing the null so much as what happens afterwards. If you dereference a null and the program terminates, that sucks. But, you debug it and life moves on. If "something" happens that's a whole different much bigger issue. Rust doesn't have null but you can ".unwrap()" an option type. Which may terminate the program and force you to debug. If memory serves, Haskell doesn't enforce exhaustive patterns. So once again, the program terminates and you're stuck debugging. That's really just life.

Now, I do in general prefer languages "without" null as they generally have more warning about when you can actually encounter null. Though my personal experience says that in sensibly written programs dealing with null isn't that big a deal. Is it a billion dollar mistake? I would have little trouble believing that. However, that would likely make dynamic typing an order of magnitude or two larger in the mistake dept.

Re:Curl is C by staticassertion on Tuesday March 28, 2017 @10:20AM (#13976751)
The quote wasn't really about null - that's just the talk he was giving. It was about checked array indexing.

I would also say there really is no comparison between null, which escapes typechecking, and unwrap, which does not. But that's not my point, nor is it Hoare's. It's that we blame people for problems that are better solved by languages.