| ▲ | pron 3 days ago |
| What about every Java/JS/Python/Rust/Go programmer who ever created a CVE? Out-of-bounds access is, indeed, a very common cause of dangerous vulnerabilities, but Zig eliminates it to the same extent as Rust. UAF is much lower on the list, to the point that non-memory-safety-related causes easily dominate it.[1] The question is, then, what price in language complexity are you willing to pay to completely avoid the 8th most dangerous cause of vulnerabilities as opposed to reducing them but not eliminating them? Zig makes it easier to find UAF than in C, and not only that, but the danger of UAF exploitability can be reduced even further in the general case rather easily (https://www.cl.cam.ac.uk/~tmj32/papers/docs/ainsworth20-sp.p...). So it is certainly true that memory unsafety is a cause of dangerous vulnerabilities, but it is the spatial unsafety that's the dominant factor here, and Zig eliminates that. So if you believe (rightly, IMO) that a language should make sure to reduce common causes of dangerous vulnerabilities (as long as the price is right), then Zig does exactly that! I don't think it's unreasonable to find the cost of Rust justified to eliminate the 8th most dangerous cause of vulnerabilities, but I think it's also not unreasonable to prefer not to pay it. [1]: https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html |
|
| ▲ | johncolanduoni 3 days ago | parent | next [-] |
| I don't think the rank on a list that includes stuff like SQL injection and path traversal tells you much about what language features are worthwhile in the C/C++ replacement space. No developer that works on something like Linux or Chromium would introduce a SQL injection vulnerability unless they experienced severe head trauma. They do still introduce use after free vulnerabilities with some regularity. |
| |
| ▲ | pron 3 days ago | parent [-] | | First, UAF can be made largely non-dangerous without eliminating it (as in the link above and others). It's harder to exploit to begin with, and can be made much harder still virtually for free. So the number of UAFs and the number of exploitable vulnerabilities due to UAF are not the same, and have to be treated as separate things (because they can be handled separately). Second, I don't care if my bank card details leak because of CSRF or because of a bug in Chromium. Now, to be fair, the list of dangerous vulnerabilities weighs things by number of incidents and not by number of users affected, and it is certainly true that more people use Chrome than those who use a particular website vulnerable to CSRF. But things aren't so simple, there, too. For example, I work on the JVM, which is largely written in C++, and I can guarantee that many more people are affected by non-memory-safety vulnerabilities in Java programs than by memory-safety vulnerabilities in the JVM. Anyway, the point is that the overall danger and incidence of vulnerabilities - and therefore the justified cost in addressing all the different factors involved - is much more complicated than "memory unsafety bad". Yes, it's bad, but different kinds of memory unsafety are bad to different degrees, and the harm can be controlled separately from the cause. Now, I think it's obvious that even Rust fans understand there's a complex cost/benefit game here, because most software today is already written in memory-safe languages, and the very reason someone would want to use a language like Rust in the first place is because they recognise that sometimes the cost of other memory-safe languages isn't worth it, despite the importance of memory safety. If both spatial and temporal safety were always justified at any reasonable cost (that is happily paid by most software already), then there would be no reason for Rust to exist. Once you recognise that, you have to also recognise that what Rust offers must be subject to the same cost/benefit analysis that is used to justify it in the first place. And it shouldn't be surprising that the outcome would be similar: sometimes the cost may be justified, sometimes it may not be. | | |
| ▲ | johncolanduoni 3 days ago | parent [-] | | > I don't care if my bank card details leak because of CSRF or because of a bug in Chromium Sure, but just by virtue of what these languages are used for, almost all CSRF vulnerabilities are not in code written in C, C++, Rust, or Zig. So if I’m targeting that space, why would I care that some Django app or whatever has a CSRF when analyzing what vulnerabilities are important to prevent for my potential Zig project? You’re right that overall danger and incidence of vulnerabilities matter - but they matter for the actual use-case you want to use the language for. The Linux kernel for example has exploitable TOCTOU vulnerabilities at a much higher rate than most software - why would they care that TOCTOU vulnerabilities are rare in software overall when deciding what complexity to accept to reduce them? | | |
| ▲ | pron 3 days ago | parent [-] | | To your first point, you're sort-of right, but it's still not so simple. The value of vulnerabilities in V8 or in CPython is affected by their likelihood compared to other vulnerabilities to users using that same product (i.e. in JS or Python code). If I want to know how much I should pay for a screw in some machine, the answer isn't "whatever it costs to minimise the chance of the screw failing regardless of other components". Once the chance of a fault in the screw is significantly lower than the chance of the machine failing for other reasons, there's no much point in getting a more resilient screw, as it would have little to no effect on the resilience of the machine. The rate of vulnerabilities obviously can't be zero, but it also doesn't need to be. It needs to be low enough for the existing coping processes to work well, and those processes need to be applied anyway. So really the question is always about cost: what's the cheapest way for me to get to a desired vulnerability rate? Which brings me to why I may prefer a low-level language that doesn't prevent UAF: because the language that does present UAF has a cost that is not worth it for me, either because UAF vulnerabilities are not a major risk for my application or because I have cheaper ways to prevent them (without necessarily eliminating the possibility of UAF itself), such as with one of the modern pointer-tagging techniques. | | |
| ▲ | johncolanduoni 3 days ago | parent [-] | | I buy that Zig would fit the risk/reward envelope for some projects. My only issue was with using a breakdown of amalgamated CVEs where most of the software would never actually be written in Zig or Rust regardless to demonstrate that. Perhaps that misunderstanding about my claims is most of the source of our disagreement. To your point about V8 and CPython: that calculus makes sense if I’m Microsoft and I could spend time/money on memory safety in CPython or on making CSRF in whatever Python library I use harder. My understanding is that the proportions of the budget for different areas of vulnerability research at any tech giant would in fact vindicate this logic. However, if I’m on the V8 team or a CPython contributor and I’m trying to reduce vulnerabilities, I don’t have any levers to pull for CSRF or SQL injection without just instead working on a totally different project that happens to be built on the relevant language. If my day job is to reduce vulnerabilities in V8 itself, those would be totally out of scope and everybody would look at my like I’m crazy if I brought it up in a meeting. Similarly, if I’m choosing a language to (re)write my software in and Zig is on the table, I am probably not super worried about CSRF and SQL injection - most likely I’m not writing an API accessed by a browser or interfacing with a SQL database at all! Also I have faith that almost all developers who know what Zig is in the first place would not write code with a SQL injection vulnerability in any language. That those are still on the top ten list is a condemnation of our entire species, in my book. | | |
| ▲ | pron 3 days ago | parent [-] | | > If my day job is to reduce vulnerabilities in V8 itself, those would be totally out of scope and everybody would look at my like I’m crazy if I brought it up in a meeting. Maybe (and I'll return to that later), but even if the job were to specifically reduce vulnerabilities in V8, it may not be the case that focusing on UAF is the best way to go, and even if it were, it doesn't mean that eliminating UAF altogether is the best way to reduce UAF vulnerabilities. More generally, memory safety => fewer vulnerabilities doesn't mean fewer vulnerabilities => memory safety. When some problem is a huge cause of exploitable vulnerabilities and eliminating it is cheap - as in the case of spatial memory safety - it's pretty easy to argue that eliminating it is sensible. But when it's not as big a cause, when the exploits could be prevented in other ways, and when the cost of eliminating the problem at the source is high, it's not so clear cut that that's the best way to go. The costs involved could actually increase vulnerabilities overall. A more complex language could have negative effects on correctness (and so on security) in some pretty obvious ways: longer build times could mean less testing; less obvious code could mean more difficult reviews. But I would say that there's even a problem with your premise about "the job". The more common vulnerabilities are in JS, the less value there is in reducing them in V8, as the relative benefit to your users will be smaller. If JS vulnerabilities are relatively common, there could, perhaps, be more value to V8 users in improving V8's performance than in reducing its vulnerabilities. BTW, this scenario isn't so hypothetical for me, as I work on the Java platform, and I very much prefer spending my time on trying to reduce injection vulnerabilities in Java than on chasing down memory-safety-related vulnerabilities in HotSpot (because there's more security value to our users in the former than in the latter). I think Zig is interesting from a programming-language design point of view, but I also think it's interesting from a product design point of view in that it isn't so laser-focused on one thing. It offers spatial memory safety cheaply, which is good for security, but it also offers a much simpler language than C++ (while being just as expressive) and fast build times, which could improve productivity [1], as well as excellent cross-building. So it has something for everyone (well, at least people who may care about different things). [1]: These could also have a positive effect on correctness, which I hinted at before, but I'm trying to be careful about making positive claims on that front because if there's anything I've learnt in the field of software correctness is that things are very complicated, and it's hard to know how to best achieve correctness. Even the biggest names in the field have made some big, wrong predictions. | | |
| ▲ | johncolanduoni 3 days ago | parent [-] | | > BTW, this scenario isn't so hypothetical for me, as I work on the Java platform, and I very much prefer spending my time on trying to reduce injection vulnerabilities in Java than on chasing down memory-safety-related vulnerabilities in HotSpot (because there's more security value to our users in the former than in the latter). That's a good example and I agree with you there. I think the difference with V8 though is twofold: 1. Nobody runs fully untrusted code on HotSpot today and expects it to stop anybody from doing anything. For browser JavaScript engines, of course the expectation is that the engine (and the browser built on it) are highly resistant to software sandbox escapes. A HotSpot RCE that requires a code construction nobody would actually write is usually unexploitable - if you can control the code the JVM runs, you already own the process. A JavaScript sandbox escape is in most cases a valuable part of an exploit chain for the browser. 2. Even with Google's leverage on the JS and web standardization processes, they have very limited ability to ship user-visible security features and get them adopted. Trusted Types, which could take a big chunk out of very common XSS vulnerabilities and wasn't really controversial, was implemented in Safari 5 years after Chrome shipped it. Firefox still doesn't support it. Let's be super optimistic and say that after another 5 years it'll be as common as CSP is today - that's ten years to provide a broad security benefit. These are of course special aspects of V8's security environment, but having a mountain of memory safe code you can tweak on top of your unsafe code like the JVM has is also unusual. The main reason I'd be unlikely to reach for Zig + temporal pointer auth on something I work on is that I don't write a lot of programs that can't be done in a normie GC-based memory safe programming language, but for which having to debug UAF and data race bugs (even if they crash cleanly!) is a suitable tradeoff for the Rust -> Zig drop in language complexity. | | |
| ▲ | pron 2 days ago | parent [-] | | I agree with your observations about the differences between HotSpot and V8, but my general point is precisely that where you want to focus for security is complicated and application-specific, and that the relative risk of different vulnerability causes does matter. As to your last point, I certainly accept that that could be the case for some, but the opposite is also likely: if UAF is not an outsized cause of problems, then a simpler language that, hopefully, can make catching/debugging all bugs easier could be more attractive than one that could be tilting too much in favour of eliminating UAF possibly at the expense of other problems. My point being that it seems like there are fine reasons to prefer a Rust-like approach over a Zig-like approach and vice-versa in different situations, but we simply don't yet know enough to tell which one - if any - is universally or even more commonly superior to the other. |
|
|
|
|
|
|
|
|
| ▲ | pjmlp 3 days ago | parent | prev [-] |
| Ideally neither Zig nor Rust would matter. Languages like Modula-3 or Oberon would have taken over the world of systems programming. Unfortunately there are too many non-believers for systems programming languages with automatic resource management to take off as they should. Despite everything, kudos to Apple for pushing Swift no matter what, as it seems to be only way for adoption. |
| |
| ▲ | pron 3 days ago | parent | next [-] | | > Unfortunately there are too many non-believers for systems programming languages with automatic resource management to take off as they should. Or those languages had other (possibly unrelated) problems that made them less attractive. I think that in a high-economic-value, competitive activity such as software, it is tenuous to claim that something delivers a significant positive gain and at the same time that that gain is discarded for irrational reasons. I think at least one of these is likely to be false, i.e. either the gain wasn't so substantial or there were other, rational reasons to reject it. | | |
| ▲ | johncolanduoni 3 days ago | parent | next [-] | | I’m not willing to go to bat for Oberon, but large swaths of software engineering are done with no tradeoff analysis of different technologies at all. Most engineers know one imperative programming language and maybe some SQL. If you ask them what to use, they will simply wax poetic about how the one language they know is the perfect fit for the use-case. Even for teams further toward the right of the bell curve, historical contingencies have a greater impact than they do in more grounded engineering fields. There are specialties of course, but nobody worries that when they hire a mechanical engineer someone needs to make sure the engineer can make designs with a particular brand of hex bolt because the last 5 years of the company’s designs all use that brand. | | |
| ▲ | pron 3 days ago | parent [-] | | If a language offered a significant competitive advantage, such an analysis wouldn't be necessary. Someone would capitalise on it, and others would follow. There are selective pressures in software. Contingencies play an outsized role only when the intrinsics don't. | | |
| ▲ | johncolanduoni 3 days ago | parent [-] | | My point is that for most of the software world, selective pressures are much weaker than things like switching costs and ecosystem effects. The activation energy for a new tech stack is massive - so it's very easy to get stuck in local maxima for a long time. | | |
| ▲ | pron 2 days ago | parent [-] | | You call it weak selective pressures, but another way of saying it is low fitness advantage. And we can see that because the programming language landscape is far from static, and newcomers do gain adoption very quickly every now and then. In fact, when we look at the long list of languages that have become super-popular and even moderately popular - including languages that have grown only to later shrink rather quickly - say Fortran, COBOL, C, C++, JavaScript, Java, PHP, Python, Ruby, C#, Kotlin, Go, TypeScript, we see languages that are either more specific to some domains or more general, some reducing switching costs (TS, Kotlin) some not, but we do see that the adoption rate is proportional to the language's peak market share, and once the appropriate niche is there (think of a possibly new/changed environment in biological evolution) we see very fast adoption, as we'd expect to see from a significant fitness increase. So given that many languages displace incumbents or find their own niches, and that the successful ones do it quickly, I think that the most reasonable assumption to start with when a language isn't displaying that is that its benefits just aren't large enough in the current environment(s). If the pace of your language's adoption is slow, then: 1. the first culprit to look for is the product-market fit of the language, and 2. it's a bad sign for the language's future prospects. I guess it's possible for something with a real but low advantage to spread slowly and reach a large market share eventually, but I don't think it's ever happened in programming languages, and there's the obvious risk of something else with a bigger advantage getting your market in the meantime. |
|
|
| |
| ▲ | pjmlp 3 days ago | parent | prev [-] | | As proven in several cases, it is mostly caused by management not willing to keep the required investment to make it happen. Projects like Midori, Swift, Android, MaximeVM, GraalVM, only happen when someone high enough is willing to keep it going until it takes off. When they fail, usually it is because management backing felt through, not because there wasn't a way to sort out whatever was the cause. Even Java had enough backing from Sun, IBM, Oracle and BEA during its early uncertainty days outside being a language for applets, until it actually took off on server and mobile phones. If Valhala never makes it, it is because Oracle gave up funding the team after all these years, or it is impossible and it was a waste of money? |
| |
| ▲ | lerno 3 days ago | parent | prev [-] | | Unfortunately Swift is a mess of a language, trying to put as many language features in there as possible. While still not getting close to being a good replacement for Objective-C. AND it's the slowest language to compile among languages with a substantial adoption. It's just pig-headedness by Apple, nothing more. | | |
| ▲ | pjmlp 3 days ago | parent [-] | | I agree with the toolchain problems, the rest we don't need another Go flavour, with its boilerplate and anti language research culture. | | |
| ▲ | lerno 2 days ago | parent [-] | | It is well known that Swift set out in design without any prior knowledge of the language it was replacing (Objective-C), with only the most junior in the team having used it to any greater extent. Instead Swift was designed around the use-cases the team was familiar with, which would be C++ and compilers. Let's just say that the impedance between that and rapid UI development was pretty big. From C++ they also got the tolerance for glacial compile times (10-50 times as slow as compiling the corresponding Objective-C code) In addition to that they did big experiments, such as value semantics backed by copy-on-write, which they thought was cool, but is – again – worthless in terms of the common problem domains. Since then, the language's just been adding features at a speed even D can't match. However, one thing the language REALLY GETS RIGHT, and which is very under-appreciated, is that they duplicated Objective-C's stability across API versions. ObjC is best in class when it comes to the ability to do forward and backwards compatibility, and Swift has some AWESOME work to make that work despite the difficulties. |
|
|
|