Is it time for secure C ?

R

Roman Ziak

Hello,

I just downloaded MS Visual Studio 2005 Express Beta. When I tried to
compile existing valid project, I get a lot of warnings like 'sprintf'
has been deprecated, 'strcpy' has been deprecated etc. I opened STDIO.H
and figured that one has to define a macro _CRT_SECURE_NO_DEPRECATE
to stop these warnings.

I started to search internet and found few links, and the following proposal

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1031.pdf

After looking into Whidbey Beta header files I started liking this. This is
something I have been using already for static and local buffers using
macro with strncpy() and vsnprintf(), only this is better.

Although this feature should be invoked by defining _USE_SECURE_LIBS
and not be used by default, that's easy to fix in CRTDEFS.H.

Anyway, I am just wondering if anybody knows about the status of this
proposal. And also would like to read some opinions.

Roman
 
J

jacob navia

This is very good. I have been arguing in this group against the situation
in C where
unsecure programming is the rule. This means that things can change.

In lcc-win32, after a discussion about C strings in this group, I developed
a secure
string library, that is distributed with the compiler.

The Microsoft proposal goes in this direction, albeit it leaves to the
programmer
the work of always specifying correctly the block size. I posted in
comp.lang.lcc
an article proposing the usage of *bounded* pointers, that would solve the
problem of strings and other related problems.

jacob

http://www.cs.virginia.edu/~lcc-win32
 
V

Vijay Kumar R Zanvar

jacob navia said:
the work of always specifying correctly the block size. I posted in
comp.lang.lcc

There is no such group by this name. ITYM, news:comp.compilers.lcc
 
R

Richard Bos

[ Please, leave _some_ context. ]
This is very good. I have been arguing in this group against the situation
in C where unsecure programming is the rule.

It isn't. Insecure programming is the rule anywhere rank amateurs or
poor professionals program in any language; it is not the rule where
real professionals or dedicated amateurs program, in C no more than in
Ada.
In lcc-win32, after a discussion about C strings in this group, I developed
a secure string library, that is distributed with the compiler.

Which, of course, is off-topic here.
The Microsoft proposal goes in this direction,

It is a dreadful solution, but one of the kind which is entirely
expected of those embrace-extend-and-massively-abuse artists.
I posted in comp.lang.lcc an article proposing the usage of *bounded* pointers,

There is a newsgroup especially for lcc? That's great! That means you
won't have to post off-topic material in comp.lang.c anymore, and we
won't have to bother you with our requests for topicality anymore. Now,
all that remains is for you to post lcc-specific material there, and ISO
C material here...

Richard
 
G

Guillaume

I just downloaded MS Visual Studio 2005 Express Beta. When I tried to
compile existing valid project, I get a lot of warnings like 'sprintf'
has been deprecated, 'strcpy' has been deprecated etc. I opened STDIO.H
and figured that one has to define a macro _CRT_SECURE_NO_DEPRECATE
to stop these warnings.

1. And what exactly makes you think that any Microsoft's tantrum is
going to mean anything valid in the C world?

2. Since when Microsoft is a well known authority for secure
programming? There is so much evidence of the opposite,
it's somewhat boggling...

3. So according to them, sprintf, strcpy and the like have
been deprecated? How presumptuous.

4. They seem to keep thinking that software quality is going to be
achieved with software tools for incompetent programmers. I don't
think this is ever going to work.

5. I have heard of Visual Studio 2005, and it sounds like this
new release doesn't give anything more than hypothetical improved
"programming security". Sounds more like marketing than engineering
to me.


"Secure C" in itself doesn't exist any more than a "secure car".
If you can't drive, no amount of so-called technology is going
to change the fact that you're dangerous behind the wheel - except
if you're not actually driving it yourself. Is that where Microsoft
wants the profession to be heading?
 
A

Arthur J. O'Dwyer

I just downloaded MS Visual Studio 2005 Express Beta. When I tried to
compile existing valid project, I get a lot of warnings like 'sprintf'
has been deprecated, 'strcpy' has been deprecated etc. I opened STDIO.H
and figured that one has to define a macro _CRT_SECURE_NO_DEPRECATE
to stop these warnings.

(This sounds like typical Microsoft behavior. Ick.)

I started to search internet and found few links, and the following
proposal
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1031.pdf

This is a somewhat interesting proposal, and one I hadn't seen
before (at least, not in such a standardese-specified way). It
doesn't strike me as particularly useful. Read on.


The 'scanf_s' family of functions is slightly broken, from the
implementor's point of view. Consider Example 2 in section 3.2.2.1:

EXAMPLE 2 The call:
#define __USE_SECURE_LIB__
#include <stdio.h>
/* ... */
int n; char s[5];
n = fscanf_s(stdin, "%s", s, sizeof s);
with the input line:
hello
will assign to 'n' the value 0 since a matching failure occurred
because the sequence 'hello\0' requires an array of six characters
to store it. No assignment to 's' occurs.

In other words, the implementation of 'scanf_s' requires a lookahead
buffer of at least N characters, where N is some value specified by the
user at runtime. This is certainly possible (especially with C99 VLAs
at the implementor's disposal), but is the proposed "security" worth
the inconvenience?

(There's also the issue of what happens when the programmer passes
a 'size_t' argument to a variadic function; I forget exactly what is
supposed to happen, but the integer promotions definitely don't help.
Maybe this is a non-issue in this case, though.)

The 'gets_s' function is exactly equivalent to the existing 'fgets'
function, except that it discards the *USEFUL* end-of-line indicator,
which is the only thing that can tell the program that a full line
has indeed been read. 'gets_s' is thus *WORSE* than nothing! (Though
it's not as bad as 'gets'. ;)

The 'rand_s' function would be absolutely a godsend... if the
author had bothered to specify its behavior!


The 'bsearch_s' function is interesting, but of course it doesn't
add any functionality to the library that didn't already exist in C99
(I don't know whether C90 guaranteed that 'key' would always be the
first argument to 'compar'). And it has *nothing* to do with
security, so it's a little silly to attach it as a "rider" onto the
main proposal.

The 'qsort_s' function is no better than the existing 'qsort'; it
guarantees neither O(NlgN) sorting time nor stable sorting. What
it *does* do is add unnecessary complexity; perhaps the 'context'
argument is an alternative to "locales" in C99? I don't know. It's
certainly not any improvement on the existing C99 functions.

And from the security POV, the author completely forgot to address
the major security hole in both functions: they take two 'size_t'
parameters, right next to each other, and I never remember which
is which. The compiler is never smart enough to help, either. So
this is a potential source of major hard-to-find bugs in C programs,
and the proposed "secure" library doesn't even address the issue!


'memcpy_s(foo, n, bar, n)' replaces the existing 'memcpy(foo, bar, n)',
and likewise 'memmove'. Extra verbosity, no security gain. Bad idea.

In practice, 'strncpy_s' now performs exactly the same function as
'memcpy_s'; ironically, the historical extra security of filling the
array out with NUL bytes is removed!

'strlen_s' is interesting, but I hardly think it's useful for its
intended purpose; after all, wasn't the whole point of this string
library proposal so that all strings *would* have well-defined lengths,
thus making the existing 'strlen' perfectly safe?


In conclusion, I think it's pretty ironic that the proposal begins
with the paragraph

Traditionally, the C Library has contained many functions that trust
the programmer to provide output character arrays big enough to hold
the result being produced. Not only do these functions not check that
the arrays are big enough, they frequently lack the information needed
to perform such checks. While it is possible to write safe, robust,
and error-free code using the existing library, the library tends to
promote programming styles that lead to mysterious failures if a
result is too big for the provided array.

when all it does is provide even *more* functions that require "big
enough" character arrays with programmer-specified values, thus promoting
the "mysterious failure" programming style it claims to be trying to
avoid!
Anyway, I am just wondering if anybody knows about the status of this
proposal. And also would like to read some opinions.

I hope this was useful to you.

-Arthur
 
M

Malcolm

Richard Bos said:
It isn't. Insecure programming is the rule anywhere rank amateurs or
poor professionals program in any language; it is not the rule where
real professionals or dedicated amateurs program, in C no more than in
Ada.
C makes it very easy to address memory illegally. This problem can be solved
by using another language, at the cost of some runtime inefficiency and loss
of simplicity.
What no language and no compiler can solve is the logic error. If I am
writing control software for an aircraft, and I accidentally use a sine
rather than a cosine in some vital calculation, it will not be picked up
except through testing, or when the aeroplane crashes.
 
J

Jeremy Yallop

Arthur said:
I started to search internet and found few links, and the following
proposal
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1031.pdf
[...]
The 'bsearch_s' function is interesting, but of course it doesn't
add any functionality to the library that didn't already exist in C99
(I don't know whether C90 guaranteed that 'key' would always be the
first argument to 'compar').

It did.
The 'qsort_s' function is no better than the existing 'qsort'; it
guarantees neither O(NlgN) sorting time nor stable sorting. What
it *does* do is add unnecessary complexity; perhaps the 'context'
argument is an alternative to "locales" in C99? I don't know. It's
certainly not any improvement on the existing C99 functions.

I agree with much of what you wrote, but I think you've overlooked the
usefulness of the `context' argument. In my experience, a `context'
argument is an essential part of any properly-designed interface
involving a callback function, allowing customization of the behaviour
of the comparison function at runtime. The lack of it is, I think,
the one major defect in the specification of qsort().

An example is perhaps the easiest way to show this: suppose you want
to sort an array of elements of structure type:

struct element {
int id;
char strings[3];
} elements[] = { ... };

Further, you want to allow sorting by a particular member, say
strings[0], strings[1] or strings[2], and to provide the option of
sorting in forward or reverse. One way to do this is to provide two
separate comparison functions for each possibility:

int compare_zero(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return strcmp(left->strings[0], right->strings[0]);
}

int compare_one(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return strcmp(left->strings[1], right->strings[1]);
}

int compare_two(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return strcmp(left->strings[2], right->strings[2]);
}

int compare_r_zero(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return - strcmp(left->strings[0], right->strings[0]);
}

int compare_r_one(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return - strcmp(left->strings[1], right->strings[1]);
}

int compare_r_two(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return - strcmp(left->strings[2], right->strings[2]);
}

The appropriate comparison function can then be selected at runtime by
an if-else ladder, or an array of pointers to the functions, etc.
Duplicating the comparison code in this way is pretty inelegant,
though, besides being a maintenance burden. Obviously, it's desirable
to replace the almost-identical functions above with a single
function, and parameterize the hard-coded indexes and minus operator.

int compare(const void *l, const void *r)
{
const struct element *left = l, *right = r;
return sign * strcmp(left->strings[index], right->strings[index]);
}

The question, of course, is "Where do `sign' and `index' come from?
They could be global variables, but this is undesirable for a number
of reasons: giving up thread safety, re-entrancy, modularity, etc.
The ideal thing would be to pass them as parameters, but qsort()
provides no mechanism for doing this: the signature of the comparison
function is fixed, and only allows two arguments to be passed. Now, I
hope, the purpose of the `context' parameter starts to become clear.
We can pass data of any type through `context', so the single function
becomes easy to write:

struct context
{
int sign;
int index;
};
int compare_ctxt(const void *l, const void *r, void *context)
{
const struct element *left = l, *right = r;
return context->sign * strcmp(left->strings[context->index],
right->strings[context->index]);
}

Having dispensed with the plethora of functions, there's no longer any
need for a runtime selection of comparison function, so the code that
invokes qsort() (or rather, qsort_s()) becomes much simpler as well.
Borrowing some syntax from C99:

qsort_s(elements,
sizeof elements / sizeof elements[0],
sizeof elements[0],
&(struct context){direction, index});

This is essentially the same as the concept of a "closure" in more
functionally-inclined languages, albeit quite a bit more explicit.

Jeremy.
 
A

Arthur J. O'Dwyer

I agree with much of what you wrote, but I think you've overlooked the
usefulness of the `context' argument. In my experience, a `context'
argument is an essential part of any properly-designed interface
involving a callback function, allowing customization of the behaviour
of the comparison function at runtime. The lack of it is, I think,
the one major defect in the specification of qsort().

[Snip example: sorting structs by fields 0,1,2, forward and reverse]
qsort_s(elements,
sizeof elements / sizeof elements[0],
sizeof elements[0],
&(struct context){direction, index});

Yes, I recognized that this was the intended usage, I just didn't
see any good reason to want to do this. You say you've had reason to
do this before? Well, perhaps it is useful, then, just not to me. ;)

I would pessimistically think the effort spent initializing
'direction' and 'index' ("on location," before each and every call
to the "contextual" qsort) would often exceed the amount of effort needed
to write six or seven specialized comparison functions in the first
place.
This is essentially the same as the concept of a "closure" in more
functionally-inclined languages, albeit quite a bit more explicit.

Yup.

-Arthur
 
K

Keith Thompson

Malcolm said:
What no language and no compiler can solve is the logic error. If I am
writing control software for an aircraft, and I accidentally use a sine
rather than a cosine in some vital calculation, it will not be picked up
except through testing, or when the aeroplane crashes.

Or code review. If you're writing airplane control software without
doing code review, remind me not to fly in your airplanes. (That's a
general comment, not directed at Malcolm.)
 
J

Jeremy Yallop

Arthur said:
sorting structs by fields 0,1,2, forward and reverse]
qsort_s(elements,
sizeof elements / sizeof elements[0],
sizeof elements[0],
&(struct context){direction, index});

I would pessimistically think the effort spent initializing
'direction' and 'index' ("on location," before each and every call
to the "contextual" qsort) would often exceed the amount of effort needed
to write six or seven specialized comparison functions in the first
place.

That's quite possibly true for the fairly simple example I gave, but
in some situations it's impossible to write a comparison function for
each case. Consider the case where the number of "fields" is not
known until runtime (i.e. the array member in the snipped example is
dynamically allocated).

The context argument is just the next logical step in the
parameterization of qsort(). The qsort() function is much more useful
than it would be if its behaviour couldn't be customized by compar().
The context argument is to compar() as compar() is to qsort().

Jeremy.
 
J

jacob navia

Very well written Jeremy.

A very convincing argument, well explained.

Kudos for that message.
 
J

jacob navia

Arthur J. O'Dwyer said:
On Wed, 7 Jul 2004, Jeremy Yallop wrote:
I would pessimistically think the effort spent initializing
'direction' and 'index' ("on location," before each and every call
to the "contextual" qsort) would often exceed the amount of effort needed
to write six or seven specialized comparison functions in the first
place.

If your compiler doesn't support default arguments then
you can always make a memset to zero. If the function
is well constructed, a default initialization should be easy.
 
M

Malcolm

Keith Thompson said:
Or code review. If you're writing airplane control software without
doing code review, remind me not to fly in your airplanes. (That's a
general comment, not directed at Malcolm.)
Fortunately all my aeroplanes are vitual video game ones. However we don't
do code reviews, we just play it and if it plays for areasnable length of
time without faling over, release it.
 
K

kyle york

Greetings,
C makes it very easy to address memory illegally. This problem can be solved
by using another language, at the cost of some runtime inefficiency and loss
of simplicity.

No, implementations of C make it very easy to address memory illegally.
I've not read anything in the standard the prohibits an implementation
from actually enforcing the rules.

I've given this a lot of thought of late & don't think it would be that
terribly difficult to add proper bounds checking to a good compiler.
 
R

Roman Ziak

Guillaume said:
1. And what exactly makes you think that any Microsoft's tantrum is
going to mean anything valid in the C world?

Microsoft is world seconds biggest software developper. And their main
product
is written mostly in C and C++. The most sensitive part of their product -
kernel -
is written almost entirely in C. Yes, WinNT used to crash a lot, but I seen
WinXP
crashed probably once or twice in my career and that was for the third party
driver.

What makes you think MS does not mean anything in C world ? Do you live in
the cave ?
2. Since when Microsoft is a well known authority for secure
programming? There is so much evidence of the opposite,
it's somewhat boggling...

Everybody learns from mistakes and so does this company. And they had
plethora
opportunities.
 
A

Arthur J. O'Dwyer

Microsoft is world seconds biggest software developper. And their main
product
is written mostly in C and C++. The most sensitive part of their product -
kernel -
is written almost entirely in C.

How do *you* know? ;) (And BTW, your lines are too long. Stick to
75 characters wide for Usenet, please.)
Yes, WinNT used to crash a lot, but I seen
WinXP
crashed probably once or twice in my career and that was for the third party
driver.

Lucky you. WinXP Professional crashes about twice a week at work,
and more, lately. At home it's less of a problem, but it still crashes
every so often. ...OTOH and besides, crashing is a heck of a lot better
than the alternative, from a *security* point of view!
What makes you think MS does not mean anything in C world ? Do you live in
the cave ?

The Unix/Linux/network/mainframe/embedded/portable cave, yeah,
probably. Microsoft certainly doesn't mean anything in the world
of C standards, and it doesn't mean a whole lot more even in the
world of C applications programming. Just because they hire a lot
of programmers doesn't make them relevant. ;)

Everybody learns from mistakes and so does this company. And they had
plethora opportunities.

You seriously believe that, do you? Check Google News recently;
even their bugfixes apparently need bugfixes!

-Arthur
 
R

Roman Ziak

Arthur J. O'Dwyer said:
How do *you* know? ;) (And BTW, your lines are too long. Stick to

How do *I* know ... hmmm, ... everybody knows.

I give you a hint ... if you have DDK, try to search for C and CPP files in
examples. In my case - version 3790 - it is 711 C files, 233 CPP files,
2 ASM files (which is DOS app anyway).

Look into headers and tell me how many classes do you find in DDK files ?
I found 2 files out of 111 which have a 'class'.
The Unix/Linux/network/mainframe/embedded/portable cave, yeah,
probably. Microsoft certainly doesn't mean anything in the world
of C standards, and it doesn't mean a whole lot more even in the
world of C applications programming. Just because they hire a lot
of programmers doesn't make them relevant. ;)

I do not agree.
You seriously believe that, do you? Check Google News recently;
even their bugfixes apparently need bugfixes!

Almost every more sofisticated software contains bugs. The one used
by more users will expose them much more often. And because 98%
people (Google statistics) use Windows, there will be theoretically 50x
more virus crackers searching for security holes in Windows than for
other systems.

So answer to your question: I believe that people and companies learn
from mistakes.

Btw, I have tried Linux, I used it for some short time and the apps liked
crashing very much too.

Anyway, I am not going to defend MS here, my post was about new
proposal. I liked your first post, because it was to the point unlike
Guillame's was just cheap ridiculing. I have no interest and time to
get into arguments about Windows vs. Unix or MS vs everybody.
I have interest in C and that's why I subscribed to this group. To discuss
C.

Roman
 
R

Richard Bos

Jeremy Yallop said:
I agree with much of what you wrote, but I think you've overlooked the
usefulness of the `context' argument. In my experience, a `context'
argument is an essential part of any properly-designed interface
involving a callback function, allowing customization of the behaviour
of the comparison function at runtime. The lack of it is, I think,
the one major defect in the specification of qsort().
Having dispensed with the plethora of functions, there's no longer any
need for a runtime selection of comparison function, so the code that
invokes qsort() (or rather, qsort_s()) becomes much simpler as well.

Yes... but what does that have to do with discouraging "programming
styles that lead to mysterious failures if a result is too big for the
provided array" and promoting "promote safer, more secure programming"?
It solves a completely different problem, and should not have been in
_this_ proposal.

Richard
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top