|
|
Log in / Subscribe / Register

One year of Coverity work

By Jonathan Corbet
August 20, 2014

Kernel Summit 2014
For the last year, Dave Jones has been working with the Coverity scanner to identify and fix possible bugs in the kernel. Like many developers, he worried that things could get worse over time; with all the code that is going into the kernel, there must be a lot of defects coming in as well. But the actual news turns out to be a bit better than that.

What Dave feeds to Coverity is a "kitchen-sink build" with almost everything enabled. Where there is a configuration choice to be made, he tries to choose like a distributor would. The end result is that the kernel he builds has some 6,955 options selected. Running the scanner on this kernel takes several hours. Indeed, Dave has been keeping Coverity busy enough that the company eventually set up a dedicated server for kernel runs, enabling him to do two or three runs each day.

When Dave ran a scan of the 3.11 kernel, he ended up with a "defect density" of 0.68 per thousand lines of code — somewhat above the company's "open-source average" of 0.59. The results since then look like this:

KernelDefect
density
3.110.68
3.120.62
3.130.59
3.140.55
3.150.55
3.160.53

The current defect density, after the closing of the 3.17 merge window, is 0.52. So things have consistently gotten better over time.

He has put together a ranking of the areas in the kernel with the most defects. At the top of the list is the staging tree. That, he said, is good; if any other subsystem were worse than staging, that would indicate a real problem. Most of the other entries in the list were in the driver tree, which is not surprising; that is where most of the code is.

The biggest single issue raised by Coverity, he said, was dead code. Sometimes the warning makes sense, but it is not always correct. Some code will be unreachable due to configuration choices, for example. Second on the list was a failure to check return values; that, too, may or may not be a real bug, depending on the situation. The third item on the list — checking for a null pointer after the pointer has already been dereferenced — is clearly bad news and needs to be fixed.

Also scary are the static buffer overrun errors. These can be "nasty," and there are too many of them, though the situation is getting better. These, too, are not always bugs; the networking layer, for example, performs [Dave Jones] tricks with its skb data structures that look like buffer overruns but in reality are not. Coverity also flags a large number of resource leaks; unsurprisingly, these are usually found in error paths.

There are numerous other classes of potential errors. Some of them, such as "statement with no effect," tend to be harmless and may well be intentional. For example, assigning a variable to itself has no effect, but it was evidently an effective way of shutting down "possibly uninitialized" warnings from the compiler in the past. Others, like unchecked use of data from user space, can be more serious; in this case, most of the offending uses are behind capability checks and are thus not immediately exploitable.

The good news, Dave said, is that there are now less than 50 use-after-free errors flagged in the kernel. Various other classes of "dumb" errors have been nearly eliminated from the kernel as well. Dave said he keeps a close eye on those; when one pops up in a new kernel, he tries to get it fixed quickly.

Ted Ts'o asked how many of the issues flagged by Coverity are real bugs. Dave's feeling is that only a small minority of the reports indicate serious bugs. If one is interested in security issues, he said, the Trinity fuzz tester has found more of them than Coverity has.

What about ARM coverage? The commercial Coverity product has it, but the free version for the open source community does not. In truth, Dave said, if the code can be made to compile on an x86 compiler, Coverity will scan it. So he has pondered approaches like commenting out all of the inline assembly in the ARM tree and scanning the result. That is a project for the future, though.

Other developers can have a look at the Coverity results if they want to help to fix the reported problems. It's a matter of going to scan.coverity.com and signing up for the "Linux" project. Then drop a note to Dave, and he will approve access to the results. As is usually the case, more eyes on these results should lead to a better kernel in the long run.

Index entries for this article
KernelDevelopment tools/Static analysis
ConferenceKernel Summit/2014


to post comments

One year of Coverity work

Posted Aug 21, 2014 2:34 UTC (Thu) by agelastic (guest, #96282) [Link] (2 responses)

> It's a matter of going to scan.coverity.com and signing up for the "Linux" project. Then drop a note to Dave, and he will approve access to the results

I admit I'm far from being a core kernel developer but I do work in security. I've sent a request to get access to Coverity scan results and was sent away "because the results are sensitive."

One year of Coverity work

Posted Aug 22, 2014 6:37 UTC (Fri) by lkundrak (subscriber, #43452) [Link] (1 responses)

I'm not sure why would this happen. Coverity is free for free software projects; you could easily build and upload Linux kernel tree there for analysis yourself.

One year of Coverity work

Posted Aug 22, 2014 6:43 UTC (Fri) by agelastic (guest, #96282) [Link]

> you could easily build and upload Linux kernel tree there for analysis yourself.

False.

One year of Coverity work

Posted Aug 22, 2014 14:28 UTC (Fri) by etienne (guest, #25256) [Link] (5 responses)

> For example, assigning a variable to itself has no effect

I know some developers see that has bad practice, but I use it to attract attention about a variable - when that variable is initialized and used in only some code-path.

The "design pattern" is basically:
void fct(...) {
int var = var;
if (test1) var = 42;
some_common_function();
if (test2) anotherfct (var);
}

The point is that you shall never use the variable "var" without initializing it, but in this case the compiler will not check for you - "var = var;" is just a "take care" indication to the reader and not a real initialisation.
The other point is that it is not logical to always initialize "var" to a dummy value - there may not be any dummy value available, and usually it would be an error to use that dummy value considering the algorithm.
So when a maintainer see "int var = var;", he will know that "test2" has to be either identical to "test1", or more restrictive than "test1".
I have see too many bug created by bug-fixes applied to just "test1"...

One year of Coverity work

Posted Aug 22, 2014 17:18 UTC (Fri) by giraffedata (guest, #1954) [Link] (4 responses)

it is not logical to always initialize "var" to a dummy value - there may not be any dummy value available, and usually it would be an error to use that dummy value considering the algorithm.

A more fundamental reason not to initialize "var" to a dummy value is that it makes the code harder to read. It makes it look like that dummy value is a legitimate value for "var" (after all, it is common for people to cram multiple pieces of information into a variable, so "-1" isn't necessarily a dummy value for a variable named "length"). And it makes it look like "var" is meaningful in the code before it is really set. And that makes it much harder for a reader of the code to detect true used-before-set bugs.

One year of Coverity work

Posted Aug 22, 2014 20:46 UTC (Fri) by etienne (guest, #25256) [Link] (3 responses)

Self initialized variables are surely harder to read - but that is the point: for someone trying to understand (and maybe modify) the source code, that trick tell them to double check everything about its use.
It is obviouly a error to use the value of a self-initialized variable, maybe one day the compiler will flag an error in such case, either at compile time or at run time.
What I need in the algorithm is a "poisonous" value (doesn't exists in C) or a memory area reservation but no visibility at that level (and in the stack, doesn't exists in C).
Myself, if I have a quick bug to correct and I see the obvious test to modify, I will do the change quite quickly; if I see a self initialised variable I will look for the design pattern I was talking of.

One year of Coverity work

Posted Aug 22, 2014 20:50 UTC (Fri) by mathstuf (subscriber, #69389) [Link] (2 responses)

When I see a self-initialized variable, I think "bug", not "here there be dragons". Make your assumptions explicit with a comment please.

One year of Coverity work

Posted Aug 24, 2014 7:24 UTC (Sun) by johill (subscriber, #25196) [Link] (1 responses)

Additionally, if you *don't* initialize the variable then the compiler will be able to warn you if you later create a code path where you forgot...

One year of Coverity work

Posted Aug 31, 2014 12:11 UTC (Sun) by Wol (subscriber, #4433) [Link]

Okay, user-space code, but when I set coding standards at a company, the rule was "all warnings must be explained away".

The reason was precisely that - we had certain code (where we called a commercial library that then called-back our code) that we just couldn't suppress all warnings.

Sometimes you end up between a rock and a hard place, and things like "var = var" are an easy escape route...

Cheers,
Wol


Copyright © 2014, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds