201x Filetype PDF File size 1.99 MB Source: www.usenix.org
Benefits and Drawbacks of Adopting a Secure Programming Language: Rust as a Case Study Kelsey R. Fulton and Anna Chan, University of Maryland; Daniel Votipka, Tufts University; Michael Hicks and Michelle L. Mazurek, University of Maryland https://www.usenix.org/conference/soups2021/presentation/fulton This paper is included in the Proceedings of the Seventeenth Symposium on Usable Privacy and Security. August 9–10, 2021 978-1-939133-25-0 Open access to the Proceedings of the Seventeenth Symposium on Usable Privacy and Security is sponsored by Benefits and Drawbacks of Adopting a Secure Programming Language: RustasaCaseStudy † Kelsey R. Fulton, Anna Chan, Daniel Votipka , Michael Hicks, and Michelle L. Mazurek University of Maryland †Tufts University Abstract ties have remained a consistent, and sometimes worsening, Programming languages such as Rust and Go were devel- threat [37], with estimates that 60-70% of critical vulnerabili- opedtocombatcommonandpotentiallydevastating memory- ties in Chrome [13], Microsoft products [7] and in other large safety-related vulnerabilities. But adoption of new, more se- critical systems [12] owe to memory safety vulnerabilities. cure languages can be fraught and complex. To better under- Overwhelmingly, memory safety vulnerabilites occur in stand the benefits and challenges of adopting Rust in partic- C and C++ code—while most popular languages enforce ular, we conducted semi-structured interviews with profes- memory safety automatically, C and C++ do not [43,47]. sional, primarily senior software developers who have worked Relatively recently, Google developed Go [14] and Mozilla with Rust on their teams or tried to introduce it (n = 16), and developed Rust [33] to be practical but secure alternatives to wedeployed a survey to the Rust development community CandC++; these languages aim to be fast, low-level, and (n = 178). We asked participants about their personal experi- type- and memory-safe [34,40]. Rust and Go have been rising ences using Rust, as well as experiences using Rust at their in popularity—IEEE’s 2019 Top Programming languages list companies. We find a range of positive features, including ranks them 17 and 10, respectively—but C and C++ continue goodtoolinganddocumentation,benefitsforthedevelopment to occupy top spots (3 and 4). We might wonder: What are lifecycle, and improvement of overall secure coding skills, as the factors fueling the rise of these secure languages? Is there well as drawbacks including a steep learning curve, limited li- a chance they will overtake their insecure counterparts, C and brary support,andconcernsabouttheabilitytohireadditional C++,andifso, how? Rust developers in the future. Our results have implications In this paper, we attempt to answer these questions for Rust, for promoting the adoption of Rust specifically and secure in particular. While Go is extremely popular, Rust’s popular- programming languages and tools more generally. ity has also risen sharply in the last few years [9,15,34,39,46]. Rust’s “zero-cost abstractions” and its lack of garbage col- 1 Introduction lection make it appropriate for resource-constrained environ- ments, where Go would be less appropriate and C and C++ Secure software development is a difficult and important task. have traditionally been the only game in town. Vulnerabilities are still discovered in production code on a reg- Weconductedsemi-structuredinterviewswithprofessional, ular basis [4,27,38], and many of these arise from highly dan- primarily senior developers who have actively worked with gerous violations of memory safety, such as use-after-frees, Rustontheirproductteams,and/orattemptedtogettheircom- buffer overflows, and out-of-bounds reads/writes [28–32]. panies to adopt Rust (n = 16). We also surveyed participants Despite their long history and the many attempts aimed at in Rust development community forums (n = 178). We asked mitigating or blocking their exploitation, such vulnerabili- participants about their general programming experience and experiences using and adopting Rust both personally and at a company. We also asked about the benefits and drawbacks of using Rust in both settings. By asking these questions, we aimtounderstand the challenges that inhibit adoption, the net benefits (if any) that accrue after adoption, and what tactics Copyright is held by the author/owner. Permission to make digital or hard have been (un)successful in driving adoption and use. copies of all or part of this work for personal or classroom use is granted Our survey population likely represents those who view without fee. Rust at least somewhat positively, since we would not expect USENIXSymposiumonUsablePrivacyandSecurity(SOUPS)2021. those who tried Rust and abandoned it to be members of Rust August 8–10, 2021, Virtual Conference. USENIX Association Seventeenth Symposium on Usable Privacy and Security 597 forums. That said, our survey population comprised people For those with a deeper interest, we recommend the tutorial with a variety of general and Rust-specific development expe- offered in the official Rust Programming Language Book [21]. rience. 26% of respondents had used Rust for less than one year and they often held similar opinions to more experienced 2.1 Corefeatures and ecosystem Rust users. Our results uncovered a wide variety of specific challenges and benefits which can provide novel insights into Rustis a multi-paradigm language, with elements drawn from the human factors of secure language adoption. functional, imperative, and object oriented languages. Rust’s Participants largely perceived Rust to succeed at its goals traits abstract behavior that types can have in common, sim- of security and performance. Other key strengths identified ilarly to interfaces in Java of typeclasses in Haskell. Traits by participants include an active community, high-quality can be applied to any type, and types need not specifically documentation, and clear error messages, all of which make mention them in their definitions. Objects can be encoded it easy to find solutions to problems. Further, participants using traits and structures. Rust also supports generics and indicated that overall Rust benefits the development cycle in modules,andasophisticatedmacrosystem.Rust’svariables both speed and quality, and using Rust improved their mental are immutable by default: once a value is bound to a vari- models of secure programming in ways that extend to other able, the variable cannot be changed unless it is specifically languages. annotated as mutable. Immutability eases safe code composi- However, participants also noted key drawbacks that can tion, and plays well with ownership, described shortly. Rust inhibit adoption, most seriously a steep learning curve to also enjoys local type inference: types on local variables are adjusttotheparadigmsthatenforcesecurityguarantees.Other generally optional, and can be inferred from their initializer. concerns included dependency bloat, limited library support, Rust also supports tagged unions (“enums”) and pattern slow compile times, high up-front costs, worries about future matching, which allow it to, for example, avoid the need for stability and maintenance, and apprehension about the ability a null value (the “billion dollar mistake” [19]). to hire Rust programmers going forward. For our participants, Rust has an integrated build system and package man- these negatives, while important, were generally outweighed ager called Cargo, which downloads library packages, called bythe positive aspects of the language. crates, as needed, during builds. Rust has an official commu- Lastly, participants offered advice for others wanting to ad- nity package registry called crates.io. At the time of writing, vocate adoption of Rust or other secure languages: be patient, Crates.io lists more than 49,000 crates. pick projects playing to the language’s strengths, and offer support and mentorship during the transition. 2.2 OwnershipandLifetimes Analyzing our findings, we offer recommendations aimed at supporting greater adoption of Rust in particular and se- To avoid dangerous, security-relevant errors involving ref- cure languages generally. The popularity of Rust with our erences, Rust enforces a programming discipline involving participants highlights the importance of the ecosystem — ownership, borrowing, and lifetimes. tooling, documentation, community — when developing se- Ownership. Most type-safe languages use garbage col- cure languages and tools that users will actually want to use. lection to prevent the possibility of using a pointer after its Our results also suggest that perhaps the most critical path memoryhasbeenfreed.Rustprevents this without garbage toward increased adoption of Rust in particular is to flatten collection byenforcingastrictownership-basedprogramming its learning curve, perhaps by finding ways to gradually train discipline involving three rules, enforced by the compiler: developers to use Rust’s ownership and lifetimes. Further, we 1. Each value in Rust has a variable that is its owner. findthat much of the cost of adoption occurs up front, while 2. There can only be one owner at a time for each value. benefits tend to accrue later and with more uncertainty; secu- 3. A value is dropped when its owner goes out of scope. rity advocates should look for ways to rebalance this calculus Anexample of these rules can be seen in Listing 1. In this by investing in a pipeline of trained developers and contribut- example, a is the owner of the value “example.” The scope ing to the longevity and stability of the Rust ecosystem. of a starts when a is created on line 3. The scope of a ends on line 5, so the value of a is then dropped. In the second 2 Background block of code, x is the initial owner of the value “example.” Ownership is then transferred to y on line 11, which is why Rust is an open-source systems programming language cre- the print on line 13 fails. The value cannot have two owners. ated by Mozilla, with its first stable release in 2014. Rust’s Borrowing. Since Rust does not allow values to have more creators promote its ability to “help developers create fast, than one owner, a non-owner wanting to use the value must secure applications” and argue that Rust “prevents segmenta- borrow a reference to a value. A borrow may take place so tion faults and guarantees thread safety.” This section presents long as the following invariant is maintained: There can be (a) Rust’s basic setup and how it aims to achieve these benefits. just one mutable reference to a value x, or (b) any number of 598 Seventeenth Symposium on Usable Privacy and Security USENIX Association 1 { 1 { 2 //make a mutable string and store it in a 2 //make a mutable string and store it in x 3 let mut a = String::from("example"); 3 let mut x = String::from("example"); 4 a.push_str(" , text"); //append to a 4 { 5 } 5 //make immutable reference to x 6 //scope is now over so a’s data is dropped 6 let y = &x; //allowed 7 7 //make second immutable reference to x 8 { 8 let z = &x; //alllowed 9 //make a mutable string and store it in x 9 println!("x is {}. y is {}", x, y) //allowed 10 let x = String::from("example"); 10 x.push_str(" , text"); //fails 11 let y = x; //moved ownership to y 11 //make mutable reference to x 12 println!("y is {}", y); //allowed 12 let mut a = &mut x; //fails 13 println!("x is {}", x); //fails 13 } //drops y and z; x owner again 14 } 14 x.push_str(" , text"); //allowed Listing 1: Examples of how ownership works in Rust 15 { 16 //make mutable reference to x 17 let mut a = &mut x; //allowed 18 a.push_str(" , text"); //allowed 19 x.push_str(" , text"); //fails immutable references to x (but not both). An example of the 20 //make second mutable reference to x rules of borrowing can be seen in Listing 2. In this example, a 21 let mut b = &mut x; //fails mutable string is stored in x. Then, immutable references are 22 } //drops a; x is owner again 23 } made(“borrowed”) on lines 6 and 8. However, the attempt to Listing 2: Examples of how borrowing works in Rust mutate the value on line 10 fails since x cannot be mutated while it has borrowed (immutable) references. Line 12 fails in the attempt to make a mutable reference: x cannot have both a mutable and an immutable reference. Once we reach ends. Similarly, the lifetime of a in Listing 2 ends on line 22. line 13, the immutable references to x have gone out of scope and been dropped. x is once again the owner of the value and 2.3 Unsafe Rust possesses a mutable reference to the value, so line 14 does not fail. In the second code block, starting on line 15, a mutable Since the memory guarantees of Rust can cause it to be reference is made to the value. Attempts to make a second conservative and restrictive, Rust provides escape hatches mutable reference on lines 19 and 21 fail because only one that permit developers to deactivate some, but not all, of mutable reference can be made to a value at a time. the borrow checker and other Rust safety checks. We Theownership and borrowing rules are enforced by a part use the term unsafe blocks to refer generally to unsafe of the Rust compiler called the borrow checker. By enforcing Rust features. Unsafe blocks allows the developer to: these rules the borrow checker prevents vulnerabilities com- • Dereference a raw pointer montomemorymanagementinC/C++.Inparticular,these • Call an unsafe function or method rules prevent dangling pointer dereferences and double-frees • Access or modify a mutable global variable (only a sole, mutable reference may be freed), and data races • Implement an unsafe trait (a data race requires two references, one mutable). • Access a field of a union Unfortunately, these rules also prevent programmers from Unsafe functions and methods are not safe in all cases or for creating their own doubly-linked lists and graph data struc- all possible inputs. Unsafe functions and methods can also tures. To create complex data structures, Rust programmers refer to code that a developer wants to call that is in another mustrelyonlibraries that employ aliasing internally. These li- language. Unsafe traits refer to traits with at least one unsafe braries do so by breaking the rules of ownership, using unsafe variant. Lastly, unions are like structs but only one field in blocks (explained below). The assumption is that libraries are a union is used at a time. To use unsafe blocks, the relevant well-vetted, and Rust programmers can treat them as safe. code construct is labeled with keyword unsafe. Lifetimes. In a language like C or C++, it is possible to have the following scenario: (1) you acquire a resource; (2) 3 Method you lend a reference to the resource; (3) you are done with the resource, so you deallocate it; (4) the lent reference to the Tounderstand the benefits and drawbacks to adopting Rust, resource is used. Rust prevents this scenario using a concept weconducted semi-structured interviews with senior and pro- called lifetimes. A lifetime names a scope, and a lifetime fessional software engineers working at technology compa- annotation on a reference tells the compiler the reference nies who were using Rust or attempting to get Rust adopted. is valid only within that scope. For example, the lifetime of To examine the resulting findings in a broader ecosystem, variable a in Listing 1 ends on line 5 where the scope of a wethendistributed a survey to the Rust community through USENIX Association Seventeenth Symposium on Usable Privacy and Security 599
no reviews yet
Please Login to review.