CERT C Programming Language Secure Coding Standard

R

Robert Seacord

We have made significant progress on the CERT C Programming Language
Secure Coding Standard since I first posted about this effort around a
year ago. In particular, the document was reviewed and endorsed by the
WG14 C language standards committee at the London meeting in April of
this year.

We would again like to invite the community to review and comment on the
current version of the standard available at www.securecoding.cert.org
before we publish the final version. To do this, you can create an
account on the secure coding wiki and post your comments there.

There is some possibility that ISO/IEC WG14 may eventually publish this
document as a type III (informational) technical report and this
document may also be mined for ideas for the next major revision of the
C language standard. As a result, we would greatly appreciate your time
and expertise in reviewing the standard, and we will acknowledge your
contributions.

Thanks,
rCs
 
C

christian.bau

We have made significant progress on the CERT C Programming Language
Secure Coding Standard since I first posted about this effort around a
year ago. In particular, the document was reviewed and endorsed by the
WG14 C language standards committee at the London meeting in April of
this year.

We would again like to invite the community to review and comment on the
current version of the standard available atwww.securecoding.cert.org
before we publish the final version. To do this, you can create an
account on the secure coding wiki and post your comments there.

There is some possibility that ISO/IEC WG14 may eventually publish this
document as a type III (informational) technical report and this
document may also be mined for ideas for the next major revision of the
C language standard. As a result, we would greatly appreciate your time
and expertise in reviewing the standard, and we will acknowledge your
contributions.

I'd say you could do with a bit of proof reading.

First, there is an example showing a macro modifying a global
variable, which supposedly leads to incorrect results when the macro
is used within a function having a local variable of the same name.
The example doesn't show this, and it doesn't produce the output that
you claim it does.

Second, you show an example that supposedly replaces the "puts"
function with a macro. That example doesn't compile. Apart from that,
the whole example doesn't make sense. There is a slight problem when
library functions can be implemented through macros, and there are
rare times when one has to make sure the real function is called, but
your explanation of the danger is way off the mark.

In general, it seems your webpage contains lots of comments that refer
to earlier versions of the document. This is really confusing. If a
comment says that the document should be changed, and you changed the
document, then leaving that comment there is just confusing.
 
R

Robert Gamble

We have made significant progress on the CERT C Programming Language
Secure Coding Standard since I first posted about this effort around a
year ago. In particular, the document was reviewed and endorsed by the
WG14 C language standards committee at the London meeting in April of
this year.

We would again like to invite the community to review and comment on the
current version of the standard available atwww.securecoding.cert.org
before we publish the final version. To do this, you can create an
account on the secure coding wiki and post your comments there.

There is some possibility that ISO/IEC WG14 may eventually publish this
document as a type III (informational) technical report and this
document may also be mined for ideas for the next major revision of the
C language standard. As a result, we would greatly appreciate your time
and expertise in reviewing the standard, and we will acknowledge your
contributions.

Thanks,
rCs

It looks much better than the previous versions I have seen. I would
have to agree with Christian's sentiments and add that I personally
have a difficult time taking seriously anything that contains the
suggestion "Use TR 24731" which I think is a laughing stock at best
and honestly find it surprising that such a recommendation would find
its way into a serious security document. Aside from that, from what
I saw, it is looking pretty good.

Robert Gamble
 
J

jacob navia

Robert said:
It looks much better than the previous versions I have seen. I would
have to agree with Christian's sentiments and add that I personally
have a difficult time taking seriously anything that contains the
suggestion "Use TR 24731" which I think is a laughing stock at best
and honestly find it surprising that such a recommendation would find
its way into a serious security document. Aside from that, from what
I saw, it is looking pretty good.

Robert Gamble

You can consider TR 24731 laughing stock, a product of the evil empire,
but it is the only implementation of a schema
for error processing in C that has been considered by the committee
other than errno...

The refusal of the committee to establish a catch/throw mechanism
leads to TR 24731 as the ONLY alternative.

WHAT ELSE YOU PROPOSE?

Regarding the CERT document I am still reading this, so I will comment
later

jacob
 
R

Robert Gamble

You can consider TR 24731 laughing stock, a product of the evil empire,

Let me just make it clear that the source of the proposal isn't a
factor in my disdain of it. Microsoft's influence may well be the
major/only reason this proposal has received the level of attention it
has so far in committee but my objections lie purely with the details
of the proposal itself.
but it is the only implementation of a schema
for error processing in C that has been considered by the committee
other than errno...

The refusal of the committee to establish a catch/throw mechanism
leads to TR 24731 as the ONLY alternative.

This makes no sense to me.
WHAT ELSE YOU PROPOSE?

Standardize strlcat and strlcpy. Deprecate gets(). If you care about
security don't pass an unchecked user-provided string as the format
string to printf(), use snprintf() instead of sprintf(), don't use the
%s/%[ scanf() conversion specifiers without a precision, etc. If you
care about reentrancy don't use functions like strtok/strerror/asctime/
gmtime/etc but instead use the POSIX *_r equivalents like everyone
else, if you insist on having these functions in Standard C go ahead
and lobby for them to be included in the next version, just don't
reinvent the wheel. Finally, don't hire programmers that can't keep
track of the size of a char array or who don't know how to count.

That should just about cover what is addressed in the TR I think.

Robert Gamble
 
C

CBFalconer

Robert said:
.... snip ...


This makes no sense to me.


Standardize strlcat and strlcpy. Deprecate gets(). If you care

So far you are doing fine, (and should include ggets()) but ...
about security don't pass an unchecked user-provided string as the
format string to printf(), use snprintf() instead of sprintf(),
don't use the %s/%[ scanf() conversion specifiers without a
precision, etc. If you care about reentrancy don't use functions
like strtok/strerror/asctime/ gmtime/etc but instead use the POSIX
*_r equivalents like everyone else, if you insist on having these
functions in Standard C go ahead and lobby for them to be included
in the next version, just don't reinvent the wheel. Finally, don't
hire programmers that can't keep track of the size of a char array
or who don't know how to count.

But now you are getting outside the realm of standard C, IMO.
However we can always accept the last sentence :).
 
E

Eric Sosman

Robert Seacord wrote On 07/31/07 10:28,:
[...] As a result, we would greatly appreciate your time
and expertise in reviewing the standard, and we will acknowledge your
contributions.

General observation: The standard intends to promote
"security," but a good deal of it seems to have the effect
of avoiding "bugs." That's a worthy aim, but the two goals
don't seem to me to be precisely equivalent.

General observation: The navigation on this site makes
sequential reading cumbersome: The only (apparent) way to
navigate from a leaf to the next leaf is to crawl back up
the tree to the parent first. Cannot we have Next (and maybe
Previous) links like everybody else?

General observation: Many of the "non-compliant" examples
contain code for which the compiler is obliged to issue a
diagnostic. It seems to me that this makes them less likely
to cause trouble than other, not-necessarily-diagnosed errors.

Introduction/Rules Versus Recommendations, second point
in the definition of a rule:

There is an enumerable set of exceptional conditions
(or no such conditions) in which violating the coding
practice is necessary to ensure the correct behavior
for the program.

Perhaps my reading comprehension has deteriorated, but I can
make no sense of this sentence. The first part describes a
situation in which there is a set of conditions or there are
no conditions; isn't this vacuously true? It sure looks an
awful lot like `true OR false' to me. Then the second part
speaks of a program that only works correctly when the rule
is violated; hence if the program is compliant it does not
work, and if it works it cannot be compliant. Is that what
is really intended?

PRE02-A makes `#define COUNT 42' non-compliant, which
seems extreme. It also makes

#ifdef FROBOZZ_MAGIC_C
#define FAR far
#else
#define FAR /* nil */
#endif

non-compliant. Isn't this rather draconian?

PRE03-A just seems confused: Anybody who defines his own
overriding macro for a Standard library function deserves a
good scolding, but for treading on the library's name space
rather than for defining a macro. And why is it a generally
good idea to avoid the macros that the library has lovingly
provided for you? Do you *like* making an actual function
call for every memcpy() or isdigit() or getc() or sqrt()?
And why is avoiding such a macro "likely to increase system
security" (one of the requirements for a recommendation)?

DCL00-A seems highly debatable. Also, the second point
in the list of contexts where const objects cannot be used
is not quite right as of C99. (Maybe there'll be a rule later
on to avoid using this particular C99 feature; it strikes me
as something that makes an existing risk much worse.)

DCL01-A, first bullet: Not even in a scope where the
global variable is unknown? Why not?

DCL02-A seems to render PRE30-C moot.

DCL03-A seems misguided. In the example, the root of
the problem isn't the placement of the qualifier, but the
use of a typedef for a data pointer type. (Maybe there'll
be a rule against that later on -- but since the typedef is
still there in the "compliant solution," maybe not. There
ought to be such a rule, IMHO.)

DCL04-A: Oh, fiddlesticks. I spit upon your silly
rule; my qsort() comparators almost always begin with

int compare(const void *pp, const void *qq) {
const Type *p = pp, *q = qq;

and I intend to go right on doing so. Layout is not an
appropriate subject matter for rule-making unless a positive
benefit can be found; restricting the programmer's freedom
of layout also restricts his ability to *use* layout to make
the code more readable. The example given is such a tired
old newbie mistake that it's hardly worth mentioning -- if
you're using programmers who could make it, no amount of
rules and standards are going to make your system secure
anyhow.

DCL05-A shows one of the more famously difficult-to-
eyeball declarations, but since the programmer never needs
to write the declaration anyhow (and never needs to read it
unless he's perusing the implementation's headers, in which
case he'll run into far more baffling things), it's hardly
helpful in deciding when to use the "clarifying" typedef.
Is `int (*func)(int)' too complex? If not, why not? Where's
the dividing line?

DCL06-A is often a good practice, but can be taken too
far. Surely, exceptions can be made for 0 and 1, and maybe
for 2. Do you *really* think

enum { TWO = 2 }; /* a scalar */
enum { FOUR = 4 }; /* a scalar */
enum { SQUARE = 2 }; /* an exponent */
x = (-b + sqrt(pow(b,SQUARE) - FOUR*a*c))
/ (TWO * a);

is an improvement on

x = (-b + sqrt(b*b - 4*a*c)) / (2*a);

? Also, why is the "compliant solution" compliant? The
magic number 18 still appears in it, albeit in a different
context.

DCL07-A needs an editing pass. Also, I do not see the
claimed undefined behavior in the non-compliant example, and
the comments on the static variables in both code samples
are wrong (the identifier has no linkage, not internal linkage).

DCL08-A: Note that the compiler must issue a diagnostic
for the code in the non-compliant example. Also, the calling
mechanism described in the risk assessment is by no means
universal (the machine in front of me at this moment doesn't
use it). (By the way, why is this in the DCL section?)

DCL09-A needs a note to the effect that it relies on a
type not defined in any Standard header (indeed, a type that
Standard headers are forbidden to declare).

DCL20-A: Why the distinction between "must" call va_start
but "should" call va_end? "Must" and "must" would be better.
(And why is this in DCL?)

DCL11-A: Again, too much (non-portable) detail about the
mechanism of the failure. There is no assurance that "the
integer is silently converted into a pointer;" what actually
happens may be completely different. The code is in error,
but does not necessarily fail in the manner described. Similar
remarks pertain to the second example. (Why is it in DCL?)

DCL30-C: I don't think this should be a "rule," because
as far as I know there is no way to verify conformance in
all cases (third requirement in definition of "rule"). Or
can you propose a verification method? (And why is this
in DCL?)

DCL31-C: The advice is good, but the first example really
goes to a different point: Don't write free-hand declarations
of Standard library functions (indeed, of your own library
functions, except in the library's own headers). Also, note
that a C99 compiler must issue diagnostics for the code in
the third and fourth examples, and the "implicitly defined"
remark after the fourth example is incorrect for C99.

DCL32-C overstates its case: Why should (for example)
no-linkage identifiers in different scopes be unique?

DCL34-C: The "compliant solution" may comply to CERT's
standard, but it fails to comply to C's standard. (Hint:
What is the type sig_atomic_t for?) Also, why is the "risk
assessment" talking about a completely different qualifier?

DCL35-C forbids a common and useful practice. Also,
note that a diagnostic is required for the code in the non-
compliant example.

INT00-A might make mention of <limits.h>.

INT01-A offers two "compliant solutions" that call malloc()
and then use the returned value WITHOUT CHECKING FOR NULL!!!
Go to Jail. Go directly to Jail. Do not pass Go. Do not
collect $200. Also, why does the second compliant solution
use < instead of <=? Finally, there's entirely too much
foreknowledge of the characteristics of C's data types; who
says an unsigned int is 32 bits?

INT02-A: "the sum is truncated" is a common outcome, but
not one that it guaranteed by the C language.

INT05-A should note that the compliant solution is not
a drop-in replacement for the non-compliant original. Also,
there's a bug in the solution that a quick bench-test will
easily reveal.

INT06-A ought to mention that the third argument to
strtol() should almost always be 10; I'd even delete the
"almost" if input is coming from a human being. Only a
user of C or a C derivative expects a leading zero to be
significant; ISTR you can find some reports on comp.risks
of unhealthy consequences ensuing from non-programmers
inadvertently entering base-eight values.

INT07-A: The compliant solution (!) requires a compiler
diagnostic (on the assumption that the non-compliant example
did not and that bash_input.location.string is not of type
void*). A better solution, IMHO, is to leave the pointer
type alone and to use `c = (unsigned char)*string++' to
pluck the value out.

INT08-A: In light of INT03-A and INT04-A, why do we
need this? If there's something new, I've missed it.

INT09-A: In the third compliant solution, `indigo=yellow'
and `violet=green' would be better still. (The example
suggests a kind of visual impairment; perhaps it could be
re-worked into something where the duplicated values make
more sense? Perhaps `cerise=red' and `lime=green' would
startle the reader a bit less.)

INT10-A looks like a rehash of DCL00-A; why repeat it?
The only new thing seems to be to hang "non-confirming" on
implementations that don't prevent alteration of const-
qualified objects; the label is unwarranted and incorrect.

INT11-A: Why repeat INT02-A? (Well, it's not really
a repetition: The "compliant solution" for this one has
undefined behavior if SCHAR_MAX < 255, which describes
a very large fraction of implementations.)

INT12-A: I haven't yet decided whether the main argument
of this section is right or wrong. However, the expression
`(bits.a << 24)' exhibits undefined behavior if ints aren't
at least 33 bits wide.

That's all I've got time for now (the clumsy navigation
slows me down). My general impression is that there's some
good stuff in here, but it's interlarded with oversights
major and minor, and with entirely too much specificity
about how implementations work "under the hood." If the
document wants to talk about C, let it talk about C and
not about specific implementations of C (except in the
few cases where that's unavoidable). Otherwise, change
the title to "Secure Coding for Frobozz Magic C."
 
K

Keith Thompson

Eric Sosman said:
General observation: The navigation on this site makes
sequential reading cumbersome: The only (apparent) way to
navigate from a leaf to the next leaf is to crawl back up
the tree to the parent first. Cannot we have Next (and maybe
Previous) links like everybody else?

Agreed. I took a very quick look at the site, but I lost patience
with the navigation. A linear PDF document would suit me much better,
or even just plain text. (I know some people have reasons to dislike
PDF; I'm speaking only for myself.)

[...]
Introduction/Rules Versus Recommendations, second point
in the definition of a rule:

There is an enumerable set of exceptional conditions
(or no such conditions) in which violating the coding
practice is necessary to ensure the correct behavior
for the program.

Perhaps my reading comprehension has deteriorated, but I can
make no sense of this sentence. The first part describes a
situation in which there is a set of conditions or there are
no conditions; isn't this vacuously true? It sure looks an
awful lot like `true OR false' to me.

I think it's saying that if there are any such conditions (there may
not be), they must form an enumerable set.
Then the second part
speaks of a program that only works correctly when the rule
is violated; hence if the program is compliant it does not
work, and if it works it cannot be compliant. Is that what
is really intended?

I suspect the point here is that this is not an attempt to define a
set of rules that must never be violated; there may be circumstances
in which a programmer must (carefully) violate a rule to get the job
done.

[big snip]
 
R

Robert Gamble

Robert said:
jacob navia <[email protected]> wrote:

... snip ...
This makes no sense to me.
Standardize strlcat and strlcpy. Deprecate gets(). If you care

So far you are doing fine, (and should include ggets()) but ...
about security don't pass an unchecked user-provided string as the
format string to printf(), use snprintf() instead of sprintf(),
don't use the %s/%[ scanf() conversion specifiers without a
precision, etc. If you care about reentrancy don't use functions
like strtok/strerror/asctime/ gmtime/etc but instead use the POSIX
*_r equivalents like everyone else, if you insist on having these
functions in Standard C go ahead and lobby for them to be included
in the next version, just don't reinvent the wheel. Finally, don't
hire programmers that can't keep track of the size of a char array
or who don't know how to count.

But now you are getting outside the realm of standard C, IMO.

The point regarding reentrancy is that there already exist reentrant
versions of the functions that a) exist on many systems, and b) work
just fine. If there is a desire to address this issue in Standard C
it would make quite a bit more sense to lobby to include the existing
functions, which many people are already familiar with and are already
implemented in many C libraries, instead of proposing something
completely new.
However we can always accept the last sentence :).

It's amazing to me how many people apparently people can't.

Robert Gamble
 
R

rCs

General observation: The navigation on this site makes
sequential reading cumbersome: The only (apparent) way to
navigate from a leaf to the next leaf is to crawl back up
the tree to the parent first. Cannot we have Next (and maybe
Previous) links like everybody else?

this sounds like a great idea; i'm not sure why it hadn't already
occurred to me.

thanks for taking the time to do a thorough evaluation. we will go
through each of your comments and give then careful consideration.

thanks again,
rCs
 
R

rCs

Standardize strlcat and strlcpy.

i believe strlcat and strlcpy are being proposed for TR 24731-2,
although i don't believe these functions handle string truncation very
well (the interface is rather complex).
Deprecate gets().

This was accomplished at the London meeting in April.

rCs
 
K

Keith Thompson

rCs said:
i believe strlcat and strlcpy are being proposed for TR 24731-2,
although i don't believe these functions handle string truncation very
well (the interface is rather complex).


This was accomplished at the London meeting in April.

Please don't snip attribution lines (such as the line above that says
follow the discussion.
 
R

Richard Tobin

Army1987 said:
It means that that set is enumerable, i.e. that its cardinality
is aleph-null or less.

Though "enumerable" is probably sometimes used with that meaning,
the usual terms are "countable" and "denumerable".

-- Richard
 
A

Army1987

Introduction/Rules Versus Recommendations, second point
in the definition of a rule:

There is an enumerable set of exceptional conditions
(or no such conditions) in which violating the coding
practice is necessary to ensure the correct behavior
for the program.

Perhaps my reading comprehension has deteriorated, but I can
make no sense of this sentence. The first part describes a
situation in which there is a set of conditions or there are
no conditions; isn't this vacuously true?
It means that that set is enumerable, i.e. that its cardinality
is aleph-null or less. (Since the empty set is enumerable, the
parenthesized phrase is redundant.) :)
(More likely they meant that it is possible to enumerate all these
conditions, so it means that the set is finite, and perhaps
reasonably small. But if they meant *that* they'd better say "a
small set".)
 
E

Eric Sosman

Army1987 said:
It means that that set is enumerable, i.e. that its cardinality
is aleph-null or less. (Since the empty set is enumerable, the
parenthesized phrase is redundant.) :)
(More likely they meant that it is possible to enumerate all these
conditions, so it means that the set is finite, and perhaps
reasonably small. But if they meant *that* they'd better say "a
small set".)

Ah! I think I get it ("Light dawns on Marblehead"): It's
all right to flout the rules if the exceptional circumstances
that require flouting it are enumerable.

... but doesn't that mean that it's *always* all right to
flout the rules? The set of all possible Turing machines is
enumerable (by the diagonal argument), and the number of Turing
machines clearly dwarfs the number of programs that can actually
be written for real finite hardware, so ...?

Now that I (think I) understand the requirement, I am more
perplexed by it than when I thought it gibberish. That word
"enumerable" is, as you point out, at the root of the difficulty,
but what small finite number should be proposed? "It's OK to go
ape, but no more than forty-two times per MLOC?"
 
R

Robert Seacord

Eric Sosman wrote:

Now that I (think I) understand the requirement, I am more
perplexed by it than when I thought it gibberish. That word
"enumerable" is, as you point out, at the root of the difficulty,
but what small finite number should be proposed? "It's OK to go
ape, but no more than forty-two times per MLOC?"

Eric,

What I had in mind was that these conditions be enumerated as part of
the rule, not that individuals claiming compliance could simply made up
exceptions as they went along.

Another way we could handle this would be to allow users of the
standards to break whatever rules they like, provided they document
which rules were broken and why. Someone interested in acquiring this
system could then ask for and review this list.

rCs
 
E

Eric Sosman

Robert Seacord wrote On 08/03/07 14:56,:
Eric Sosman wrote:





Eric,

What I had in mind was that these conditions be enumerated as part of
the rule, not that individuals claiming compliance could simply made up
exceptions as they went along.

Another way we could handle this would be to allow users of the
standards to break whatever rules they like, provided they document
which rules were broken and why. Someone interested in acquiring this
system could then ask for and review this list.

So even when I got it, I didn't get it? Well,
to err is human (and to really screw up requires
a computer).

My third try at understanding is that a rule
requires some coding practice, but is allowed to
grant exceptions in enumerated cases. If the coding
practice is "Identifiers must not contain vowels,"
the rule may grant an exception of the form "except
for no-linkage identifiers with scopes less than
seventeen lines long." But a proper rule may *not*
grant an exception of the form "unless you feel like
it" or "except sometimes." Have I got it now?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top