NDC TechTown 2023
Secure development with C++ - Lessons and techniques - Helge Penne - NDC TechTown 2023
Estimated read time: 1:20
Summary
Helge Penne shares insights into developing secure software using C++ at NDC TechTown 2023. Representing Talis, a company that prioritizes security, she talks about the challenges faced while making software resilient against cyber threats, particularly from capable adversaries like nation-states. Helge emphasizes employing redundancy similar to other industries, enabling compiler warnings, and using static analysis and sanitizers. The importance of using modern C++ practices and testing methodologies like fuzzing is highlighted as essential steps. Additionally, the need for strong architecture, avoiding crude thread-based synchronization, and considering security from the language level is stressed, concluding with a call for security to become a larger priority within C++ development.
Highlights
- Helge Penne discusses techniques used by her company, Talis, to tackle secure software development in C++. 🚀
- Nation-states are real threats to Talis' products, making security paramount. 🔒
- Redundancy in design, similar to aerospace strategies, is key to robustness. ✈️
- Static analysis and comprehensive compiler warnings are bases for designing secure software. ⚒️
- Modern C++ features like smart pointers help mitigate ownership issues. 📌
- Memory bugs are best handled with thorough testing and modern programming practices. 💾
- Use of thread sanitizers minimizes data race issues, influencing better software architecture. 🌐
- The need for an overhaul in security prioritization within programming languages is emphasized. 🔄
Key Takeaways
- C++ development can be made more secure by leveraging redundancy, similar to other industries like aerospace. 🚀
- Compiler warnings and static analysis should be exhaustive; don't ignore those warnings! 🛡️
- Use smart pointers wisely to avoid ownership and lifetime issues in C++. 🤔
- Always test with sanitizers and incorporate fuzzing for better software resilience. 🔍
- Avoid naive reliance on user-written bounds checks; automatic checks or alternative libraries can be more trustworthy. ✔️
- Consider architectural designs that naturally avoid multithreading pitfalls. 🏗️
- Security overrides speed; opt-in is preferable for rapid execution over default insecure modes. 🚦
Overview
The NDC TechTown 2023 session, led by Helge Penne, emphasized the importance of security in C++ development, drawing on experiences from her work at Talis. Against a challenging backdrop of potential nation-state adversaries, she highlighted the critical need for designing resilient software through methods inspired by redundancy in fields like aerospace.
A significant portion of the talk revolved around leveraging compiler warnings and static analysis tools, which are essential for catching security vulnerabilities early. Furthermore, Penne underscored the necessity for adopting modern C++ practices like using smart pointers to manage resource ownership, thus minimizing potential security risks.
Helge also addressed broader concerns within software development, advocating for robust testing methodologies, the need for better thread management techniques, and a shift in programming language priorities to favor security over performance by default. This includes incorporating automatically safer options within codebases, ensuring a comprehensive defense against exploitation.
Chapters
- 00:00 - 03:30: Introduction and Defining Secure Development The chapter introduces Helena from Talis, a company focused on software architecture and development. Helena discusses insights gained from efforts to develop secure software using C++.
- 03:30 - 06:30: Building in Redundancy for Software The chapter discusses the role of TS Norway, a subsidiary of the larger French company tals group, which operates in various sectors like Aerospace, Defense, and Communications, focusing on aspects related to security and safety. In Norway, TS (tles) specializes specifically in Secure Communications, employing around 200 people in Oslo and its other location.
- 06:30 - 10:30: Authoring Phase and Compiler Warnings The chapter discusses the challenges and considerations during the authoring phase of software development, particularly focusing on the handling of sensitive user data and encryption keys. The potential threats are highlighted, noting that attackers can include nation states. This underscores the critical need for security, especially when using programming languages like C++ for development.
- 10:30 - 13:30: Static Analysis and Memory Bugs The chapter titled 'Static Analysis and Memory Bugs' discusses the inherent distrust in software systems, emphasizing the importance of preventing unauthorized access and advancements by attackers. Although there is an acknowledgment of the necessity for software to communicate externally, which introduces vulnerabilities, the focus remains on safeguarding the system from potential breaches. The chapter outlines strategies to deter attackers from gaining a foothold within the system, despite the challenging threat model posed by necessary external communications.
- 13:30 - 18:00: Handling Modern C++ and Pointers This chapter discusses the challenges of handling modern C++ and pointers, particularly in the context of ensuring zero exploitable defects in software. It acknowledges that achieving zero defects is theoretically impossible, as evidenced by high bug counts in software. The chapter stresses the importance of reducing these defects and prioritizing the elimination of exploitable bugs.
- 18:00 - 23:00: C++ Integer Handling Issues This chapter draws a parallel between handling complexity in C++ integer operations and redundancy in aircraft systems. It suggests that just as aircraft are designed with redundancies to ensure no single failure results in disaster, C++ systems should be designed with similar strategies to manage bugs and failures effectively.
- 23:00 - 27:30: Testing and Fuzzing The chapter discusses the importance of creating redundancy in software development to prevent exploits caused by single program mistakes. It compares this approach to the safety measures in aviation, such as having two engines or two pilots. The chapter follows the path of a bug from its creation, through the review process, to its release, aiming to enhance software reliability.
- 27:30 - 34:00: Implementing Safety in C++ The chapter delves into the implementation of safety measures in C++. The speaker discusses the deployment phase and suggests introducing various mitigations to prevent bugs from becoming exploitable. The 'authoring phase' is highlighted as a significant stage where safety can be enhanced. The speaker plans to briefly cover several topics while elaborating on others, starting with some foundational aspects before progressing into more detailed discussions.
- 34:00 - 37:00: Summary of Authoring Phase The chapter provides guidance on handling compiler warnings during the authoring phase. It emphasizes enabling all possible warnings to identify security-related bugs and missed initializations. The basic but essential step is to ensure that all warnings are treated seriously, to the extent that they should prevent the build from proceeding if not addressed. The advice concludes with a strong recommendation for using 'Werror' to ensure that any warning stops the build, encouraging compliance and thoroughness in development.
- 37:00 - 41:30: Review Process and Fuzzing The chapter focuses on the review process and fuzzing techniques in software security. The speaker emphasizes the importance of static analysis tools like Clank tidy, which is free and recommended for use. Although commercial tools can potentially detect more issues, they are often not the primary source of finding security issues. Many security vulnerabilities are typically discovered through other methods. The chapter also touches upon memory bugs, although they are considered somewhat mundane or 'boring' at the outset.
- 41:30 - 46:00: Runtime Bug Management The chapter titled 'Runtime Bug Management' discusses best practices for managing bugs during runtime, especially in programming with C++. It suggests avoiding outdated C APIs for memory and strings and instead advocates for using modern C++ features. By leveraging modern C++ practices, programmers can effectively bypass issues associated with older C elements. The chapter also emphasizes the importance of thorough testing and employing robust tools to identify and address bugs. Tools like sanitizers are highlighted as effective resources for detecting and managing runtime errors. This approach helps maintain code quality and stability, ensuring smoother runtime experiences.
- 46:00 - 50:00: Importance of Assertion The chapter titled 'Importance of Assertion' emphasizes the need for both unit testing and integrated system testing. It stresses the need to automate these processes and integrate them into a continuous integration pipeline to maintain software quality consistently. The speaker encourages the use of sanitizers as an effective tool in this process, although it seems underutilized currently.
- 50:00 - 59:00: Handling Subscript Operator Safely This chapter delves into the topic of safely handling the subscript operator, especially in the context of modern C++. The discussion highlights different perspectives on using shared pointers, a common feature in C++. While some programmers advocate for using shared pointers extensively, arguing for their convenience, others criticize them due to the additional overhead they introduce. A significant part of the criticism stems from the complexity in managing ownership and lifetimes of objects when multiple shared pointers reference a single object. The chapter emphasizes that while shared pointers provide utility, they require careful handling to avoid ownership and lifetime issues that aren't immediately apparent in the code but are crucial to prevent misuse and potential errors.
- 59:00 - 64:00: Compiler Options for Security This chapter discusses the use of pointers in relation to security, specifically the use of unique pointers versus normal pointers. Unique pointers are praised for their clear ownership semantics, but they have limitations, such as being unsuitable for class dependencies. This limitation often leads developers to use normal pointers or references, which can introduce security vulnerabilities like use-after-free bugs.
- 64:00 - 66:00: Importance of Asset Protection The chapter discusses the challenges and limitations of achieving secure asset protection using existing pointer techniques. It explores the lack of a 'third way' to solve these issues without causing semantic confusion. The speaker suggests the use of custom classes as a potential solution, acknowledging the absence of an ideal method currently.
- 66:00 - 90:00: Conclusion and Q&A The chapter highlights a talk by Sean Parent at C++ Now, focusing on memory safety and the importance of value semantics as the safest alternative. It also mentions the Rust borrow checker, indicating it guides towards the same direction.
Secure development with C++ - Lessons and techniques - Helge Penne - NDC TechTown 2023 Transcription
- 00:00 - 00:30 okay sorry welcome everyone um my name is Helena uh I work for a company called Talis uh where I do software architecture and development uh and I'm going to talk to you today about some things we have learned while trying to make secure software with C++
- 00:30 - 01:00 um so who is TS no way we're part of the tals group which is a big French company we do uh more or less anything related to security or safety so that includes Aerospace defense Communications uh you name it um tles Norway is a bit more focused we're about 200 employees in Oslo and tonim and we specialize in Secure Communications um
- 01:00 - 01:30 and we do some serious work um our user data sorry our system assets uh for some products is user data which may be classified and encryption keys and the would be attackers for what we make is actually nation states which soes you right up um and in C++ well H it sounds barely doable
- 01:30 - 02:00 uh what what saves us is that we do not actually fully trust the software we can't do that uh but still we want to prevent the attacker from getting a a foothold a foot in the door uh prevent the attacker from from getting in and moving further into the system um and the threat model is also a bit difficult the products will need to communicate externally which means that we will have software that has attack
- 02:00 - 02:30 surfaces um and what we really need is zero exploitable defects uh which is in principle impossible um the bug count of software I I did some searching for that and it varies but it's fairly High uh we need to reduce that uh and even more important we need the remaining bugs not to be exploitable
- 02:30 - 03:00 so how do we achieve that well what do other businesses do an aircraft for example is an incredibly complex machine it has millions of ways to fail so so how can we even dare to fly these things well they build in redundancy uh they realize that bugs will happen but you need to design it to engineer it in such a way that no single failure will ever cause a disaster so so you bu you build it with
- 03:00 - 03:30 two engines you have two pilots and so on uh and we should strive to do the same for software no single program mistake should create an exploit so how can we do that can we device some redundancy for software that will help us get there U and I structured this by following uh the path that a bug takes from making it authoring the bug through the review process and release and
- 03:30 - 04:00 deployment and so on so if we can put in some mitigations along this path several mitigations to try and stop the bug from becoming exploitable then maybe we can device something similar um the authoring phas is is possibly the biggest one uh there are a lot of things we can look at and I will skim over some of these and for some I will go in a bit more detail um and it starts out a little bit boring but we have to go through this as
- 04:00 - 04:30 well compiler warnings basic stuff enable everything you can uh this will find some security related bugs uh initializations that you have missed things like that basic stuff but you need to do the basics as well and of course the warnings must break the build I assume that you all run with W error and if you don't just sneak back home and fix it
- 04:30 - 05:00 um static analysis as well uh Clank tidy is free you should use it uh there are commercial tools that you can buy that will find possibly more stuff uh we do find that this has some benefits but in reality uh most of the security issues that we find we find in other ways um memory bugs also a bit boring to begin with um
- 05:00 - 05:30 you should of course avoid the old C apis for memory and strings um there are other talks about this I won't go into details um you should use modern C++ you want to use modern C++ so you know avoiding the old C stuff is not that difficult um and you need to do tests and use good tooling to detect these problems uh there are good tools the sanitizers are great uh also free use
- 05:30 - 06:00 them uh you need to run this on unit tests but you also need to test the whole system integrated which is a bit more difficult and you need to automate this put it in your continuous integration Pipeline and do this all the time and this will catch a lot of stuff this is really good so go use those how many use the sanitizers okay not bad could be more but please try them they are great um
- 06:00 - 06:30 and for modern C++ small pointers of course uh there are different schools of thought here uh some people love share pointer and use that for everything and some people frown upon that uh it has extra overhead uh and the frowning comes from the second Point here the ownership and lifetimes can get difficult to reason about if you have an object and you have 10 shared pointers to that how long does it live who actually owns it code doesn't show it but it does prevent use of
- 06:30 - 07:00 free which is good especially for security uh the other alternative is unique pointer um the owner holds it fine the semantics are great you can see who owns it and who doesn't um problem with that is that if you want to have class B having a dependency on C over there you can't use unique pointer so you have to use some other way and we tend to resort to normal pointers of references which makes it possible for use after free bugs to creep in so it's
- 07:00 - 07:30 not ideal I sometimes wish there was a third way where you could solve this as well in a secure way uh but it doesn't exist you could try to mimic this with sharp pointer and weak pointer but that kind of mixes this up mixes this up semantically uh with this normal user share pointers which are which will confuse things so I'm not sure if we have a great solution for that at the moment you could make your own classes for this it's not a bad
- 07:30 - 08:00 idea um there's a good talk by Sean parent at C++ now this spring which talks about memory safety among other things and uh it's really worth a look it's good um his conclusion is that value semantics is the only safe alternative um and U incidentally this is also the direction that the rust borrow Checker will push you in if you try that way um it
- 08:00 - 08:30 also sort of rhymes with what Robert Secord said this morning um C plus will never be Memory safe unfortunately so you just have to do the best you can taking a step back um we do protocols a lot where do the vulnerabilities and protocols come from well probably you're reading or writing
- 08:30 - 09:00 outside your buffer so maybe your arguments to the subscript operator is out of range um or similarly for pointer arithmetic I do not recommend pointer arithmetic by the way please don't uh why does this happen well maybe you have an attacker that sends you an input that causes integer overflow and then you use the bad results as an index so overflow is a really important issue
- 09:00 - 09:30 and in my opinion C++ and C integers are fundamentally broken uh Expressions promote to int or unsigned even though you don't ask for it um and when you use the result it gets converted back to smaller types silently and it gets truncated if it needs to changes the value and also overflow is silent and nothing about this is secure
- 09:30 - 10:00 it was a reasonable design choice at the time in the 70s but that's a long time ago there were no attackers there were no hackers at that time it doesn't fit well nowadays so what do we do well we can try and fix some of the conversion problems um yeah let's see if the code examples work this is just a primitive simple program
- 10:00 - 10:30 uh here we go oh that was a bit small anyway can you read that good uh it creates an 8bit integer and then it inverts the bits simple enough uh let's see now if we run that you would think that this would output 33 he but it doesn't it inverts also the extra bits that you get because it's
- 10:30 - 11:00 promoted to in so a bit confusing uh and then it get when you come up back to small types truncates uh there are some good warnings you can enable for that um which means that every time this happens you get a warning and because the warnings break you build then you need to do something you need an explicit cost uh for explicit costs we use static cost but that just suppresses the problem again so what you actually need to do is to
- 11:00 - 11:30 implement your own cost which will trap any conversions that course um bits to be thrown away uh that makes it a lot safer there is nothing like that in the standard library but it's easy to build and also even worse this is a bit subtle you don't see this every day but make shed is broken in this way because your Constructor will be called inside
- 11:30 - 12:00 the implementation of these functions and all warnings are disabled in the standard libraries no warnings at all they can do anything they want it just compiles um which is a bit concerning let me show you that so simple oh sorry wrong window again I'm not sure how to fix that uh anyway um simple class takes an 8bit INT
- 12:00 - 12:30 in the Constructor and then puts that in a variable and I initialize that using unique pointer I have the warnings enabled and the compiler gives me a nice uh error output but if I use the second line instead and use make unique then h no Compass just fine and the output is
- 12:30 - 13:00 wrong no warnings which doesn't go well with security so you actually need to write your own replacement functions if you want to fix this um it's the only way it's simple but it's a bit annoying um same goes for in place back it's also broken you can't fix that because that's a member function but you don't really need them Place
- 13:00 - 13:30 back very often it's the optimizer will make push back just as efficient in many cases um and then there's a bigger problem the Overflow unsigned integer overflow is allowed just silently wraps which is not very secure signed integer overflow is UN is undefined Behavior which is worse if you have a program that needs to be secure then you cannot have any undefined Behavior anywhere
- 13:30 - 14:00 so do pull requests help this nah not much the errors are subtle they're hard to spot we've had several bugs that we have found through other means that pass review that was a critical security critical uh problem is that the abstractions get in the way the way you reason about Expressions uh well when you do that mentally you think in perfect numbers it's very hard to to think in terms of what the uh compiler will do you're not trying to
- 14:00 - 14:30 do that and also overflow issues are incredibly complex um Robert Seal's book which you should read it's very good he spends 84 pages on inter security um reasoning about this if it's a simple addition is doable but once you get into more complex uh expressions with multiplications and such it's incredibly complex um hypothetical example this is just a function that tries to receive a
- 14:30 - 15:00 packet of data and decode the payload so there's a header and a payload so the header has a length field um and the code tries to see if the packet is big enough is their payload after the header so it just takes the length field subtracts the header size and checks if that is bigger than the required size for the payload and if it is then it returns a deserialized deserialized payload uh problem with this is that the length field is
- 15:00 - 15:30 probably unsigned and if the attacker sends you a header with a length that is smaller than the header size then this underflows and it becomes very large so it's always true and you try to deserialize data that isn't there and you get a buffer uh well you read outside your buffer and you have a security vulnerability um but the equation looks just fine the way you're trained to think about this because you think in perfect numbers you could fix this by just moving the
- 15:30 - 16:00 header size to the other side of the equation and you don't have a subtraction anymore but these things are hard to spot so in a way the language is the problem and the inability to detect overflow is is terrible for security and also the implicit conversion and truncation and this is from a time before hackers I'm not accusing anyone of doing a bad job here it's just that the time has passed and the situation is different
- 16:00 - 16:30 so what do you do well you have to first test everything all your attx services uh how many people use fusses oh that's not many uh good for those who do if you have software that needs to be secure you need to fuss things uh the tests will find some bugs but the fers will find much more uh I can't go into detail on this
- 16:30 - 17:00 but there are great talks about fuzzing and and if you write software that could be attacked then you absolutely need to do this and you also need to test the coverage does the fesser actually exercise all the code uh it's an incredibly powerful tool I strongly recommend that you do this um but it would be better if we could actually find some of these bugs um chander Cruz had a talk uh a while ago where he recommended using signed integers for
- 17:00 - 17:30 everything um it's on YouTube you can have a look at it uh his argument was that the edge cases are further away uh you typically use numbers that are small and around zero and uh the feeling was that was dangerous because zero was the edge case uh this puts the edge cases as far away from zero as possible and then the the uh the undefined Behavior sentier could detect any overflows this is what uh Robert SE was ranting about in his
- 17:30 - 18:00 talk uh last year uh there are some problems with this uh you introduce undefined behavior in a code which is bad uh you don't want that if it's supposed to be secure you don't want that in any case uh and also semantically signed ins are often a poor representation of the domain as the length of a vector will never be negative uh the big problems is that the edge Cas is up other way uh because you are more more likely to forget to test them but the attacker will test them
- 18:00 - 18:30 because he knows what to look for and also it muddies the waters because many of your Expressions will be signed oh sorry unsigned anyway uh you start with a length of a vector and you do some arithmetic on it that's still unsigned so this is not pure and then Robert secot had this talk last year where he says you should prefer unsign inages uh especially when it fits the problem at hand and then you test with the sanitizer because the undefined
- 18:30 - 19:00 Behavior sanitizer has also tests for unsigned IND overflow even though that's not undefined Behavior this is not welln um challenges with this this will detect intended overflow as well and even some of the standard libraries do this so you will need some suppressions uh surprisingly few so this is perfectly doable um and of course the normal caveat testing is never perfect but this is an interesting technique I I
- 19:00 - 19:30 really like this one uh so how well does this work but J say he well un Su to jflow checking is not implemented and there are some problems with detecting signed integer overflow as well let's see ah now it almost in the right place good so this is a simple program that creates
- 19:30 - 20:00 a variable B which is the has the maximum size for assigned int and then we add one to it so it overflows which is UB and then we test it and it returns one or zero one or two uh this one return to it's compiled with the sanitizer on to detect this but it didn't it ran anyway which is bad um let's see but this is comp with
- 20:00 - 20:30 optimizations and if I turn those off see it detects the error correctly so GCC um concludes that there is undefined Behavior it runs it through the optimizer and it exploits the undefined Behavior to do whatever it wants and then it instruments it with the sanitizer which is too late because it's not detected so this doesn't work at all uh for cling well that works as
- 20:30 - 21:00 expected um and it gets trapped even with optimizations on so this is great this works really well uh and there's a special uh sanitizer mode that's just called integer that catches everything signed unsigned uh truncation all of it so you need to use kind if you want to
- 21:00 - 21:30 do this you can't use GCC um other Solutions um there's a library called boost safe numerics which is really interesting um he defines integer classes and all the operations on them and it will trap at runtime any of these problems so it fixes the root cause uh of course increases compile and runtime a bit and your code will look slightly different I haven't by this but it looks really interesting if you want
- 21:30 - 22:00 or you could use rust fixes all that rust has this under control but sometimes you have to stay in C++ for various reasons um another security isue uh which is really important data races I kind of like this one uh this is a picture from milla's offices and someone put a poster up and says you have to be this tall to write multi-threaded code and as you can see he he doesn't he doesn't qualify is too shorts we all
- 22:00 - 22:30 are um there is a sanitizer for this as well the thread sanitizer really really good it's excellent um it's always right uh when you run it you sometimes think well this is a this is a false positive my code is correct and then you stare at your code for 15 20 minutes and you realize that no the code is broken um we all suck at writing withit code I do the thread sanitizer has proven that I
- 22:30 - 23:00 do and I think you all probably do as well U how many use the thread sanitizer okay uh then you probably know what I'm talking about um the task is simply too difficult but run the thread s run the the thread sanitizer it's it's great on the complete application good test scenarios again you need to have good coverage um it only detects data races that actually
- 23:00 - 23:30 occur so there are bugs that will manifest themselves with a low probability so you have to run it for a long time you have to run it on all your your pushes uh and on all your long-term tests run it every night run it on all changes put it in your CI pipeline uh what we've learned is that the note on the wall should be higher up uh and you you need to fix this in your architecture you need to device an
- 23:30 - 24:00 architecture that avoids using basic Primitives like threads and mutexes in in code that you write on a daily basis uh actors are good active objects are similar um that makes the problem a little bit easier so no no basic Primitives this is hard sometimes but the basics are not good enough extractions abstractions um so to summarize the
- 24:00 - 24:30 authoring part uh what you end up with is a monster pipeline in your uh continuous interogation system uh you need to run with a large number of sanitises on your unit tests on an automated F System test and on first test and also the optimization level matters uh due to UB and as we saw with GCC 02 made a differ so you need to run this also both on
- 24:30 - 25:00 debug and release um and you need passes for all your attack services so this is a big investment but it really pays off um so if we write a bug what happens in the review process um I strongly recommend you use B request most of you probably do uh you need to promote a good review culture where you don't argue about formatting leave that to Fang format or other tools
- 25:00 - 25:30 and you need to focus on on the the important stuff the design and the logic uh I also recommend that you use your CI system to generate coverage reports so that you can check has this code that I'm reviewing actually been tested uh but what we find is that the pull requests do not actually find many security bugs unfortunately but you should still do that for other reasons um if a bug passes
- 25:30 - 26:00 review and makes it into uh the main branch in your git system what what can we do to stop it there well the fussing is important here uh you should do cumulative fussing what you can do with a FES is that you can you can start them out with some good seeds then you have the CI system pass for hours every night when nothing else happens and then when that's done you can keep the state and
- 26:00 - 26:30 use that when you continue again tomorrow and that will accumulate years of runtime for the FES which they sometimes need in order to dig down into your code in a good way and again coverage data is important you need to be able to verify that your fusser has actually tested all the important code and all the important balls and some of them will be hard to reach uh if you do this on a prot and the protocol has check
- 26:30 - 27:00 sums well the fer can't guess the correct check sum so you need to help it a bit and if the protocol has States uh you will also need to create fusses for each and every state in order to to be able to test the logic in each state so it's a bit of work but it really pays off and do not forget forget your third party code um procces can actually be a problem here because if the attacker can
- 27:00 - 27:30 guess what third party code you're using then the attacker can p that code find the vulnerabilities and use those to attack you so if you have third party code someone needs to fuss that either the the person who wrote it or you now what if the bug is activated can we do something at that stage well because some bugs will will s through and be released
- 27:30 - 28:00 um the systems that we make are usually simple in the sense that bugs that terminate are not exploitable so a good a safe program is a dead program if it doesn't run it can't have any security issues but not everybody has that luxury uh so what we can do is to try to trap these at run time and for that we need to talk need to talk about assert um okay assert is
- 28:00 - 28:30 great you should definitely use this use it to check function parameters use it to check other invariants um but it only affects steber builds I guess most of you have used or do use a certain some way um so what about release builds well your program is in a sense a massive finite State machine and the code that you write you write your code based on the assumption that your invariance hold that your
- 28:30 - 29:00 asserts pass your asserts just State the assumptions you have made when you write the logic if the asserts do not hold then you are in a state that you haven't modeled you're in a rogue State Anything Can Happen your whole program is UB uh there is some good literature literature on this they call it the Weir machine uh you could check that out it's it's interesting and and the end conclusion is that if your assumptions do not hold
- 29:00 - 29:30 then your program cannot be allowed to continue because it can't be trusted anymore so you cannot disable asserts in your release builds it's not safe and for that you just need to Define your own macro macro that that also affects re release builds you terminate in debug as normal and then releasee you take the action appropriate for your application
- 29:30 - 30:00 terminate or go to some safe state it depends um I would not recommend just undefining NDB you could do that but there may be other code that depend on this being used in the normal way so so don't change its semantics um the other thing we can look at is the subscript operator uh and this is where I will go into a little bit of a rant mode maybe
- 30:00 - 30:30 uh in under overflow bugs will happen unless you run the sanitizer and release as well I'll get back to that and we need some redundancy some defense and depth um basically you have two Alternatives you can use the subscript subscript operator um but that is undefined Behavior if you go out of bounds and then there is the ad function which hardly anybody uses uh this will throw if you go out of bounds but we all
- 30:30 - 31:00 tend to use the subscript operator now why do we do that well is it because of the Need for Speed well no actually I don't think so it's a premature optimization and if we look at that let's see this is this is a simple program that just sums up uh the values of some
- 31:00 - 31:30 integers um uh let's see if we go over here you'll see that it generates a little bit of code it stops at 3E and this uses the subscript operator as we usually do now if I change that to use the at function what happens nothing it's the same where did the bounce checking go
- 31:30 - 32:00 it's gone this is compiled O2 no 01 sorry so what happens here is that the optimizer looks at this and thinks well you cannot go out of bounds here so it can all be optimized away it's the same code which is a bit surprising so using the subscript operator is a premature optimization in this case um the optimizer will figure out that
- 32:00 - 32:30 this is safe and just remove that so you only pay for the bounce checking if your code is insecure in a sense it's simplifying it but it happens a lot so that's probably not a valid reason and then some people say well user error you should ensure that the index is correct nah that's a no that's naive that's error prone because you will write bugs doesn't matter how clever you are bugs will
- 32:30 - 33:00 happen I think we use it because it's pretty and it's Compact and the code looks nice and we need to stop doing that and all this happens because the priorities of the language are outdated in terms of security at least speed is always the default and security is opt in and the nice API is unsafe and the safe API is unattractive
- 33:00 - 33:30 or even missing for Vector the subs operator is unsafe and at throws but it looks kind of ugly so we don't use it optional is the same and then the really ugly stuff span has a subscrip operator and at does not even exist there is no safe way to use Spam nothing if it was proposed in 2018 and it got voted
- 33:30 - 34:00 out the committee said no didn't like it so security was not a priority in 2018 uh there is some new hope it's proposed again I hope it goes through but it shows that the priorities are wrong and in my opinion um security security should be the default and speed should be oped
- 34:00 - 34:30 in nowadays we need to change this and the optimizer can still get you the speed um look at rust it has balance checking and it's still fast and C++ has got this wrong and things are not changing fast enough in my opinion now we can actually fix this uh all these unsafe operators could Trap by default because
- 34:30 - 35:00 out of bounds access is UB and UB allows anything also bounce checking so it would be back backwards compatible it would not break anything that isn't already broken and the optimizer will will remove the overhead most of the time and we could make some functions for those who still want to be unsafe clearly marked as such this will not be popular yeah yeah you l i I can understand that
- 35:00 - 35:30 uh it will be very unpopular it will be thrown out at the first vote but it would make C++ a lot safer so while we wait you could use a coding standard I assume many of you have one uh and discourage these unsafe operators you could prohibit span um I would recommend that you do that won't be popular I think because
- 35:30 - 36:00 your code will look uglier but it will be safer um there are there are also some other interesting ways to fix this uh you could use the debug version of the standard Library how many people know about that yeah not many um this has bound checking you can use that but it changes the object layout so you need to compile everything including the standard Library itself with this flag which is a bit of work so
- 36:00 - 36:30 I don't think many people do that but there is some other stuff you can do there is a switch that you can turn on that gives you bounce checking it does not change the object object layout and you can also use it in release builds and this works and when I found that I thought well great and then I also got deeply frustrated why is this not on in debug mode this could be turned on by default but
- 36:30 - 37:00 it's not because speed is a priority also in debug mode go figure I can't understand that so this is an easy win if you want to remember one thing from this talk I think it should be this go home and turn it on uh that's for GCC if you use clang it has a different name but it does the same thing this fixes this gives you balce checking at a low cost and you just have to turn it on your in your make
- 37:00 - 37:30 files so what about the overflows well you could actually deploy the sanitizer in your release build and fix it um you will need some suppressions um some of the standard libraries will cause overflows um by by Design a crypto Library will do this all the time um basic string does this so some
- 37:30 - 38:00 suppressions are required the random libraries do this but surprisingly few suppressions are required so this is easy to set up this will give you interet Security on par with rust or Ada or whatever um there are also some compiler options you should look into uh aslr stack protector so on um I will not go into detail about that
- 38:00 - 38:30 here uh but there's a lot of good literature out there that you could look at um this also changes from time to time and do not forget architecture specific protections um if you control the platform if you have a Linux distribution of some sort that you have configured make sure that the stack is non-executable uh if you are on very new arm platforms that's a really cool uh switch that you can use which is called
- 38:30 - 39:00 Branch protection uh the new Max support this um this actually adds some extra instructions to the functions in your program that sign the return value cryptographically and then check the signature on return so if someone tries to do return oriented programming and jump into your functions towards the end to use it as a gadget uh the prog will trap so this protects against uh return
- 39:00 - 39:30 oriented programming which is really cool uh I think Patricia Al is holding a talk later about that technique return on it to programming uh I'll go see it I think maybe you should too um of course someone has already demonstrated a successful attack against this but I'm not sure how practical it is um finally if an attacker is able to trigger a bug and get in is there
- 39:30 - 40:00 something more you can do um yes uh this is not a topic of this talk really it's uh something somebody could talk for hours about I think but it's outside the scope but try to ensure that there is nothing of value to find sounds strange but um do not put your high value Asset in the first process that attacker breaks into so so if you have say a a password
- 40:00 - 40:30 file that you don't want to to leak to the internet put that somewhere else somewhere deeper inside your system um if you look at what banks do uh they tend to put the highest value targets inside dedicated Hardware uh you could go read about that Hardware security modules um if you can't use or afford one of those you can build some something almost as good in software if you put your mind to
- 40:30 - 41:00 it which is an interesting technique all right so where does all this leave us well the good part you can detect integer overflow at runtime even in releases you can get bounce checking if you want to and you should so you can have reasonable redundant protection against buffer overruns and there is lots of good tooling that you should invest
- 41:00 - 41:30 in uh the bad memory errors still possible and will always be possible and the Ugly Part uh data rases complex problematic I don't think they can ever fix that and the the sad part I think security needs to become more of a priority in the language okay um I spoke a little faster than I
- 41:30 - 42:00 planned so I'm ahead of time questions yes okay I can just there is one here does it work oh okay thank you okay it works so thank you for the talk and I have a question about square brackets and add operator
- 42:00 - 42:30 for Vector do you think if we use a high level obstructions say ranes library would it improve the situation in general so the point is in modern C++ you probably don't really need to use both of them like neither square brackets operator nor at operator it's either what you use it's either rench based for or ranches Library which pretty much the same as do eer in Rust yeah that the question yes um yeah
- 42:30 - 43:00 you're right um You should avoid it if you can um but I still see new code written with this so it's hard to avoid at all times but yes if you can avoid using the square brackets operator or the at function then that is even better absolutely thank you yes at the back thank you for a good talk and uh you were wondering about fussing how to get started
- 43:00 - 43:30 uh uh what have you experienced that we can avoid experiencing um getting started is not that difficult um you need to set up the infrastructure um you start out by doing it locally uh and and making fessor is not that difficult you uh have to write a small function that takes some uh simly random input and just puts puts that into your
- 43:30 - 44:00 API and then you build the fer and you run it um but we have had uh we have seen that you you absolutely need to use uh coverage data in order to see what the fer does um and to give it a good start you also need to provide some seats so you uh it will eventually generate good test vectors on his own but if you can if you
- 44:00 - 44:30 can give it a good starting point if you can give it a dozen uh inputs that are actually valid and good and a bit different then it will it will cover a lot more of your code very much quicker so uh some good seeds and coverage it's a good place to start thank you and you made it internally the fer no no uh this is a part of of at least of clang I I don't remember if it's part of GCC okay well I have a colleague here who better at much of this than than me and
- 44:30 - 45:00 he also provided uh some of the examples Theon so thank you for that um so it's free and it's it's easy to start using there was one talk I saw about fing where they joked that you find 20% of your bugs with tests and 80% with fussing so there is some truth to that the really really ugly bugs uh are found
- 45:00 - 45:30 found by fussing uh we have had bugs where we we look at it and and we think well how on Earth did the fusser get there how did it even find that code it shouldn't be able to reach that but it still did yes thank you for the talk I have a question regarding estd span uh I understand like s span was originally with like you is a new save to use it and then it's it's didn't become it yes uh I'm sorry I didn't catch all that yeah you said the ban is to dispan yes
- 45:30 - 46:00 don't use this to dispan yes yes and but is thepan supposed to be that safe tool that people should use yes but my my question is maybe there is a guidelines support library and which has actually bounce check uh span yes so you would prefer to use that one I I would say yes uh to moderate that a bit if you if you don't use the square braet operator or at then fine go ahead and use
- 46:00 - 46:30 Spam but if you find that you have to use the the uh the square brackets the subscript operator then that's dangerous if you use ranges or or range based for Loops then then then it works great maybe just to follow up a question would you encourage people to write the Kang tidy checks to actually verify that you don't use something H because one thing is to yes you say it but then it's it's human control then I mean man all it's
- 46:30 - 47:00 it's not cool right uh you talking about writing your own plank tidy checks yes that's a cool technique I haven't done that myself but it looks really cool uh is it difficult not that much okay yes yeah that would be a really good idea and probably a bit of fun as well okay other things yes uh are there any good libraries uh security libraries so for instance you have let's say you have a vector uh your own sorry you have
- 47:00 - 47:30 a vector class which is safe which he has uh built in bond checking on the Square operator M yeah you could use that um but you can get bounce checking with the standard one as well so I would probably just use that just turn it on with the compile switch um yeah but if you have one and
- 47:30 - 48:00 like it then sure go ahead yes uh the performance compared to to to standard processor on servers or something so is there what are the performance penalties actually okay so
- 48:00 - 48:30 the question is what's the performance of an HSM compared to to running this in a process on a server I don't know I I would expect that um because the HSM is is something that you have to communicate with externally maybe it's a bit slower uh it will be get you much better security um but you can emulate some of that security in a process if you isolate it well if it has a very narrow API you check it extremely well uh there are also some interesting
- 48:30 - 49:00 techniques on servers like Intel sgx which provides some extra protection extra isolation that you could look into um also hsms are expensive yeah um so that was an extreme example yeah thanks yeah it was more to illustrate the importance of hiding your
- 49:00 - 49:30 assets okay yes anything else all right thanks a lot