
my name is anna as ellen already mentioned so today my talk is about the small possibilities that go isn't memory safe anymore so it's mostly theoretical but nonetheless it's important i think to be aware that you can get also go to be memory unsafe if you want to take something out of the talk i think it's just this awareness that just because the language is memory safe there are possibilities to break it and the talk i will shortly introduce it and everything i will tell you here is not confidential so most of the resources are either published or also written down in blockers from the ghost beginning area which is nearly 10 years ago but it's still valid so
let's dig into it to start with memory safety to get all on the same stage in general um it basically means that your programming language can help um to protect from software backs and also security vulnerabilities like buffer overflows which happens due to memory access why do we have these kind of bugs this these are mostly due to memory unsafe languages like c c plus plus which allow arbitrary point arithmetic that is compute to create the computations with pointers and also allow to exit directly access pointers um and therefore memory access and also for arrays you have no bond checks in contrast we have momoda languages which are usually called memory safe like rust go
c-sharp swift python and java which implements protection missionism against these vulnerabilities for example by with out of point reads and rights and avoiding dangling pointers why do we need out of boundaries and protection against dangling punchers on the left i didn't introduce you to go and one of the mascots of go with the gopher which you see on the left and basically your memory is like a long list and if you have an array which is on this call in this case simply the list of talks of this year's b sites you actually want to access only the wallet elements of your list so if your governor asked for the 13th talk spoiler we only have 12 talks
and actually this is in theory off by one area because talk 12 on your or in the corresponding program will already be an out of bound um should give your message or something like you're doing something but you're not supposed to do that's what a memory safe language would do a memory unsafe well simply ignore this information and go to the next or to the correspond element in this case it would be the next confidential information that sir maybe i don't know is speaker dinner afterwards for all speakers and of course that's confidential information and if you imagine your real program that's an issue
yes you could also argue that if you use a language which doesn't have these checks that it's the developer's responsibility but actually that's bugs so oh i mean it could happen that you implemented back and we all know we are human bugs happen so having memory safety is a nice thing to have um now covering shortly pointers um if you're delayed or tomorrow the besides organization team is very enthusiastic and i already deleted all talks of these years and updated the welcome words and closing remarks to next year and if now our curious governors want to get the first second or whatever talk for next year he should get the information that there are the talks because
the turks of this year were deleted but if you have no protection against it you will get complete the first word because you can fetch memory where the program actually said it's done and may be used for something else but maybe not be used for something else yet these kind of vulnerabilities are also called for example use after free vulnerability and i marked the point of dash because it's a dangling pointer of course these examples are simplified but should give you an impression why it's or it's important to have memory safety shortly for those of you who are not familiar with go go is aesthetically typed and compiled programming language with memory safety and for example garbage collection
collection and csp style concurrency and many more features but i think that's enough to get an impression of go and for example the memory safety for this girl also checks for bounds for slices and arrays clay slices are basically areas and go if you don't know them that's enough to know and they also have restrictions to this type system and you can't have that or you don't have dangling pointers of course so what does that mean in practice that go has spawn checks that basically mean that if you want to access an element which is out of bound because it's for example the element is too high you get a runtime error how does that look like if you run your go
program you can get a panic with some runtime error and a message like index out of range now i hope that you have an understanding why memory safety is great and that girl is actually doing pretty good in it but what can we do or not what can we do but what is possible to break the memory safety or to play against the rules so basically we have three ways to circumvent the memory safety measurements implemented and go are at least three ways i am aware of um the first is the unsafe api that's basically an api which allows you to avoid these type safety measurements implemented and go and also directly access the memory
address wallet cases for this are like optimization hardware access and also access to external libraries for example sea levels then there's concurrency due to data races and that's actually a more subtle and indirect way to break it and of course if you link c or c plus programs those programs are not have the memory safety measures and i think there are have to be that separated because c or c plus plus yeah
but now let's look shortly into the problem of a concurrency problem why we can get memory unfair there i tried to simplify it because i think in this talk you should only get the idea with you that it can be a problem if you are interested in the concrete go code you could get laid down links where you you can really dig deep into this and i wanted to give you the idea of it the problem is that slices interface values and strings are multi-word values meaning that in the case for example for the interface two instructions are required to update the values because an interfacing go is basically inter represented as once the type which points to the type
and the data which also may be a point so um and go we have kind of two and a half ways to circumvent the memory safety and go the first is the unsafe api and this api basically allows you to avoid type 70 measures implemented in go and also to directly access memory addresses and there are also a lot of valid cases to use as api like optimization or hardware access [Music] and the other way is concurrency are data races which can also cause memory and safety issues and the half array which is obvious is linked t and c plus plus programs because if you link crc plus plus programs which are not memory safe they
of course don't have the measures now shortly look into why concurrency is a problem so go has multi-word values which are namely slices which are basically erasing go interface values and strings while the later strings are immutable and thus it's only possible to read memory and not write to it for slices and interfaces we can also manage to write into the memory why this happens basically because looking at the interface example to update an interface value we require two instructions instead of one so if we don't synchronize our access to the interface value and get a data race it may happen that one routine updates one part of the interface valley and the other update the other part
having kind of something else and something new and this we can use to get memory and safety behavior now to get you an idea how this exploit works without digging too deep under the code i have created these images um let's start um because we want to exploit that an interface value of creates two instructions we build up an interface our interface and this example is xer which simply has a method x we define two structs the first is called safe and f isn't pointy to int which implements the method x and thus implicitly implement the x interface in go you don't have to explicitly define that you implement an interface as soon as your struct has the methods
of the implements it implements this interface and the struct unsafe which have a funk or expect a funk for f instead of a pointer to end then for unsafe or method x dose a bit more and checks if f is not nil which is the null in gear and if that's the case it calls this function now if we mix that up together we want to have one variable confused with this interface and of course the good and bad variables the git first we assign or create a struct value where we pass for f the address of a function win i omitted the function for simplicity and for bad we simply create an empty struct
of unsafe so we don't pass a value for f though it's nil and then we assign to confused good until now everything is looking good but you can imagine every start to put concurrency on it and come to data race we can come into a situation where confused is part good and part bad and that's the exploit basically or how it could like we have restart for example to go routines which put con er which said confused too bad and afterwards too good and then we have one for loop which runs forever like the other two in the gear routines which calls called the function x unconfused if you remember for git nothing happens it's simply
and for bad it checks if f is set but for bad we didn't set any to f so it's null so it wouldn't excuse execute unless f points already to the address of the win function which is passed as the f in good if that happened the program stops because we simply put on when the function an os exit so summarize that's how you can get from the earth that's the basic idea how you can exploit data races to screw up your memory safety um of course going or have flex such that you can detect the data races you simply put the flag minus raised to it um that curses that you get a information that a
data race was detected and it still executes so your exploit will still be applicable if you want to avoid that and first the stop of the program you have to pass arrays equal hold on arrow equal one now after this shirt claims dig deeper into it or see circles on this actually um there are two introduction level blog posts about this issue the first is from russ cox of the races they describe how slices slices and interfaces can screw up your memory safety and he also argues that it's not a security issue because normally you don't execute code you don't trust on your environment hence docker and then there's the other blog post by stocker
which is called go long data races to break memory safety which is also i think nice to read and my examples are the examples i tried to break you down in these slides before are also orientated on his blog post in case you still think more that's boring i really really want to dig deeper into it there's a nice write-up of a capture the flag challenge of the gilmore brother where they also make actual use for vulnerability or to break into the system with this memory safety issues now having said that i surely want to cover the unsafe api um the unsafe api is an escape patch if you really need to go down to your memory
and play around with the addresses as mentioned before there are legitimate use cases and basically the api allows you arbitrary typecast and pointer arithmetic and as you can think that also circumvent the memory safety measures um if you ask can we make exploit versus of course you can or we can um there is wise plug series from actually from the student of may um who tried to make some exploit exploits with unsafe pointers i think it's in total for parts and if you want to see more on this ultimate examples you're good to go there and in case if you wonder if that's a problem in the world or in the wild we also have published a paper recently
about this so if you want to dig more into this area there are probably good pointers now um to score the points and go geiger at the answer um but actually what does girl get do so what i mentioned the study i mentioned before is kind of theoretically and it doesn't apply to your code base and probably you're interested or perhaps you are now interested how much unsafe is used within your code and that case you simply can go around you can run go geiger which is similar to the rascage go er the rust geiger tool which simply lists you all unsafe usages within your code but also in your dependencies now to sum up the talk which was kind of
interrupted and now a bit faster um go has is memory save and the runtime really checks for you and do does a great job in this respect you can break it a bit if you play around with the unsafe api or if you get data races with concurrency and get the program into different states as i show you with the interface example and that really would work in practice and if you're interested in [Music] whether your projects actually use unsafe or the unsafe api you can audit your code base with go geiger and that's it thank you and also sorry for the interruptions