 which is also sponsored here for the conference. And we produce firewall products and VPN gateways based on OpenBSD. And my talk will be about all the security mitigations we have in OpenBSD. That's also one of the reasons why I've chosen OpenBSD as a base for our products. And so I'm trying to give an overview. So what we have done the past 20 years or 30 years of OpenBSD security mitigations. Let's see at my own slides. Okay, so let's start with the Stack Overflow. That's the very basic security problem you have. That's very old, it's very easy to use. And that's the order when we added mitigations to it. So we started in year 2000. We added a random gap at the beginning of the stack so that it's not always at the same location. It's just within one page, a few bits of randomness and first thing. Then the next thing is non-executable stacks. That's more or less standard nowadays. But there already it started to have some userland followup that needed executable stack for some reason at some time. Next thing is stack protector. That's more or less a compiler features that add some cookies on the stack. And when you return from it and you see that the return address has changed. It will fail by jumping into a terminate function. This was replaced later by Morta by Red Guard. Red Guard is a little bit different because in the stack protector, we only have one random value that's for all functions. And if you find out which is this value, then you can make your exploit in the way that you fake the cookie on the stack and you know it and then you can do it anyway. With Red Guard, we have a full page of random values and it's harder to guess which function is using which value. And there's another thing that the way it's written. We also protect against a Rop attacks because with Rop attacks, you need some instruction and then return and combining those instructions, you find the schedules in all the program. You can make a touring complete program but just using some of the assembly instructions and then the return instruction. And by adding some, but by checking the stack pointer and oring it with some secret and then creating a cookie, it's harder to use that because then you need, you have to know the cookie and you have to know the location to make an overflow, buffer overflow that already constains the right value so that it's continuous. And what was, so then the immutable thing that's rather new, there's the mProtect system call where you can change protections of a page. That means if the attacker can somehow call this mProtect system call, it changes the protection and then it can upload any exploit. So immutable is a one-way call from the process to the kernel, some things are done by the kernel themselves that prevents that you can ever change a mapping. So when the stack is, for example, is non-executable and if you'd say, okay, mProtect, I want to execute it, this mProtect will fail. And you can also not map something else on top of it. That you take an mMap and map it on top of the stack and then you don't see the non-executable stack but have a new one that also is prevented by the system call and un-map also doesn't work. And the last thing is something that Katan has added quite recently. That means that we not only have this random gap at the beginning of the stack, but we move the stack on 64 architectures by whole pages. So here I've made a little picture of that. So this is the random moving of the stack, the advantages that you can have 24 bits and we use one fourth of the available address space on architectures where we can easily implement it. So it's not available for 32-bit architectures but we have it on ARM and on AMD64. So the gap there is to make all the stacks not have the same alignment all the time. It's just moving around by, so you need to have alignment requirements, I guess, but you can just move the stack by some bytes but you have less random nets. So I guess it's not 12 bits because you have some alignment requirements as perhaps 10 bits there. And those stack guard and red guard things that are cookies that you put there where you have the return addresses and when your buffer overflow overrides them, the code detects that and jumps into a termination. So the other thing that the attacker wants to attack is the heap of your program. So that's basically what malloc is working on. And I recommend the talk from Otto yesterday where he's going more into details into that. So we have guard pages that separate allocations. We, within one page we have a random order of the chunks so that you don't know where we end up. You also find bugs because when you are at the end of the page and have an overflow then you run into the gap and it is killed. We have canneries which means that in the place so if you allocate, for example, 12 bytes with malloc and the minimum size is 16 bytes then we have four bytes left. And in those bytes canneries is written some random value and if you override it and you free it then the free release, oh the cannery has been changed, that shouldn't happen. And we also use the mProtect and MMutable system calls so to protect the metadata. So something that malloc only needs after initializes once and don'ts wants to change anymore, we immutable it and we can use mProtect to make pages temporarily not changeable. Malloc has more features. It provides a use after free detection. So you can do several things. You can unmap all the things that you are, so malloc freeze, the program freeze it in malloc, chunks of the page when the whole page is not used anymore. Malloc has the option to give it back to the kernel and when you do that and if an attacker wants to use that or you have a use after free then your program will crash. You cannot do it always because then the performance is degraded but we have clever mechanisms to do it when it's necessary to find bugs. Then there's the uninitialized value problem so when you malloc page there's something in there from your previous allocation. If it was previous allocated otherwise it's zero. When you set some malloc options then it's filled with some junk and when you have programs that use this uninitialized values and assume it's zero they will crash or do something stupid during the test runs. Another thing is that you put in junk after free so if you have a read after free then you will not read the value that's supposed to be there so put some junk and then the program will do some crazy stuff and crash hopefully so that you see the problems during the development phase. We are also adapting our things. We had this SSH bug where we had to use after free between June previous year and February this year and there we had some page reuses or chunk reuses in malloc that gave you a chance of one in 32 tries that allowed some research group to modify the instruction pointer. And what Otto did then at the beginning of this release there were four commits or five commits all in malloc to make that more unlikely to work. So we don't have this strict reusing of chunks and it's harder for the attacker to get this one to 32 chance so now it's much better for us and worse for the attacker. So we limited the chunk reuse because we learned from things that happened and say okay we can do better and we always try to be better. So now I'm going into the return oriented programming. So what do we, that's the thing where you have this, you just have a bunch of pointers and run into a return instruction and it takes this pointer from the stack so you have the attacker writes a pointer on stack then you jump into some gadget run it then there's the next return instruction takes it from the stack, runs another gadget, takes a return pointer from the stack and by using all the instructions from the gadgets you can write your own programs without writing any code into the program space because it's already there. It's just mixing existing assembly instructions. So what we did, we have, we now remark what is stack and what is not stack. So and when you, when the stack pointer points to a page that's not marked as stack, the kernel terminates the program. That means when you do return oriented programming, you have to put your pointers on the stack. If you put it in the heap and tell somehow the stack pointer oh go to there, the kernel will figure that out and then kill you. It's an optimistic thing, the processor has no way to do that but every time you make a system call or the kernel traps, you go to kernel land, this is checked. That's quite easy to see where the stack pointer is and if it's not in an area that's supposed to be a stack then the program will stop. We have the red guard from Mortimer already explained it. So there's one thing, Intel is a very nasty architecture. Usually you have aligned instructions so it's clear what is the return and what not. In Intel, the return has the opcode C3 but C3 can be in any other instructions if you interpret it in a different way. So you have, for example, an 11 byte instruction. The fourth byte is a C3 for some reasons and if you manage to get control over your instruction point and jump trust there then it will be a return and that is a gadget although it was not at the end of a function originally. And you see that if you have a move command, move instruction with the RBX register by incident, that's C3 in the opcode. So our C-length compiler tries to avoid the B register and takes another one if one is available. So we reduce the number of gadgets. Another thing is to use fork and exec that means that you rearrange your memory layout and it's harder to guess for the attacker what's there and what not. So then there's another thing when you have signal handlers. The kernel stores the context of where you were before in user land. So you can have a signal handler and then go to the next signal handler and to the next signal handler and all that context is in user land and then you call secret run, the signal handler does the data and the special system called you can't use it usually from your program. Then these contexts are restored and that is similar to a return instruction. You can also build rock chains out of that. So we store a random cookie at the end of the, in this area where the context of the signal handler is stored by the kernel and if this cookie, this random value is not the one that the kernel thinks this process should have, it's terminated. So you can't do this sickrop attack. With long jump and set jump, you have the same problem. You can also build some some contexts where you can jump around and there we also have some cookies that must be correct. So it's harder for the attacker to build something. Then their next bullet, there are new instructions. BTI in ARM world and IBT in the Intel world. I have no idea why the engineers didn't speak to each other and invented those abbreviations. So there in Intel, you have in ARM, the instructions called BTI and Intel, it's called ENDBR64 and this instruction for all processes that don't support it is a knob, does nothing. For new processes, it means that we have, you can set a pit in the CPU that says if you jump to somewhere with an indirect jump, so you load a value in the register and say jump to there and then it has to end at the ENDBR64 instruction and if not, you get trapped and the kernel kills the process. That means when you have those gadgets that you usually jump in the middle of the function because you only need the final instructions and then the red, it doesn't work anymore because when you jump there, it's an indirect jump and you're supposed to end at the ENDBR instruction. So all the functions that have these features get this instruction in front, then you tell the CPU if that's not the case, terminate and then if the attacker jumps to somewhere else, the kernel will get a trap and then kill the process. And so the final bullet point on this slide is random re-linking. To find the gadgets, you have to know where they are and for example in libc is very attractive, they are the system calls and at every boot, we re-link all the objects and libc is a very good target for that because there are a lot of object files, each libc function has its own object files basically because when you link statically only this code is linked into it and into your program and when you are using dynamic linking, it means you have a lot of object files and you can make a random order of it and it's very hard to figure out where an actual function is even if you have an information leak and you all print have it's there, you have no idea where SCUNF is, just somewhere else. So then we have some protections from the kernel for user land with mapping. So we have the M-protect system call and usually you can say, okay, I want to write, to execute, to read or none, so nothing. What is considered dangerous is having execute and writing simultaneously. That means that you have an exploit code that brings something in your memory and by writing it and then if you can jump to that and then you just run your exploit. Of course you can say, okay, we use all our mappings that this cannot happen but then the attacker may be having a possibility to run M-protect and change your protection and we enforce that you can never set the write and the execute simultaneously. Also for regular programs. So if you have some library imports doing some stuff and it's trying to do that, the process is killed. Or the process is the M-protect fails that there's a CTL where you can choose that. And then the next thing is quite new, it's X only. That means we allow execution but not reading. If the CPU supports it and few CPUs do. If it does not support it, we do it when we go to the kernel and just check it there, we'll have an example later. And that means that you cannot get information leaks. So when you read the values by some printf that has a pointer and read somewhere there, then you read instructions. And when you get that through standard out to your attacker, when he can read your instructions, he can figure out how your memory layout is. He's saying, oh, the lipsy print function is there. But the process doesn't have to know this. Just wants to execute printf does not want to read the instructions. So when you avoid that anybody can read it, the attacker cannot find out where your stuff is but you can still run the program. That's the reason why we want that. Then mapping immutable, I already explained that. You can mark some regions where you cannot use M-protect, M-map or un-map to change it in any way. It's fixed. And we have in M-map to new types, M-map stack I already explained that. When you go to Garnel, the stack pointer has to be there in such a segment and that's somewhere else. And mapconceal that prevents that you write cord arms to the disk. So if you say, okay, here are my crypto keys and now the program crashes for any reason, you won't have that crypto keys on the disk in the cord arm. FreeBSD has a similar option, but it's called differently. I think it's called no cores. Okay, here I just made a picture of the things, how your program address space looks like. You have the stack that's readable and writable, not executable and immutable. You cannot change that. Then when you have a JIT compiler, there you have usually problems with writing the execute. So you have to change the protection. When you write the instructions there, that you're just in time compiled and then you have to make an amp protect and you say, okay, now I want to execute that. And Firefox added an option for, especially for OpenBSD to allow that. They went for a while also for other operating systems with that, but they figured out that it takes 4% of performance. That's too much for the common Linux user. So on Linux, your Firefox has it mapped simultaneously writable and executable and in OpenBSD, not. You have to make a system call to change between them. So the heap is readable and writable and not immutable because it's dynamic. Then you have ESS, that's the data that is zero initialized when the program starts. So if you have a global variable in your C program, but you don't assign a value with zero and it will end in the ESS segment and you can read it, you can write it, but you cannot change it, it's readable and writable. You cannot execute it in any way. So data, that's the initialized variables. They are in the program file and when you start your program, they get into memory. Read-only data, if you have a variable that is const in your program, it's read-only and then it will end up there. You cannot change it and only read it. And text, that's your program. You can execute it and that's it. So hardware is only, I mentioned it. The question is which protection bits the CPU provides and with ARM and RISC-5. We have those bits where you can say, okay, we want to execute it but not read it, but in Intel. You always can read it except for newer processes that have a CPU register where you can say, okay, execute only and not, but that's changeable for user land. But we in the kernel and force it, every time you go in the kernel that it's set correctly and then if you're new CPU, then the chances are high that you get that in hardware that you cannot execute and read simultaneously. So here's an example of what happens when you don't have the CPU feature. So we map a region, one page. So at the beginning it's proton on, so you cannot do anything with it. It's anonymous memory, private to you. No file descriptor, that's the minus one. And then we say, okay, we want to read it. We make a print and we read it there. This address from there and print it. So that's the first line of the output. So it's zero. We just mapped it, it's zero. And then we say, okay, now we want to execute it. There's no read and we read it and print it and it works. So that's clearly a violation. And the reason why we can read it, although it's execute only because I did it on AMD64 and the CPU has no feature to detect it. But we can do opportunistic read XOR execute. That means when the page is not bad. So what you see here, the first print is missing. So here the page is not mapped. We allocate it, it's not mapped. It's just registered in kernel. There should be memory. Then we say, okay, we want to read. And say, okay, we want to execute it. And then we do a read in the printf. And it's not mapped, so we go to the kernel and the CPU tells us why we go to the kernel. We go to kernel because we executed it. We wanted to execute it. And then the kernel says, no, that's wrong. And now he detects the problem and gives us a segmentation fault. So even if the CPU doesn't support it, in the kernel we can, when we go to the kernel at the right time, we can still check it. And the effort was here to get all the programs clean that they make this decision correctly. Was there a question? This is always on. You don't see it. Perhaps, I don't know, perhaps GDB can do it because it's attached to the program, but you cannot see it from the program itself. So I don't know what GDB does. Maybe it can do something there. But in the kernel, we have similar problems. For example, when you have GDB, the kernel debugger and want to change a variable in the kernel and it's usually not a writable map and we change the mapping, change the value and go back. So there are things that you can work around with. So next thing, I talk about randomness. OpenBSD tries to have cheap random everywhere. So we invented new ellipsey functions. That's arg random that gives you a random value and it doesn't block and it's always something random. Other operating systems, if you have something like that, it starts blocking. That means that the program flow is not that easy as the programmer wishes it to have, which means that it's not that likely that uses it and you end up with some get time of day. Arc for random uniform, if you want a range of random number, that's not a power of two. Then the correct way to get non-BSD randomness is, okay, for example, I want numbers between one and 10 and I say, okay, give me a random number and now it's 12. Then I've taken random numbers between 10 and 16, which is next power of two. If it's 12, I just throw the thing away and try it again. That's the usual thing. Otherwise, you get bias when you just do a divide, you get bias random numbers. And so that we added it to the API so that the programmer cannot make this mistake. Then there's S-Rant. That's a very old function to get randomness and it's deterministic. And in OpenBSD, we changed it to be not deterministic. So people that use S-Rant as a crypto randomness source, even on OpenBSD, even that is safe. And if you want to have S-Rant, for example, you have a game and you initialize it and then you have the same game and can repeat it, then you can use S-Rant deterministic with a seed and then with the same seed, you get the deterministic old S-Rant algorithm. So you have to explicitly enable it to get the cryptographically insecure behavior because there are use cases for the others. So GetEntropy is a system called to seed the arc for random pseudo-random number generator. And let's see, you have to want to be fast. We want to provide randomness for everywhere. You don't have to think about it, just use it. But when you have to reseed it, you gain the kernel, this system call does not block and the slip-see calls it whenever it's needed. So when you took too much randomness out of it, this system call is made. When you fork, forking pseudo-random number generators is a bad idea because then you have two processes giving you the same numbers, but it always checks the pit. And if the pit changes, it calls GetEntropy to reseed it in the child. So we have another thing, you need randomness quite early, especially for the stack cookies of the Red Guard. So the kernel can provide a process with randomness before it made the first system call. And it works, we have a special elf header that tells the loader in the kernel, the exec elf, that in this section, in this page, there should be randomness data. And the compiler has made all the access to there, if you need that. And when the process accesses, the kernel pre-fields this with random data. So you can start with random data when you start. And we also have the same mechanism in the kernel. When you boot your system, you also want to have randomness very early. You want to have random physical page layouts and you don't have much entropy collected at that because you just started your CPUs and they are deterministic. So we have the boot loader has the same mechanism and the kernel also has an OpenBSD randomness page or section where the boot loader fills this. So the boot loader loads the kernel, loads ETC random seed from the disk and tells the kernel there's your random data. So the first instruction the kernel is running it has randomness. And when the system comes up, then this ETC random seed is written and it's also written when the system is rebooted. So while you run your collect data, you write it in your disk, you boot the kernel and you have randomness. We make it in user land, we make it in kernel land. So when we have address space layout randomization, we map the shared libraries randomly to somewhere that they are also mapped with the MAP system call in the end, we have the heap that's using MAP as a backup as Otto told you yesterday. We have this stack gap. We have programs static by the binary that's movable. So PAE means position independent executable. You have always that for dynamic libraries, but we also added that for executables for texts so that you can move that around. And we really in Glypsy and the newest thing we do is we really in SSHD because SSHD we consider as a high potential target. So every time you put your computer, you get a new SSHD with random object files reordered. So we added those in this order. So we started with one and six is the newest feature. So we evolve, you're getting better and better. So that's the result of that. So let's start at the top, stack gap, we move the stack around. The heap, it's mapped at random addresses. The heap is not continuously. We have guard pages in between that. If we free the heap, we unmap it. So if you have use after free, you will, the blue thing will be gone and you get killed. The libraries are loaded randomly. They move up and down. And also the program will move up and down because we made it position independent code. The disadvantage of position independent code is that you need an extra register because everything is relative to register, which is a problem on the I386 because it only has four or six registers. And on AMD64, you have more general purpose registers. That's not a big problem. And other architectures have even more registers. So you can look at all this, what I was talking about. So I just called the sleep and then I look at the prog map with it. You see there start and end addresses of each memory region and they are random. And you have those flags. They can see how the mapping looks like. You see that we have a lot of things that are immutable. We do as much as immutable ourselves. You see that the text is X only and not readable. And read only data is not writable. And only the heap is not immutable. So what does the kernel exec do? We have a bunch of checks there. The first one is on this slide because we had a security back in Zoodle on Linux. And the other thing, Zoodle has the Aspid set. And the back in Zoodle was that it was confused if you didn't pass it in argument. So the argument count is zero, which is illegal, but you attack security programs with illegal content. And our kernel had this check and would refuse this attack. Linux didn't have it. Then the kernel makes the stack randomization. The kernel makes the signal cookie key random. If you have some exit patches, that means that you call, that you say, if I exit something, I want to exit these patches. Kernel guarantees that. And for set UAD programs, it also reallocates standard in-out error to define zero if it's closed because by running closed zero, one, two file descriptors, you can do attacks, but not with us. So then the dynamic loader comes, which is responsible for forgetting the end libraries into the address space. It initializes more random data with get entropy. It fixes the immutable permissions because it has to move around stuff. So it's not immutable by the kernel. It's then immutable by the dynamic loader. It uses M-Map to make some random layout. We have another feature that we say system calls are only allowed in this memory region. So that when you have an exploit code, you cannot make a system call from there, except it's the region where it is. The region where it is is Lipsy. You can only make system calls from Lipsy in OpenBSD. And it's immutable. So there's not much to change there. Then the exec system call is considered very dangerous because you can go through a completely different process. There we have pin system call, and then you can make the exec only from those 70 bytes where the code actually is. So all system calls have to be in Lipsy. The exec system call can only be in the few bytes where it is, I think 70 or so. And we have lazy binding with K-bind. With K-bind, you change the got when you do dynamic linking. You have to connect the function pointers in your program to the functions in your library. There you have those pointers in the PLT and the got. And the dynamic loader is responsible for changing that. Classically, everyone can write there, and you're writing to function pointers, not a good idea. Then we start edit and protect. So it's usually protected, but now it's immutable. And you have a special system call where the LDSO can say, okay, we changed this one address here. And it says beforehand what can be changed and only from LDSO, not from another address. This system call may be called. And we have a special cookie, a random value in the LDSO that you have to know to execute the system call. So it's very hard to change something there if you're not the right guy who's authorized. Yeah, so the thing is you, when you do this system call the first time, the kernel remembers where it was called from and only from that address, it's allowed to call it again. So then the pledge is also very famous. There were a lot of talks about it. And the main thing about pledge is which restricts that, what a process can do, that it's easy to use. That means we have a lot of programs that we pledged. So you get this P in the statistics that says, okay, somebody could call pledge here. And when you're running an OpenBSD system, or at least on my laptop, you have 86% of the process pledged. We have unveil, which hides files from the process so that the browser cannot use your private SSH keys on your disk. And there we have 39% unveil. Unveiled is harder to use and pledge is easier to implement. And I prefer pledge because it's a clearer policy and you know what it's doing. And if you do something wrong with unveil, it's hard to figure out if everything works right because the person just doesn't see a file and in some error conditions, there's something wrong and you don't see that. So pledge also helps you to structure your design because it's a programmer tool and you have to move the pledge around and you initialization code around to use it easily. What I've implemented in that, you get this Daily Mail. If you enable process accounting on your OpenBSD system, that means if every process dies, you get a lock entry, it's very useful debugging. You don't know what's going on on the machine. And with Laskom, you see it and if you have a pledge violation or the process is crashed or you have an unveil in validation, then you will see the processes that misbehaved in your Daily Mail and you can debug them and fix them or see if somebody was attacking your computer. So next thing is privilege separation. So the first thing you have to, when the idea is that you've split the user line process and multiple processes, you figure out what is dangerous and has high risk and then you start with socket pairs to communicate between them, you fork them, you change root them, you change the user ID, you pledge them, you set up some, iMessage queuing between them and then you do some file descriptor parsing and then you have split your logic into processes and we have done that for a bunch of them. For example, OSPF daemon, we have the part that's calling to the route socket in the kernel, we have the part that's communicating with the internet that should be different. In RelayD, we have several trials that use that manage the traffic and also SyslogD has a privileged parent which accesses the log files and somebody else who talks to the internet with TLS and something like that. Here we have a slide with fork and exec. Usually when you fork, you have two processes that have exactly the same layout, but one of the, especially the RelayD childs that makes sense to do exec then, use it yourself and then you get everything unmapped and a reordering of your program and the libraries and the heap is gone. So you start with a new random layout and the attacker cannot learn from the previous attack. We made some API changes to make all that possible. So StrelCopy, StrelCut, it's very old, it's much easier to use and to get your memory management correctly. The realloc array, when you do malloc, you usually do a multiply. You have the size of the object and you have the number of objects and you multiply that and you get an integer overflow and then the attacker, then the amount of memory that was allocated and the amount of your memory the program is running with is differently and there you have a common security attack and realloc array, you pass them separately and like colloc and we check in the library that you don't have an integer overflow there. Explicit B0 is to remove your crypto keys. Free zero does that when you call free from malloc, it also explicitly B0 is it. Malloc conceals use the mmapconceal flag to make sure that it's not written to a core dump and in printf we remove the %n option where you can modify memory while you try to print it which is a miss feature and I think we had some new stuff in there and we just removed it from there. Some old object dump, whatever, three of the new tiles. File descriptors, it's very bad to run out of file descriptors so our demons like relay the check with get descriptor table count, how many file descriptors do we have opened? It's a new system called specific to open BSD and don't open too many file descriptors. You should have 10 left or so for a DNS request or previously for some logging. Logging was also fixed by using census log. There you don't need a file descriptor so by running out of file descriptors you can still log because you log directly with a system called to the kernel and with socket you can mark something that's used for DNS and that's important for pledge so you can allow DNS but not some other socket of the things. So everything is downsides and the downsides by our porters because they have to get all the stuff running although the kernel makes it very hard to run programs. So the current pain is BTI and IBT because then the program just fails randomly and you have to figure out why some Rust Ruby Go code has some problems because of something. X only was also hassle because some programs just didn't do it at all. You have assembly where you have data within your executable and now you have to split it. The executable is here and data is there and you have to go through your OpenSSL binary super optimization. Map stack, some people had some signal stacks or some other stacks or some configure script that set up a stack that you have to fix right or execute was also difficult and auto malloc also when I do part some program to OpenBSD I find new bugs because our malloc is more strict. The important thing about our security features is that we turn them on by default and you cannot turn it on or off. So we control the kernel that slips in base there. It's quite easy. We adapt the ports that we learn if our security measures are good or adequate to run the mass majority of the programs for your next systems or if it's too strict or not doable or the ecosystem is not ready for it. And it's the last resort. We can change things to say, okay, now we need some exceptions. For example, if this V is allowed features where you can say, okay, this one needs execution and write in parallel. For example, that's Python. When you load Python objects for some reasons I don't understand. It's not possible to make them execute or XOR writeable. So Python in OpenBSD has this flag and it works. But there are some things that you cannot enable in OpenBSD that's executable stack and this BTI and IBT functions if the CPU supports it we enforce it. In Linux it's differently. There you, the loader sees, oh, there's some program that does not support these features. Let's turn it off. So everything runs but you have to be lucky to do it that it runs securely. So what does it mean to have those policy? For example, there was this exploit in the SSA agent where you use DL Open to load four libraries and DL Open executes the constructors. So when you load a library it's already executing code. And in Linux you can say in your Elf header, okay, I want executable stack. You load one library that says doesn't unload it again. Then you found another library that you loaded that sets a signal handler and then you unload it again. Then you load something else that has the flag noted lead. So it's loaded but not unloaded. And the code that you get is loaded there where the signal handler for the previous library was. Then there's another library in the Linux system that immediately crashes. So you jump with the signal handler from the second library to the code of the third library and because of the first library you have executable stack and make your exploit. Why doesn't it go in OpenBSD? Because we do not allow executable stacks at all no matter what the header file says. So it's important to enforce it. So there are still things to do. ARM has some part of authentication. We still have to implement that. There are shadow stacks. I think there's not much hardware available at the moment. And the next thing, there's a syscall, syscall where you can call any system call and Theo wants to remove that in the next release. And we already changed our Perl so that it will work without it. So what's the main points? So the thing comes from the combination. So for every mitigations you have a way to work around it but then you run it to the next mitigation. We make a compromise between cheap and effective. We also want to run programs. For example, at Genoa we use a lot of Perl and this Perl we don't use AutoMalloc. Perl provides its own implementation of a brick-based malloc. It's not that secure. But otherwise our Perl gets very slow because it makes a lot of small allocations for every variable in Perl. It makes an alloc and free. And we thought, okay, it's Perl. It's the Perl interpreter itself. We take the risk but we need the performance. So everything you can evaluate, does it work for me or what does the network work for me? But you get a security fault. You can also say, okay, I want more security and change your malloc options to be something more paranoid. And the real hard things you cannot turn off, it's always on. And we have the port system as our baseline. So if we can manage to get our ports running, we know that we have found the compromise we want between usability and security. And now we come to the question section if you have some time. Ah, okay, Mark. Pletch has been designed very well because Theo has a very strong opinion of it. So it follows design principle or his design principle very strictly. And if you want to change something in Pletch, there's a lot of arguing. Yeah, the secure thing is to do privilege separation like we have in TCP DOM. But having it for TARS is of course a performance hustle. Okay, I think we are over. Thank you.