Buffer overflow protection

I

Ioannis Vranos

If we want our programs to be protected against buffer overflows, must we
check the size of the various containers explicitly?

E.g.

#include <iostream>
#include <string>


int main()
{
using namespace std;

string s;

while(cin>>s)
;

// ...
}


should become:


#include <iostream>
#include <string>
#include <cctype>


int main()
{
using namespace std;

string s;

while(cin && s.size()<s.max_size())
{
char c;

cin>>c;

if(isspace(c))
continue;

s.push_back(c);
}



// ...
}






Ioannis Vranos
 
I

Ioannis Vranos

Ioannis Vranos said:
If we want our programs to be protected against buffer overflows, must we
check the size of the various containers explicitly?

E.g.

#include <iostream>
#include <string>


int main()
{
using namespace std;
string s, temp;


while(cin>>temp)
s+=temp;
 
H

Howard

I'm puzzled. Is it even *possible* for s.size() to have a value greater
than s.max_size()? That would seem to violate the concept of "max",
wouldn't it? So, shouldn't the streaming operator prevent s.size() from
ever exceeding s.max_size() in the first place, making any such check on
your part redundant?

I know that checking for buffer overruns is important when filling arrays,
but I would think one of the advantages of using a string class and
streaming operators is to protect against such things.

But for filling arrays, I'd agree on your design, where you add one
character at a time. It's silly to try to see if you've *already* overrun
memory.

-Howard
 
D

David Harmon

On Tue, 13 Apr 2004 14:59:35 +0300 in comp.lang.c++, "Ioannis Vranos"
If we want our programs to be protected against buffer overflows, must we
check the size of the various containers explicitly?

You need to ensure that the sizes are checked.
How explicit it is, is another matter.
string s;

while(cin>>s)

Here std::string and its operator>> do the checking.
So, it does not need to be explicit.
 
K

Kevin Goodsell

Howard said:
I'm puzzled. Is it even *possible* for s.size() to have a value greater
than s.max_size()? That would seem to violate the concept of "max",
wouldn't it?

I believe so. I was unable to find exact details, but I'm fairly sure
that attempting to exceed a container's max_size will fail for one
reason or another. I suspect it will fail due to memory exhaustion
before you get to that point, and if that doesn't occur it will probably
throw an exception. The standard definitely says that an exception will
be thrown in a few cases (like calling reserve() for a vector where the
new capacity is too large, if I recall correctly).
So, shouldn't the streaming operator prevent s.size() from
ever exceeding s.max_size() in the first place, making any such check on
your part redundant?

I think the container (or string) itself will prevent it.

-Kevin
 
K

Kevin Goodsell

Ioannis said:
string s, temp;


while(cin>>temp)
s+=temp;

The library is responsible for managing the buffers and preventing their
overflowing. I generally assume memory exhaustion will occur before
anything else. If max_size() is reached first, I'm not 100% sure what
should happen. My guess is that an exception will be thrown, either
length_error or bad_alloc. In effect, exceeding max_size() means
exhausting the memory of the allocator I think, so bad_alloc might be
appropriate, though I suppose I should check the standard and see how
allocators are supposed to handle running out of memory.

From a security standpoint, if we assume that an overflow of this sort
could exist, it seems likely that an attack exploiting such an overflow
would have much less chance of succeeding than a traditional
fixed-buffer-length overflow attack. max_size() is probably up around 2
or 4 billion. That's a hell of a lot of data to dump into the program.
If it were a remote attack, it would take quite a while to transfer all
that (over 3 minutes on a 10 Mbps connection?), and I imagine a IDS
(which I know nothing about) would have a very good chance of detecting
that.

-Kevin
 
I

Ioannis Vranos

Kevin Goodsell said:
The library is responsible for managing the buffers and preventing their
overflowing. I generally assume memory exhaustion will occur before
anything else.


This can't happen on all modern systems using virtual memory (swap) file. If
one has 10 GB swap file my guess is that max_size() can be reached. I am too
bored to check the standard but if noone provides an answer i shall be
forced to do so, since i can't live for long with such a question.

If max_size() is reached first, I'm not 100% sure what
should happen. My guess is that an exception will be thrown, either
length_error or bad_alloc. In effect, exceeding max_size() means
exhausting the memory of the allocator I think, so bad_alloc might be
appropriate, though I suppose I should check the standard and see how
allocators are supposed to handle running out of memory.

From a security standpoint, if we assume that an overflow of this sort
could exist, it seems likely that an attack exploiting such an overflow
would have much less chance of succeeding than a traditional
fixed-buffer-length overflow attack. max_size() is probably up around 2
or 4 billion. That's a hell of a lot of data to dump into the program.
If it were a remote attack, it would take quite a while to transfer all
that (over 3 minutes on a 10 Mbps connection?), and I imagine a IDS
(which I know nothing about) would have a very good chance of detecting
that.


Buffer overflow attacks happen all the time. However i am not checking about
protection against attacks here. This is a general reliability question. If
there is no such a check implicitly in standard library containers, the
whole scenario will defeat the abstraction mechanism of the standard library
and i do not think this can happen anyway. In 15 minutes or so i 'll check
the standard and drop a message here.






Ioannis Vranos
 
K

Kevin Goodsell

Ioannis said:
This can't happen on all modern systems using virtual memory (swap) file. If
one has 10 GB swap file my guess is that max_size() can be reached. I am too
bored to check the standard but if noone provides an answer i shall be
forced to do so, since i can't live for long with such a question.

I found this in the unofficial list of C++2003 changes:

Insert subclause 21.3, paragraph 4a:

4a For any string operation, if as a result of the operation,
size() would exceed max_size() then the operation throws
length_error.


Strangely, I couldn't find anything similar for other containers.

-Kevin
 
K

Kevin Goodsell

Kevin said:
I found this in the unofficial list of C++2003 changes:

Insert subclause 21.3, paragraph 4a:

4a For any string operation, if as a result of the operation,
size() would exceed max_size() then the operation throws
length_error.


Strangely, I couldn't find anything similar for other containers.

This document, by the way, came from Stroustrup's web page if I recall
correctly. If it's not there, then maybe it was Koenig's page.

-Kevin
 
I

Ioannis Vranos

Kevin Goodsell said:
I found this in the unofficial list of C++2003 changes:

Insert subclause 21.3, paragraph 4a:

4a For any string operation, if as a result of the operation,
size() would exceed max_size() then the operation throws
length_error.


Can you provide the URL please? And what is C++2003? I assume C++0x as it
had so far?






Regards,

Ioannis Vranos
 
I

Ioannis Vranos

Ioannis Vranos said:
In 15 minutes or so i 'll check the standard and drop a message here.


From the C++98 standard:

<stdexcept>

19.1.4 Class length_error

namespace std {
class length_error : public logic_error {
public:
explicit length_error(const string& what_arg);
};
}

1 The class length_error defines the type of objects thrown as exceptions to
report an attempt to produce
an object whose length exceeds its maximum allowable size.
length_error(const string& what_arg);

2 Effects: Constructs an object of class length_error.

3 Postcondition: strcmp(what(), what_arg.c_str()) == 0.


....


21.3 Template class basic_string

3 In all cases, size() <= capacity().

4 The functions described in this clause can report two kinds of errors,
each associated with a distinct exception:
- a length error is associated with exceptions of type length_error
(19.1.4);
- an outofrange
error is associated with exceptions of type out_of_range (19.1.5).


[Elsewhere it mentions length error check in the constructors: "Throws:
length_error if n == npos". And in many other places. ]

....

vector throws it too: "Throws: length_error if n > max_size()."



basic_string (including string of course), and vector are the only standard
library containers that throw std::length_error exception.


Naturally i should not expect any such checks from classes of the kind
valarray. For classes like std::bitset i shall check some other time...






Regards,

Ioannis Vranos
 
I

Ioannis Vranos

Provided the length_error exception the reliability of the code can be
ensured:


#include <iostream>
#include <string>
#include <stdexcept>


int main()
{
using namespace std;

string s, temp;

try
{
while(cin>>temp)
s+=temp;
}

catch(length_error)
{
// ...
}

// ...
}


or

#include <iostream>
#include <string>
#include <stdexcept>


int main() try
{
using namespace std;

string s, temp;

while(cin>>temp)
s+=temp;

// ...
}

catch(std::length_error)
{
// ...
}






Ioannis Vranos
 
T

tom_usenet

This can't happen on all modern systems using virtual memory (swap) file. If
one has 10 GB swap file my guess is that max_size() can be reached. I am too
bored to check the standard but if noone provides an answer i shall be
forced to do so, since i can't live for long with such a question.

On a 32 bit system, you generally only have about 2GB of virtual
memory to play with - hitting this limit with modern software is a
real possibility. The size of the swap file and physical memory have
no bearing on this - it's an addressing problem that is solved only by
moving to 64-bit architecture, or coming up with another arcane
segmented pointer architecture like DOS's near and far pointers.

Tom
 

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,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top