Researchers at the cybersecurity company GRIMM recently published an interesting trio of bugs they found in the Linux kernel ...
… In a code that had been there unnoticed for about 15 years.
Fortunately, it seemed like no one else had looked at the code for that long, at least not diligently enough to catch the bugs, so they are now patched and the three CVEs they found are now fixed:
- CVE-2021-27365. Exploitable stack buffer overflow due to use of sprintf ().
- CVE-2021-27363. Loss of kernel address due to pointer used as unique ID.
- CVE-2021-27364. Buffer overread leading to data leakage or denial of service (kernel panic).
The bugs were found in the kernel code that implements iSCSI, a component that implements the venerable SCSI data interface over the network, so you can talk to SCSI devices like tape and disk drives that are not directly connected to your own computer.
Of course, if you no longer use SCSI or iSCSI anywhere on your network, you're probably shrugging right now and thinking, 'Don't worry about me, I don't have any of the iSCSI kernel drivers loaded because' I just don't I am using them. "
After all, buggy kernel code can't be exploited if it's only on disk; it has to be loaded into memory and actively used before it can cause any problems.
Except, of course, that most (or at least many) Linux systems don't just come with hundreds or even thousands of kernel modules in the / lib / modules directory tree, ready to go in case they are ever needed. They are also configured to allow duly authorized applications. to activate automatic loading of modules on demand.
Note. As far as we know, these bugs were fixed in the following officially maintained Linux kernels, all dated 2021-03-07: 5.11.4, 5.10.21, 5.4.103, 4.19.179, 18.104.22.168, 4.9 .260 , 4.4.260. If you have a vendor-modified kernel or an unofficial serial kernel that is not on this list, check with your distribution manufacturer. To check your kernel version, run uname -at a command prompt.
For example, my own Linux system comes with almost 4500 kernel modules just in case you need them:
root @ slack: /lib/modules/5.10.23# search. -name '* .ko'
[… 4472 lines deleted…]
I suppose one day I might need the Blowfish encryption module, but since I don't have any software that I hope to use, I could probably do without the blowfish-x86_64.ko driver.
And while I really wouldn't mind having one of Tascam's great Ux2y sound cards (eg US122, US224, US428), I don't really need room for one, so I doubt I'll ever need the snd-usb-usx2y. kocontroller. either.
However, there they are, and by accident or by design, any of those drivers could end up loading automatically, depending on what software you're using, even if I'm not running as root at the time.
Worth a second look
The potential risk posed by unloved, unused, and mostly overlooked drivers is what caused GRIMM to look twice for the errors mentioned above.
The researchers were able to find software that an unprivileged attacker could run to activate the faulty driver code they had found, and they were able to produce functional exploits that could in various ways:
- Perform privilege escalation to promote a regular user to have kernel-level superpowers.
- Extract kernel memory addresses to facilitate other attacks that need to know where kernel code is loaded in memory.
- It blocks the kernel and therefore the whole system.
- Read chunks of data from kernel memory that were supposed to be out of bounds.
As uncertain and as limited in scope as the latest exploit sounds, it appears that the data an unprivileged user might see could include chunks of data that are transferred during accesses to genuine iSCSI devices.
If so, this theoretically means that a criminal with an unprivileged account on a server where iSCSI was used could run an innocent-looking program to sit in the background, sniffing out a random selection of privileged data from memory. .
Even a fragmented and unstructured stream of confidential data intermittently pulled from a privileged process (remember the infamous Heartbleed bug?) Could allow dangerous secrets to escape.
Don't forget how easy it is for computer software to recognize and "scrape" patterns of data as it flies through RAM, such as credit card numbers and email addresses.
Above, we mentioned that the first error in this set was due to "using sprintf ()".
That's a C function that's short for print formatted in a string, and it's a way to print a text message to a block of memory so you can use it later.
For example, this code ...
char buf ; / * Reserve a 64-byte block of bytes * /
char * str = "42"; / * It is actually 3 bytes, therefore: '4' '2' NUL * /
/ * Trailing zero added automatically: 0x34 0x32 0x00 * /
sprintf (buf, "The answer is% s", str)
... It would leave the memory block that buf contains the 12 characters "Answer is 42", followed by a zero-byte terminator (ASCII NUL), followed by 51 bytes untouched at the end of the 64-byte buffer.
However, sprintf () is always dangerous and should never be used, because it doesn't check if there is enough space in the final memory block to fit the printed data.
Above, if the string stored in the variable strt is more than 54 bytes, including the zero byte at the end, then buf will not match along with the extra text "Answer is".
Worse still, if the strno text data has a zero byte at the end, which is how C indicates when to stop copying a string, you could accidentally copy thousands or even millions of bytes that keep running through memory until you just hit a zero byte, at which point the kernel is almost certain to have crashed.
Modern code shouldn't use C functions that can make memory copies of unlimited length - I use snprintf (), which means to format and print at most N bytes in a string, and your friends instead.
Don't give your address
The second error above arose from the use of memory addresses as unique identifiers.
That sounds like a good idea: if you need to indicate a data object in your kernel code with an identification number that will not collide with any other object in your code, you can use the numbers 1, 2, 3 and so on. , adding one at a time and solve the problem.
But if you want a unique identifier that does not conflict with any other numbered objects in the kernel, you might think, “Why not use the memory address where my object is stored, because obviously it is unique, since two objects cannot be in the same place in kernel RAM at the same time? ”(No, unless there is already a crisis with memory use).
The problem is that if your object ID is ever visible outside of the kernel, for example so that untrusted programs in the user area can refer to it, you just gave information about the internal memory layout of the kernel, and that's not supposed to happen.
Modern kernels use what is called KASLR, short for kernel address space layout randomization, specifically to prevent unprivileged users from discovering the exact internal layout of the kernel.
If you've ever opened locks (it's a popular and surprisingly relaxing hobby among hackers and cybersecurity researchers - you can even buy clear locks for educational fun), you'll know it's a lot easier if you already know how the lock works. The mechanism is presented internally.
Similarly, knowing exactly what has been loaded inside the kernel almost always makes other errors, such as buffer overflows, much easier to exploit.
What to do?
- Update your kernel. If you trust the creator of your distribution for the new kernels, make sure you get the latest update. See above for the version numbers where these bugs were fixed.
- Do not use C programming functions that are known to be problematic. Avoid any memory access feature that does not keep track of the maximum amount of data to use. Keep track of the officially documented "safe C string functions" for your chosen operating system or programming environment and use them whenever you can. This gives you a better chance of preventing memory overload.
- Do not use memory addresses as "unique" identifiers or identifiers. If you can't use a counter that only increases by 1 at a time, use a random number of at least 128 bits instead. These are sometimes known as UUIDs, for universal unique identifiers. Use a high-quality random font, such as / dev / urandomen on Linux and macOS, or BCryptGenRandom () on Windows.
- Consider blocking kernel module loading to avoid surprises. If you set the Linux system variable a kernel.modules_disable = 1 once your server has started and is working properly, no more modules can be loaded, either by accident or by design, and this setting can only be disabled by rebooting. Use sysctl -w kernel.modules_disable = 1st echo 1> / proc / sys / kernel / modules_disable.
- Consider identifying and keeping only the kernel modules you need. You can build a static kernel with only the required modules compiled, or create a kernel package for your servers with all unnecessary modules removed. With a static kernel, you can disable module loading entirely if you want.