Thread: Advice on preventing buffer overflows

  1. #1
    Registered User
    Join Date
    Aug 2013
    Posts
    6

    Advice on preventing buffer overflows

    Hi,

    Just wondering if someone can give me some advice on preventing a buffer overflow when dealing with strings being passed as arguments.

    If I have a function prototype such as:

    Code:
    void foobar(char *bar);
    That argument bar - is intended to take a pointer to a buffer of x characters in length. Inside that function, I can't get the size of that buffer, as bar is now just a pointer to a char. I COULD just make the user of this function pass a length parameter, but there is no guarantee that would be correct. Is there a bullet proof way of detecting that the user has provided a buffer that is too small?

    Thanks.

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Code:
    char *buffs_r_us(void)
    {
        char *buff = malloc(BUFFER_SIZE);
        if (buff)
        {
            /* stuff buff */
        }
        return buff;
    }
    This puts the onus on the function user to test for NULL and to free the buff.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by foniks View Post
    Is there a bullet proof way of detecting that the user has provided a buffer that is too small?
    No.

    The only two options are for the caller to supply the buffer by some means, or for your function to dynamically allocate a buffer and return that.

    If the user supplies the buffer, there is no way to detect its length (nor to check that the user has given correct information about its length). That is the user's responsibility.

    If your program allocates the buffer and returns that to the caller, then (unless you make a programming error) the buffer will be sufficient. However, the result of doing that is a memory leak, unless the user remembers to deallocate the buffer. If there are enough memory leaks in a program, a typical result is program slow-down or memory exhaustion.

    Either way, you are vulnerable if you make an error of judgement or coding, or if the user does not do things correctly.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  4. #4
    Registered User
    Join Date
    Aug 2013
    Posts
    6
    Ah cool - that's what I thought, but assumed I must of been missing something! Thank you.

  5. #5
    Registered User
    Join Date
    Aug 2013
    Posts
    6
    That's a good point - the responsibilities the callers, but at least it's transparent (i.e. you know it returns allocated memory, you have to test for null and free the memory as well).

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by foniks View Post
    That's a good point - the responsibilities the callers, but at least it's transparent (i.e. you know it returns allocated memory, you have to test for null and free the memory as well).
    How is requiring a caller to test for NULL and release memory (each of which may not be done) any more transparent than requiring the caller to provide a buffer of sufficient length (which may also not be done)?

    Both are responsibilities of the caller that the caller is not guaranteed to meet.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  7. #7
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    I should have began my "answer" with "NO" as grumpy did. There's no way to protect against errors here. You just get to chose from different sets of possible errors.

    The user must read and comply with the documentation for the function, providing what it needs and testing return values (and possibly other values) as required. So neither method (allocating or preallocating) is perfect.

    It's often best to get the user to allocate the buffer so that the allocation/deallocation is "bracketed" in the his own code (perhaps he's less likely to forget to free it if he allocates it himself), and in particular it allows the use of a local variable, automating memory management.

    You might define a constant for the required size. An example of this is BUFSIZ, defined in the standard library (stdio.h) for I/O buffers.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  8. #8
    Registered User
    Join Date
    Aug 2013
    Posts
    6
    @grumpy - because as a user of that function it's not clear what the function may be doing, what checks it's doing etc. But in the other case, I know I have to do something with that memory. I may not do it - and that'd be wrong, but the onus is now on me. Not on someone else code that I may not be able to see.

  9. #9
    Registered User
    Join Date
    Aug 2013
    Posts
    6
    Quote Originally Posted by oogabooga View Post
    I should have began my "answer" with "NO" as grumpy did. There's no way to protect against errors here. You just get to chose from different sets of possible errors.

    The user must read and comply with the documentation for the function, providing what it needs and testing return values (and possibly other values) as required. So neither method (allocating or preallocating) is perfect.

    It's often best to get the user to allocate the buffer so that the allocation/deallocation is "bracketed" in the his own code (perhaps he's less likely to forget to free it if he allocates it himself), and in particular it allows the use of a local variable, automating memory management.

    You might define a constant for the required size. An example of this is BUFSIZ, defined in the standard library (stdio.h) for I/O buffers.
    Thanks - that's a good approach.

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by foniks View Post
    Hi,

    Just wondering if someone can give me some advice on preventing a buffer overflow when dealing with strings being passed as arguments.

    If I have a function prototype such as:

    Code:
    void foobar(char *bar);
    That argument bar - is intended to take a pointer to a buffer of x characters in length. Inside that function, I can't get the size of that buffer, as bar is now just a pointer to a char. I COULD just make the user of this function pass a length parameter, but there is no guarantee that would be correct. Is there a bullet proof way of detecting that the user has provided a buffer that is too small?

    Thanks.
    Forcing the user to supply a length parameter for output buffers will virtually eliminate the possibility of overflows (there are still a few corner cases, but these are generally caught elsewhere in the program and easily identified). Personally, I wouldn't use any library function that doesn't require buffer lengths for output - besides posing a security threat to anyone relying on my program, it's just too damn easy to forget to allocate enough memory.

    As for input parameters, it's often sufficient to expect a null-terminated string (depends on the data format, of course); the data is effectively read-only so no possibility for overflow anyway...
    Last edited by Sebastiani; 09-21-2013 at 08:11 PM.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by foniks View Post
    @grumpy - because as a user of that function it's not clear what the function may be doing, what checks it's doing etc. But in the other case, I know I have to do something with that memory. I may not do it - and that'd be wrong, but the onus is now on me. Not on someone else code that I may not be able to see.
    Sorry, but I think your premise is flawed.

    The caller of a function does not need to know what checks the function does. All it needs to know is what that function expects of a caller - in terms of what the caller does BEFORE calling your function (say, allocating a buffer of required length) or what the caller is required to do AFTER calling your function (say, deallocating a buffer that your function has allocated).

    Either way, you're relying on correct behaviour of code you may not be able to see.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  12. #12
    Registered User
    Join Date
    Aug 2013
    Posts
    6
    Sure. Understood - thanks for your help.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 10-08-2012, 07:29 PM
  2. Replies: 5
    Last Post: 02-11-2011, 02:53 PM
  3. Sprintf overflows my buffer -- why?
    By Lasston in forum C Programming
    Replies: 26
    Last Post: 06-20-2008, 04:33 PM
  4. Question on buffer overflows
    By maxhavoc in forum C++ Programming
    Replies: 3
    Last Post: 11-25-2004, 03:48 PM
  5. Avoiding Buffer Overflows
    By Aidman in forum C++ Programming
    Replies: 5
    Last Post: 01-03-2004, 12:21 PM