After an initial report from @Pushkar_N_Kulkarni (thank you!) we recently identified a severe security vulnerability in SwiftNIO's ByteBuffer code which was fixed in the following releases: 1.0.1, 1.1.1, 1.2.2, 1.3.2, 1.4.3, 1.5.2, 1.6.2, 1.7.3, 1.8.0, all other SwiftNIO versions are affected.
What should I do?
please run swift package update in any project that uses SwiftNIO
make sure that after running this command, you're using one of the unaffected SwiftNIO versions (to see what version you're currently using, run cat Package.resolved | grep -A7 '"swift-nio"' | grep version)
Optional further steps:
to make sure your application can not ever be run with an affected SwiftNIO version, change the SwiftNIO dependency to .package(url: "https://github.com/apple/swift-nio.git", from: "1.8.0")
Details
In all prior NIO releases (that means all except for 1.0.1, 1.1.1, 1.2.2, 1.3.2, 1.4.3, 1.5.2, 1.6.2, 1.7.3, 1.8.0) ByteBuffer had a very bad (exploitable!) security vulnerability if the following conditions are all true:
user writes to a ByteBuffer which is a slice (slice.lowerBound != 0)
the slice is uniquely referenced (ie. the buffer that it was sliced
from is gone)
the write triggers a re-allocation
Then the slice is actually larger than the overall available capacity so another write to said ByteBuffer could end up out of bounds.
Would somebody mind elaborating on how exactly is this exploitable? I don't know a lot about security but I am very interested. To my untrained and naive mind, this looks like it would crash at worst case.
Writing outside the bounds of an array will overwrite whatever content was in that memory. If you can guess what variables are stored in that memory, then you can carefully craft a payload to write which sets those variables values to anything you like.
Most critically, if one of these variables is a function pointer that's jumped to, you could overwrite it with the address of some payload, which contains executable code that the process will jump to.
I see.. I thought kinds of out-of-bounds writes are guarded against in swift. Are those striped away in release builds or are they somehow bypassed by slices?
I agree with everything said above. It's probably not super easy to exploit but it's for sure possible as there might be something interesting (could be anything, data, function pointers, etc) next to the ByteBuffer's storage that we allocated. Especially because NIO is a framework and not an application by itself we can't really reason about what an application stores in memory so we need to assume the worst.
Moreover, crashing the software is a DOS and is also a severe attack. Especially if it is easy to craft a package that crash the app. You can send it repeatedly and prevent the service to be restarted.