The C language is very powerful and where it is used a lot - especially in the Linux kernel - but it is very dangerous. One of the developers of the Linux kernel told how to deal with security vulnerabilities of S.You can do almost any thing on C, but this does not mean that it needs to be done. Code C is very fast, but is carried without seat belts. Even if you are an expert, like
most of the Linux kernel developers , deadly errors are still possible.
')
In addition to the pitfalls such as
pseudonyms of pointers , the C language has fundamental uncorrected errors that are waiting for their victims. It was these vulnerabilities that
Case Cook , Google Linux kernel security engineer, discussed at
the Linux security conference in Vancouver.
“C is a kind of assembler. This is almost a machine code, ”Cook said, referring to an audience of several hundred colleagues who understand and appreciate the speed of C applications. But the bad news is that“ C comes with some dangerous baggage, undefined behavior and other weaknesses that lead to
security holes and vulnerable infrastructure. "
If you use C in your projects, you should pay attention to security issues.
Linux kernel security
Over time, Cook and his colleagues discovered numerous problems of the native C. To eliminate them, the
Kernel Self Protection Project, the Kernel Self -Defense Project, was launched. He is slowly and steadily working to protect the Linux kernel from attacks, removing the problematic code from there.
This is difficult, says Cook, because "the kernel needs to do very specific architecture-specific things for memory management, interrupt handling, scheduling, and so on." A large amount of code refers to specific tasks that need to be carefully checked. For example, “C has no API for setting page tables or switching to 64-bit mode,” he said.
With such a load, and with weak standard libraries in C, there are too many undefined behaviors. Cook quoted - and agreed - with Raf Levien
’s blog post
“Everything is possible with undefined behavior” .
Cook gave specific examples: “What is the content of“ uninitialized ”variables? This is all that was in memory before! In void pointers, there is no type, but can we call typed functions through them? Of course! Assembly anyway: you can contact any address! Why does
memcpy()
have no 'max destination length' argument? It doesn't matter, just do as said; all memory areas are the same! ”
Ignoring warnings ... but not always
Some of these features are relatively easy to handle. Cook commented: “Linus [Torvalds] likes the idea of ​​always initializing local variables. So just do it. ”
But with a reservation. If you initialize a local variable in switch, you will get a warning: “The operator will never execute
[-Wswitch-unreachable]
” because of how the compiler handles the code. This warning can be ignored.
But not all warnings can be ignored. “Variable length arrays are always bad,” said Cook. Other problems include stack exhaustion, linear overflow, and paging violation. In addition, Cook drew attention to the
slowness of the VLA . Removing all VLAs from the core improved performance by 13%. Improving both speed and security is a double benefit.
Although the VLAs were almost removed from the kernel, they still remained in some code. Fortunately, the VLA is easy to find using the
-Wvla
compiler
-Wvla
.
Another problem is hidden in the semantics of C. If break is skipped in a switch, then what did the programmer mean? Skipping a break may lead to the execution of a code of several conditions; This is a well-known problem.
If you are looking for break / switch statements in existing code, you can use
-Wimplicit-fallthrough
to add a new switch statement. In fact, this is a comment, but modern compilers disassemble it. You can also
explicitly mark the absence of a break with the “fallthrough” comment .
Cook also found a decrease in performance when checking boundaries for
allocating slab memory . For example, checking
strcpy()-family
reduces performance by 2%. Alternatives like
strncpy()
their own problems. It turns out that Strncpy does not always end with a null character. Cook sadly addressed the audience: “Where can I get the best API?”
During a question and answer session, one Linux developer asked, “Can I get rid of old, bad APIs?” Cook replied that for some time Linux had supported the concept of outdated APIs. However, Torvalds abandoned this idea, arguing that if an API is outdated, it should be completely discarded. However, throwing the API “politically dangerous” forever, Cook added. So while we are stuck with them.
Long-term solution to the problem? More developers who understand security issues
Cook foresees a long and difficult journey. Once upon a time, the idea of ​​creating a Linux C dialect seemed attractive, but this will not happen. The real problem with dangerous code is that “people do not want to do the work of clearing the code — not only bad code, but C itself,” he said. As with all open source projects, “we need more dedicated developers, reviewers, testers and backport specialists.”
Dangerous C: lessons
- C is a mature and powerful language, but it creates technical difficulties and security problems.
- Linux developers pay special attention to securing C (without losing its power), because most of the operating system is written on it.
- Google Linux kernel security engineer identified specific language vulnerabilities and explained how to avoid them.