Bug #8864

sprintf segfaults with too high precision

Added by Aaron Neyer almost 2 years ago. Updated over 1 year ago.

[ruby-core:57023]
Status:Closed
Priority:Normal
Assignee:-
ruby -v:- Backport:1.9.3: DONE, 2.0.0: DONE

Description

In any Ruby version (attempted with 1.8.7, 1.9.3, and 2.0.0), specifying a very large precision in sprintf can cause a segmentation fault.

The following code will cause the segmentation fault.

"%.99999f" % 10

The number to cause a segfault is dependent on the system. On my laptop, any number above 1100 would cause it, and on an EC2 micro instance, around 2500 was the limit.

vsnprintf.patch Magnifier (1.39 KB) Heesob Park, 09/12/2013 07:44 PM

Associated revisions

Revision 42918
Added by Nobuyoshi Nakada almost 2 years ago

vsnprintf.c: fix buffer overflow

  • vsnprintf.c (MAXEXP, MAXFRACT): calculate depending on constants in float.h.
  • vsnprintf.c (BSD_vfprintf): limit length for cvt() to get rid of buffer overflow. [Bug #8864]
  • vsnprintf.c (exponent): make expbuf size more precise.

Revision 42918
Added by Nobuyoshi Nakada almost 2 years ago

vsnprintf.c: fix buffer overflow

  • vsnprintf.c (MAXEXP, MAXFRACT): calculate depending on constants in float.h.
  • vsnprintf.c (BSD_vfprintf): limit length for cvt() to get rid of buffer overflow. [Bug #8864]
  • vsnprintf.c (exponent): make expbuf size more precise.

History

#1 Updated by Nobuyoshi Nakada almost 2 years ago

  • Project changed from CommonRuby to Ruby trunk

#2 Updated by Nobuyoshi Nakada almost 2 years ago

  • Tracker changed from Feature to Bug

#3 Updated by Utkarsh Kukreti almost 2 years ago

I'm trying to write a patch for this (my first contribution actually), and I'll really appreciate some help.

I've found the cause -- the buffer sent to cvt() function in vsnprintf.c is allocated on the stack with a fixed size of #define BUF (MAXEXP+MAXFRACT+1) here which on my machine is 1024 + 64 + 1 == 1089, and the data is written to it without any bounds check, which causes the segfault.

I can think of two possible solutions:

  1. Limit the precision a user can specify on a call to sprintf to MAXFRACT.
  2. malloc the actual required memory when it's greater than the defined constant BUF, and free it before returning from the function.

I think (2) is the best solution here.

What do you all think? Also, what functions should I use to allocate/free memory inside vsnprintf?

#4 Updated by Utkarsh Kukreti almost 2 years ago

Ok, (1) is not really an option, all other languages I looked at support arbitrary value of precision.

#5 Updated by Heesob Park almost 2 years ago

I made a patch for this issue.

#6 Updated by Nobuyoshi Nakada almost 2 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r42918.
Aaron, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


vsnprintf.c: fix buffer overflow

  • vsnprintf.c (MAXEXP, MAXFRACT): calculate depending on constants in float.h.
  • vsnprintf.c (BSD_vfprintf): limit length for cvt() to get rid of buffer overflow. [Bug #8864]
  • vsnprintf.c (exponent): make expbuf size more precise.

#7 Updated by Tomoyuki Chikanaga almost 2 years ago

  • Backport set to 1.9.3: REQUIRED, 2.0.0: REQUIRED
  • ruby -v set to -

#8 Updated by Tomoyuki Chikanaga almost 2 years ago

  • Backport changed from 1.9.3: REQUIRED, 2.0.0: REQUIRED to 1.9.3: REQUIRED, 2.0.0: DONE

Backported 42908 (for resolve conflict) and 42918 to ruby_2_0_0 at r42944.

#9 Updated by Usaku NAKAMURA over 1 year ago

  • Backport changed from 1.9.3: REQUIRED, 2.0.0: DONE to 1.9.3: DONE, 2.0.0: DONE

Backported to ruby_1_9_3 at r43488.

Also available in: Atom PDF