C Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me
Go Back   Dev Shed ForumsProgramming LanguagesC Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
Dell PowerEdge Servers
  #1  
Old May 5th, 2008, 12:48 PM
Scorpions4ever's Avatar
Scorpions4ever Scorpions4ever is offline
Banned ;)
Dev Shed God 5th Plane (7000 - 7499 posts)
 
Join Date: Nov 2001
Location: Glendale, Los Angeles County, California, USA
Posts: 7,337 Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level) 
Time spent in forums: 4 Weeks 13 h 9 m 33 sec
Reputation Power: 674
Puzzle of the Month 05-05-2008

First, here's wishing you all a Happy Sinco De Mayo. With that said, today's puzzle has an especially strong reason to be here -- it happened to keep me up all weekend. This bug existed in our code for a few weeks, but was only triggered by some other recent changes to our codebase. I discovered the cause of the bug on Friday, but due to our policy of not releasing patches on Friday, I couldn't fix it. Instead I kept getting called by our 3rd party monitoring company every time our app crashed, which really sucks, because I didn't write the bug in the first place -- I should really have given those guys the phone # of the guy that wrote it

With all that ranting done with, here's the code in question (slightly modified to remove a few things irrelevant to this puzzle). The code attempts to concatenate as many attributes as possible into a buffer, so that it can log the line to a file. It is perfectly all right to discard any data that cannot fit into the buffer, so if you have more data than the size of the buffer, you can simply discard the rest of it.
Code:
static void create_attr_line(attribute_t *attributes, int num_attribs, char *buf_str, int max_len)
{
        int         i;
        int         offset = 0;
        attribute_t *p_attr;

        for (i = 0; i < num_attribs; i++) {
            p_attr = attributes[i];
            offset += snprintf(buf_str + offset, max_len - offset, "%d:%s:%d:%d:%d:%s:%d:%d:%s;", 
                     p_attr->attr.business_id,
                     p_attr->attr.update_date,
                     p_attr->attr.event_type_id,
                     p_attr->attr.group_id,
                     p_attr->attr.subgroup_id,
                     p_attr->attr.attribute_name,
                     p_attr->score,
                     p_attr->count,
                     p_attr->attr.attribute_value
            );
        }
}

// called like this:
char attr_buf[4096];
create_ups_string(ctx->attributes, ctx->attribute_count, attr_buf, sizeof(attr_buf));

At first glance, the code appears to be doing some proper size checking to make sure that the size of the buffer cannot be exceeded. However there is a serious problem with it. For the purposes of this discussion, the compiler is assumed to be ANSI compliant (in my case, it is gcc running on Linux).
The puzzle is to point out where the buffer overflow is. Next question is to point out how to fix it.
BONUS QUESTION: Why will Microsoft Visual C++ produce different results with the same code?
__________________
Up the Irons
What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
"Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
Down with Sharon Osbourne

Puzzle of the Month solved by sizeablegrin, etienne141 and L7Sqr, superior C/C++ programmers of the month

Reply With Quote
  #2  
Old May 5th, 2008, 01:06 PM
sizablegrin's Avatar
sizablegrin sizablegrin is offline
Stubborn ol' L'User
Click here for more information.
 
Join Date: Jun 2005
Posts: 2,742 sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level) 
Time spent in forums: 1 Month 2 Days 4 h 43 m 5 sec
Reputation Power: 1193
I'm going to shoot from the hip, here. Some versions of the function returned -1 when the data was truncated, instead of the number of characters that would have been written if all had gone well. This could garfle up maxlen-offset.

Incidentally, what are you doing if a format error causes -1 to be returned?
__________________
The population in my hometown has been stable for 50 years. Every time a woman gets pregnant, a man leaves.

Reply With Quote
  #3  
Old May 5th, 2008, 02:12 PM
etienne141's Avatar
etienne141 etienne141 is offline
Paris est magique!
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Apr 2004
Location: France!
Posts: 346 etienne141 User rank is Sergeant Major (2000 - 5000 Reputation Level)etienne141 User rank is Sergeant Major (2000 - 5000 Reputation Level)etienne141 User rank is Sergeant Major (2000 - 5000 Reputation Level)etienne141 User rank is Sergeant Major (2000 - 5000 Reputation Level)etienne141 User rank is Sergeant Major (2000 - 5000 Reputation Level)etienne141 User rank is Sergeant Major (2000 - 5000 Reputation Level) 
Time spent in forums: 4 Days 23 h 41 m 43 sec
Reputation Power: 41
Send a message via ICQ to etienne141 Send a message via MSN to etienne141
Quote:
Originally Posted by sizablegrin
I'm going to shoot from the hip, here. Some versions of the function returned -1 when the data was truncated, instead of the number of characters that would have been written if all had gone well. This could garfle up maxlen-offset.


This would cause a buffer overflow only if offset goes lower than 0 (due to adding -1 one or several times) - well a buffer underflow
It would generally overwrite previous data (the last character).


As of glibc 2.1, snprintf returns the number of char that would have benn written if the buffer was large enough:

Quote:
Originally Posted by man snprintf
... if the output was truncated due to this limit then the return value is the number of characters (not including the trailing '\0') which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated. (See also below under NOTES.) If an output error is encountered, a negative value is returned.


This way, the offset continue to grow, even if the limit of the buffer is reached.

Oh, oh, wait! what happens if offset grows above max_len? (maxlen - offset) would be negative, no data will be printed in the buf... Nope, since size_t is generally typedef-ed as an unsigned int, it is cast as unsigned (a very high value!). All characters are likely to be copied. Bang.


The solution would be to test after snprintf() if the result is 0 <= res < max_len - offset.
If not, return.

Or, replace (max_len - offset) with (max_len - offset > 0 ? (max_len - offset) : 0)

With MSVC, snprintf() returns -1 if all characters could not be copied into the buffer. So, generally, it would work (see above).
__________________
UNIX shells are so cool!
etienne:~ > %blow
fg: %blow: no such job


There are 10 kind of people:
- those who know binary
- those who don't.

Reply With Quote
  #4  
Old May 5th, 2008, 02:54 PM
sizablegrin's Avatar
sizablegrin sizablegrin is offline
Stubborn ol' L'User
Click here for more information.
 
Join Date: Jun 2005
Posts: 2,742 sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level)sizablegrin User rank is General 3rd Grade (Above 100000 Reputation Level) 
Time spent in forums: 1 Month 2 Days 4 h 43 m 5 sec
Reputation Power: 1193
Okay, I'll shoot from the other hip. If the function is ANSI compiliant and the data is truncated, the return will be the number of characters that would have been written had size been sufficiently large. Suppose this is 4100. Offset goes beyond the 4096 length. Maxlen - offset is negative. However, that's an unsigned value, no negative values. The next operation will write beyond the buffer with an invalid length value.
Comments on this post
etienne141 agrees: you got it, cow-boy

Reply With Quote
  #5  
Old May 6th, 2008, 12:09 AM
Scorpions4ever's Avatar
Scorpions4ever Scorpions4ever is offline
Banned ;)
Dev Shed God 5th Plane (7000 - 7499 posts)
 
Join Date: Nov 2001
Location: Glendale, Los Angeles County, California, USA
Posts: 7,337 Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level)Scorpions4ever User rank is Brigadier General (60000 - 70000 Reputation Level) 
Time spent in forums: 4 Weeks 13 h 9 m 33 sec
Reputation Power: 674
Boy you guys are good. I also got a PM from L7Sqr along the same lines.
1. As you guys pointed out, once it goes -ve and gets converted to unsigned, all hell breaks loose.
2. For the record, the patch we did was to break out of the loop by detecting when offset > max_len. Like I mentioned above, it is ok for the last bit of data to be truncated for our purposes.
3. As you guys pointed out, _snprintf() for VC++ returns a negative value if the buffer is not big enough, whereas ANSI says that if the output was truncated then the return value is the number of characters (not including the trailing '\0') which would have been written to the final string if enough space had been available. This is why some people implement their own version of snprintf for portability (e.g. Apache Portable Library with apr_snprintf).

BTW a small issue that no one has pointed out yet -- some compilers/libraries (e.g. some old versions of glibc, libdb (from Sleepycat) and Solaris libc) implement snprintf() very badly. They would disregard the size parameter and simply call sprintf() !!! It didn't apply to our particular situation, but I thought I should throw out a warning to anyone reading this to watch out for those ancient libcs floating around.

Anyway, I hope you guys had fun solving this puzzle! I can tell you my weekend wasn't very pleasant though, what with answering all those calls due to this darn bug.

Last edited by Scorpions4ever : May 6th, 2008 at 12:32 AM.

Reply With Quote
Reply

Viewing: Dev Shed ForumsProgramming LanguagesC Programming > Puzzle of the Month 05-05-2008


Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

 Free IT White Papers!
 
Accelerating Trading Partner Performance
One in five. That's how many partner transactions have at least one error. That is an amazing statistic, particularly given the extraordinary leaps in innovation across the global supply chain during the past two decades. Download this white paper to learn more.

 
Competing on Analytics
This Tech Analysis is designed to help identify characteristics shared by analytics competitors, and includes information about 32 organizations that have made a commitment to quantitative, fact-based analysis.

 
Cost Effective Scaling with Virtualization and Coyote Point Systems
An overview of the industry trend toward virtualization, how server consolidation has increased the importance of application uptime and the steps being taken to integrate load balancing technology with virtualized servers.

 
Five Checkpoints to Implementing IP Telephony
Implementation planning for IP PBX software and IP telephony has become vital as businesses replace discontinued legacy PBX phone systems. This informative whitepaper outlines five "checkpoints" for any implementation plan that will help make IP communications a successful proposition.

 
Hosted Email Security: Staying Ahead of New Threats
In the last two years, email has become a fierce battleground between the nefarious forces of spam and malware, and the heroes of messaging protection. The spam volumes increased alarmingly every month, bringing clever new forms of phishing and virus propagation attacks.

 

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 





© 2003-2008 by Developer Shed. All rights reserved. DS Cluster 6 hosted by Hostway