[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] Re: mpg321: Out-of-bounds Write
From:       Ren Kimura <rkx1209dev () gmail ! com>
Date:       2018-12-10 20:45:14
Message-ID: CALoRt7T8LLCCU5svHOuPfr9dZ+UV_B4WaQZruByMnkjkcLDypg () mail ! gmail ! com
[Download RAW message or body]

2018年12月10日(月) 12:44 Matthew Fernandez <matthew.fernandez@gmail.com>:
> 
> 
> 
> On Sun, 9 Dec 2018 at 15:11, Ren Kimura <rkx1209dev@gmail.com> wrote:
> > 
> > > Did you report this one upstream? In trying to understand this, it looks to me like the \
> > > problem isn't that mpg321 fails to check the bitrate is positive, but rather that there's \
> > > an unchecked malloc elsewhere. 
> > > The point where the OOB write occurs (mad.c:285) looks like the following:
> > > 
> > > 282     /* update cached table of frames & times */
> > > 283     if (current_frame <= playbuf->num_frames) /* we only allocate enough for our \
> > > estimate. */ 284     {
> > > 285         playbuf->frames[current_frame] = playbuf->frames[current_frame-1] + \
> > > (header->bitrate / 8 / 1000) 286             * mad_timer_count(header->duration, \
> > > MAD_UNITS_MILLISECONDS); 287         playbuf->times[current_frame] = current_time;
> > > 
> > > At this point, header->bitrate is 0 and playbuf->num_frames is the correct limit to check \
> > > against for this buffer. The problem seems to stem from the point at which \
> > > playbuf->frames was allocated (mpg321.c:990):
> > 
> > > 985             if ((options.maxframes != -1) && (options.maxframes <= \
> > > playbuf.num_frames)) 986             {
> > > 987                 playbuf.max_frames = options.maxframes;
> > > 988             }
> > > 989
> > > 990             playbuf.frames = malloc((playbuf.num_frames + 1) * sizeof(void*));
> > > 991             playbuf.times = malloc((playbuf.num_frames + 1) * sizeof(mad_timer_t));
> > > 992 #ifdef __uClinux__
> > > 993       if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_PRIVATE, fd, 0)) == \
> > > MAP_FAILED) 994 #else
> > > 995       if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_SHARED, fd, 0)) == \
> > > MAP_FAILED) 996 #endif
> > > 
> > > At this point, playbuf.num_frames is whatever the your platform happens to yield when ∞ \
> > > is cast to a long (undefined behavior in C). AFAICT there is no check that malloc \
> > > succeeded before the code later writes to the frames array (the same applies to \
> > > playbuf.times). Poking around a bit more, this (unchecked malloc) seems common in the \
> > > code.
> > 
> > checking malloc status is not enough, because playbuf.num_frames can
> > be very large value, in my environment Ubuntu 18.04, gcc 7.03,
> > it becomes 0x8000000000000000.
> > 990             playbuf.frames = malloc((playbuf.num_frames + 1) *
> > sizeof(void*));
> > So at this point it try to calculate (0x8000000000000000 + 1) * 8 =
> > 0x8 (INTEGER OVERFLOW).
> > As a result malloc succeed but it only allocate 0x8 byte buffer, lead
> > OOB write at following points.
> > 
> > 283     if (current_frame <= playbuf->num_frames) /* we only allocate
> > enough for our estimate. */
> > 285         playbuf->frames[current_frame] =
> > playbuf->frames[current_frame-1] + (header->bitrate / 8 / 1000)
> > 286             * mad_timer_count(header->duration, MAD_UNITS_MILLISECONDS);
> > 287         playbuf->times[current_frame] = current_time;
> > 
> > The value of playbuf.num_frames may depend on platform because it's
> > calculated from INF value. (undefined behavior)
> > I only tried to Ubuntu package of mpg321 (may be compiled by gcc?). At
> > least on ubuntu, OOB write always happen due to above reason.
> > 
> > Ren Kimura
> 
> Did you report this upstream?

Yes. I've reported it to Ubuntu security team.
But there is no response yet.

Ren Kimura


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic