Langsung ke konten utama

Drawing Exterior The Box: Precision Issues Inwards Graphic Libraries

By Mark Brand as well as Ivan Fratric, Google

In this spider web log post, nosotros are going to write nearly a seldom seen vulnerability shape that typically affects graphic libraries (though it tin also occur inwards other types of software). The root elbow grease of such issues is using limited precision arithmetics inwards cases where a precision fault would invalidate security assumptions made yesteryear the application.

While nosotros could also telephone telephone other classes of bugs precision issues, namely integer overflows, the major divergence is: amongst integer overflows, nosotros are dealing amongst arithmetics operations where the magnitude of the final result is too large to endure accurately represented inwards the given precision. With the issues described inwards this spider web log post, nosotros are dealing amongst arithmetics operations where the magnitude of the final result or a constituent of the final result is too small to endure accurately represented inwards the given precision.

These issues tin occur when using floating-point arithmetics inwards operations where the final result is security-sensitive, but, as we’ll demonstrate later, tin also occur inwards integer arithmetics inwards some cases.

Let’s expression at a little example:

 float a = 100000000;
 float b = 1;
 float c = a + b;

If nosotros were making the computation amongst arbitrary precision, the final result would endure 100000001. However, since float typically solely allows for 24 bits of precision, the final result is genuinely going to endure 100000000. If an application makes the ordinarily reasonable supposition that a > 0 as well as b > 0 implies that a + b > a, as well as so this could Pb to issues.

In the instance above, the divergence betwixt a as well as b is so pregnant that b completely vanishes inwards the final result of the calculation, but precision errors also move on if the divergence is smaller, for example

 float a = 1000;
 float b = 1.1111111;
 float c = a + b;

The final result of the to a higher house computation is going to endure 1001.111084 as well as non 1001.1111111 which would endure the accurate result. Here, solely a constituent of b is lost, but fifty-fifty such results tin sometimes withdraw hold interesting consequences.

While nosotros used the float type inwards the to a higher house examples, as well as inwards these particular examples using double would final result inwards to a greater extent than accurate computation, similar precision errors tin move on amongst double as well.

In the balance of this spider web log post, nosotros are going to exhibit several examples of precision issues amongst security impact. These issues were independently explored yesteryear 2 members: Mark Brand, who looked at SwiftShader, a software OpenGL implementation used inwards Chrome, as well as Ivan Fratric, who looked at the Skia graphics library, used inwards Chrome as well as Firefox.

SwiftShader

SwiftShader is “a high-performance CPU-based implementation of the OpenGL ES as well as Direct3D ix graphics APIs”. It’s used inwards Chrome on all platforms as a fallback rendering pick to piece of work around limitations inwards graphics hardware or drivers, allowing universal utilization of WebGL as well as other advanced javascript rendering APIs on a far wider attain of devices.

The code inwards SwiftShader needs to handgrip emulating a broad attain of operations that would ordinarily endure performed yesteryear the GPU. One functioning that nosotros commonly recollect of as essentially “free” on a GPU is upscaling, or drawing from a modest source texture to a larger area, for instance on the screen. This requires computing retentiveness indexes using non-integer values, which is where the vulnerability occurs.

As noted inwards the master copy põrnikas report, the code that we’ll expression at hither is non quite the code which is genuinely run inwards do - SwiftShader uses an LLVM-based JIT engine to optimize performance-critical code at runtime, but that code is to a greater extent than hard to empathize than their fallback implementation, as well as both comprise the same bug, so we’ll beak over the fallback code. This code is the copy-loop used to re-create pixels from i surface to some other during rendering:

 source->lockInternal((int)sRect.x0, (int)sRect.y0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
 dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);

 float w = sRect.width() / dRect.width();
 float h = sRect.height() / dRect.height();

 const float xStart = sRect.x0 + 0.5f * w;
 float y = sRect.y0 + 0.5f * h;
 float x = xStart;

 for(int j = dRect.y0; j < dRect.y1; j++)
 {
   x = xStart;

   for(int i = dRect.x0; i < dRect.x1; i++)
   {
     // FIXME: Support RGBA mask
     dest->copyInternal(source, i, j, x, y, options.filter);

     x += w;
   }

   y += h;
 }

 source->unlockInternal();
 dest->unlockInternal();
}

So - what highlights this code as problematic? We know prior to entering this role that all the bounds-checking has already been performed, as well as that whatsoever telephone telephone to copyInternal amongst (i, j) inwards dRect as well as (x, y) inwards sRect volition endure safe.

The examples inwards the introduction to a higher house exhibit cases where the resulting precision fault agency that a rounding-down occurs - inwards this instance that wouldn’t endure plenty to make an interesting security bug. Can nosotros elbow grease floating-point imprecision to final result inwards a larger-than-correct value, leading to (x, y) values that are larger than expected?

If nosotros expression at the code, the intention of the developers is to compute the following:

 for(int j = dRect.y0; j < dRect.y1; j++)
 {
   for(int i = dRect.x0; i < dRect.x1; i++)
   {
     x = xStart + (i * w);
     Y = yStart + (j * h);
     dest->copyInternal(source, i, j, x, y, options.filter);
   }
 }

If this approach had been used instead, we’d all the same withdraw hold precision errors - but without the iterative calculation, there’d endure no propagation of the error, as well as nosotros could await the eventual magnitude of the precision fault to endure stable, as well as inwards direct proportion to the size of the operands. With the iterative calculation as performed inwards the code, the errors start to propagate/snowball into a larger as well as larger error.

There are ways to gauge the maximum fault inwards floating indicate calculations; as well as if you lot really, genuinely demand to avoid having extra bounds checks, using this sort of approach as well as making certain that you lot withdraw hold conservative security margins around those maximum errors powerfulness endure a complicated as well as error-prone way to solve this issue. It’s non a dandy approach to identifying the pathological values that nosotros desire hither to demonstrate a vulnerability; so instead we’ll accept a brute-force approach.

Instinctively, we’re fairly certain that the multiplicative implementation volition endure roughly correct, as well as that the implementation amongst iterative add-on volition endure much less correct. Given that the infinite of possible inputs is modest (Chrome disallows textures amongst width or peak greater than 8192), nosotros tin only run a creature forcefulness over all ratios of source width to destination width, comparison the 2 algorithms, as well as seeing where the results are most different. (Note that SwiftShader also limits us to fifty-fifty numbers). This leads us to the values of 5828, 8132; as well as if nosotros compare the computations inwards this instance (left side is the iterative addition, right side is the multiplication):

0:    1.075012 1.075012
1:    1.791687 1.791687
...
1000: 717.749878 717.749878   Up to hither (at the precision shown) the values are all the same identical
1001: 718.466553 718.466553
...
2046: 1467.391724 1467.391724 At this point, the kickoff pregnant errors start to occur, but note
2047: 1468.108398 1468.108521 that the "incorrect" final result is smaller than the to a greater extent than precise one.
...
2856: 2047.898315 2047.898438
2857: 2048.614990 2048.614990 Here our 2 computations coincide again, briefly, as well as from hither onwards
2858: 2049.331787 2049.331787 the precision errors consistently favour a larger final result than the more
2859: 2050.048584 2050.048340 precise calculation.
...
8129: 5827.567871 5826.924805
8130: 5828.284668 5827.641602
8131: 5829.001465 5828.358398 The terminal index is at nowadays sufficiently dissimilar that int conversion results inwards an oob index.

(Note also that at that spot volition also endure fault inwards the “safe” calculation; it’s only that the lack of fault propagation agency that that fault volition rest straight proportional to the size of the input error, which nosotros await to endure “small.”)

We tin indeed run into that, the multiplicative algorithm would rest within bounds; but that the iterative algorithm tin homecoming an index that is exterior the bounds of the input texture!

As a result, nosotros read an entire row of pixels yesteryear the destination of our texture resources allotment - as well as this tin endure easily leaked dorsum to javascript using WebGL. Stay tuned for an upcoming spider web log shipping inwards which we’ll utilization this vulnerability together amongst some other unrelated number inwards SwiftShader to accept command of the GPU procedure from javascript.

Skia

Skia is a graphics library used, amid other places, inwards Chrome, Firefox as well as Android. In the spider web browsers it is used for instance when drawing to a sail HTML chemical component using CanvasRenderingContext2D or when drawing SVG images. Skia is also used when drawing diverse other HTML elements, but sail chemical component as well as SVG images are to a greater extent than interesting from the security perspective because they enable to a greater extent than direct command over the objects existence drawn yesteryear the graphic library.

The most complex type of object (and therefore, most interesting from the security perspective) that Skia tin pull is a path. Influenza A virus subtype H5N1 path is an object that consists of elements such as lines, but also to a greater extent than complex curves, inwards particular quadratic or cubic splines.

Due to the way software drawing algorithms piece of work inwards Skia, the precision issues are real much possible as well as quite impactful when they happen, typically leading to out-of-bounds writes.

To empathize why these issues tin happen, let’s assume you lot withdraw hold an icon inwards retentiveness (represented as a buffer amongst size = width x height x color size). Normally, when drawing a pixel amongst coordinates (x, y) as well as color c, you lot would desire to brand certain that the pixel genuinely falls within the infinite of the image, specifically that 0 <= x < width as well as 0 <= y < height. Failing to banking concern check this could final result inwards attempting to write the pixel exterior the bounds of the allocated buffer. In reckoner graphics, making certain that solely the objects inwards the icon part are existence drawn is called clipping.

So, where is the problem? Making a clip banking concern check for every pixel is expensive inwards damage of CPU cycles as well as Skia prides itself on speed. So, instead of making a clip banking concern check for every pixel, what Skia does is, it kickoff makes the clip banking concern check on an entire object (e.g. line, path or whatsoever other type of object existence drawn). Depending on the clip check, at that spot are 3 possible outcomes:

  1. The object is completely exterior of the drawing area: The drawing role doesn’t pull anything as well as returns immediately.

  1. The object is partially within the drawing area: The drawing role proceeds amongst per-pixel clip enabled (usually yesteryear relying on SkRectClipBlitter).

  1. The entire object is inwards the drawing area: The drawing role draws straight into the buffer without performing per-pixel clip checks.

The problematic scenario is c) where the clip banking concern check is performed solely per-object as well as the to a greater extent than precise, per-pixel checks are disabled. This means, if at that spot is a precision number somewhere betwixt the per-object clip banking concern check as well as the drawing of pixels as well as if the precision number causes the pixel coordinates to move exterior of the drawing area, this could final result inwards a security vulnerability.

We tin run into per-object clip checks leading to dropping per-pixel checks inwards several places, for example:

  • In hair_path (function for drawing a path without filling), clip is initially laid to naught (which disables clip checks). The clip is solely laid if the bounds of the path, rounded upwards as well as extended yesteryear 1 or 2 depending on the drawing options don’t gibe inwards the drawing area. Extending the path bounds yesteryear 1 seems similar a pretty large security margin, but it is genuinely the to the lowest degree possible security value because drawing objects amongst antialiasing on volition sometimes final result inwards drawing to nearby pixels.

  • In SkScan::FillPath (function for filling a path amongst antialiasing turned off), the bounds of the path are kickoff extended yesteryear kConservativeRoundBias as well as rounded to obtain the “conservative” path bounds. Influenza A virus subtype H5N1 SkScanClipper object is as well as so created for the electrical current path. As nosotros tin run into inwards the definition of SkScanClipper, it volition solely utilization SkRectClipBlitter if the x coordinates of the path bounds are exterior the drawing expanse or if irPreClipped is truthful (which solely happens when path coordinates are real large).

Similar patterns tin endure seen inwards other drawing functions.

Before nosotros accept a closer expression at the issues, it is useful to chop-chop move over diverse number formats used yesteryear Skia:

  • SkScalar is a 32-bit floating indicate number

  • SkFDot6 is defined as an integer, but it is genuinely a fixed-point number amongst 26 bits to the left as well as half dozen bits to the right of the decimal point. For example, SkFDot6 value of 0x00000001 represents the number 1/64.

  • SkFixed is also a fixed-point number, this fourth dimension amongst sixteen bits to the left as well as sixteen bits to the right of the decimal point. For example, SkFixed value of 0x00000001 represents 1/(2**16)

Precision fault amongst integer to float conversion

We discovered the initial employment when doing DOM fuzzing against Firefox terminal year. This issue where Skia wrote out-of-bounds caught our oculus so nosotros investigated further. It turned out the root elbow grease was a discrepancy inwards the way Skia converted floating indicate to ints inwards several places. When making the per-path clip check, the lower coordinates (left as well as top of the bounding box) were rounded using this function:

static inline int round_down_to_int(SkScalar x) {
   double xx = x;
   xx -= 0.5;
   return (int)ceil(xx);
}

Looking at the code you lot run into that it volition homecoming a number greater or equal to null (which is necessary for passing the path-level clip check) for numbers that are strictly larger than -0.5. However, inwards some other constituent of the code, specifically SkEdge::setLine if SK_RASTERIZE_EVEN_ROUNDING is defined (which is the instance inwards Firefox), floats are rounded to integers differently, using the next function:

inline SkFDot6 SkScalarRoundToFDot6(SkScalar x, int shift = 0)
{
   union {
       double fDouble;
       int32_t fBits[2];
   } tmp;
   int fractionalBits = half dozen + shift;
   double magic = (1LL << (52 - (fractionalBits))) * 1.5;

   tmp.fDouble = SkScalarToDouble(x) + magic;
#ifdef SK_CPU_BENDIAN
   return tmp.fBits[1];
#else
   return tmp.fBits[0];
#endif
}

Now let’s accept a expression at what these 2 functions homecoming for a number -0.499. For this number, round_down_to_int returns 0 (which ever passes the clipping check) as well as SkScalarRoundToFDot6 returns -32 which corresponds to -0.5, so nosotros genuinely destination upwards amongst a number that is smaller than the i nosotros started with.

That’s non the solely problem, though, because there’s some other house where a precision fault occurs inwards SkEdge::setLine.

Precision fault when multiplying fractions

SkEdge::setLine calls SkFixedMul which is defined as:

static inline SkFixed(SkFixed a, SkFixed b) {
   return (SkFixed)((int64_t)a * b >> 16);
}

This role is for multiplying 2 SkFixed numbers. An number comes upwards when using this role to multiply negative numbers. Let’s expression at a modest example. Let’s assume a = -1/(2**16) as well as b = 1/(2**16). If nosotros multiply these 2 numbers on paper, the final result is -1/(2**32). However, due to the way SkFixedMul works, specifically because the right shift is used to convert the final result dorsum to SkFixed format, the final result nosotros genuinely destination upwards amongst is 0xFFFFFFFF which is SkFixed for  -1/(2**16). Thus, nosotros destination upwards amongst a final result amongst a magnitude much larger than expected.

As the final result of this multiplication is used yesteryear SkEdge::setLine to adapt the x coordinate of the initial employment indicate here, nosotros tin utilization the number inwards SkFixedMul to elbow grease an additional fault upwards to 1/64 of a pixel to move exterior of the drawing expanse bounds.

By combining the previous 2 issues, it was possible to larn the x coordinate of a employment sufficiently modest (smaller than -0.5), so that, when a fractional representation was rounded to an integer here, Skia attempted to pull at coordinates amongst x = -1, which is clearly exterior the icon bounds. This as well as so led to an out-of-bounds write as tin endure seen inwards the original põrnikas report. This põrnikas could endure exploited inwards Firefox yesteryear drawing an SVG icon amongst coordinates as described inwards the previous section.

Floating indicate precision fault when converting splines to employment segments

When drawing paths, Skia is going to convert all non-linear curves (conic shapes, quadratic as well as cubic splines) to employment segments. Perhaps unsurprisingly, these conversions endure from precision errors.

The conversion of splines into employment segments move on inwards several places, but the most susceptible to floating-point precision errors are hair_quad (used for drawing quadratic curves) as well as hair_cubic (used for drawing cubic curves). Both of these functions are called from hair_path, which nosotros already mentioned above. Because (unsurprisingly), larger precision errors occur when dealing amongst cubic splines, we’ll solely consider the cubic instance here.

When approximating the spline, kickoff the cubic coefficients are computed inwards SkCubicCoeff. The most interesting constituent is:

fA = P3 + 3 * (P1 - P2) - P0;
fB = 3 * (P2 - times_2(P1) + P0);
fC = 3 * (P1 - P0);
fD = P0;

Where P1, P2 as well as P3 are input points as well as fA, fB, fC as well as fD are output coefficients. The employment segment points are as well as so computed inwards hair_cubic using the next code

const Sk2s dt(SK_Scalar1 / lines);
Sk2s t(0);

...

Sk2s Influenza A virus subtype H5N1 = coeff.fA;
Sk2s B = coeff.fB;
Sk2s C = coeff.fC;
Sk2s D = coeff.fD;
for (int i = 1; i < lines; ++i) {
   t = t + dt;
   Sk2s p = ((A * t + B) * t + C) * t + D;
   p.store(&tmp[i]);
}

Where p is the output indicate as well as lines is the number of employment segments nosotros are using to approximate the curve. Depending on the length of the spline, a cubic spline tin endure approximated amongst upwards to 512 lines.

It is obvious that the arithmetics hither is non going to endure precise. As identical computations move on for x as well as y coordinates, let’s only consider the x coordinate inwards the ease of the post.

Let’s assume the width of the drawing expanse is G pixels. Because hair_path is used for drawing path amongst antialiasing turned on, it needs to brand certain that all points of the path are betwixt 1 as well as 999, which is done inwards the initial, path-level clip check. Let’s consider the next coordinates that all overstep this check:

p0 = 1.501923
p1 = 998.468811
p2 = 998.998779
p3 = 999.000000

For these points, the coefficients are as follows

a = 995.908203
b = -2989.310547
c = 2990.900879
d = 1.501923

If you lot do the same computation inwards larger precision, you’re going to notice that the numbers hither aren’t quite correct. Now let’s run into what happens if nosotros approximate the spline amongst 512 employment segments. This results inwards 513 x coordinates:

0: 1.501923
1: 7.332130
2: 13.139574
3: 18.924301
4: 24.686356
5: 30.425781
...
500: 998.986389
501: 998.989563
502: 998.992126
503: 998.994141
504: 998.995972
505: 998.997314
506: 998.998291
507: 998.999084
508: 998.999695
509: 998.999878
510: 999.000000
511: 999.000244
512: 999.000000

We tin run into that the x coordinate keeps growing as well as at indicate 511 clearly goes exterior of the “safe” expanse as well as grows larger than 999.

As it happens, this isn’t sufficient to trigger an out-of-bounds write, because, due to how drawing antialiased lines works inwards Skia, nosotros demand to move at to the lowest degree 1/64 of a pixel exterior of the clip expanse for it to move a security issue. However, an interesting matter nearly the precision errors inwards this instance is that the larger the drawing area, the larger the fault that tin happen.

So let’s instead consider a drawing expanse of 32767 pixels (maximum sail size inwards Chrome). The initial clipping banking concern check as well as so checks that all path points are inwards the interval [1, 32766]. Now let’s consider the next points:

p0 = 1.7490234375
p1 = 32765.9902343750
p2 = 32766.000000
p3 = 32766.000000

The corresponding coefficients

a = 32764.222656
b = -98292.687500
c = 98292.726562
d = 1.749023

And the corresponding employment approximation

0: 1.74902343
1: 193.352295
2: 384.207123
3: 574.314941
4: 763.677246
5: 952.295532
505: 32765.925781
506: 32765.957031
507: 32765.976562
508: 32765.992188
509: 32766.003906
510: 32766.003906
511: 32766.015625
512: 32766.000000

You tin run into that nosotros went out-of-bounds significantly to a greater extent than at index 511.

Fortunately for Skia as well as unfortunately for aspiring attackers, this põrnikas can’t endure used to trigger retentiveness corruption, at to the lowest degree non inwards the up-to-date version of skia. The argue is SkDrawTiler. Whenever Skia draws using SkBitmapDevice (as opposed to using a GPU device) as well as the drawing expanse is larger than 8191 pixels inwards whatsoever dimension, instead of drawing the whole icon at once, Skia is going to dissever it into tiles of size (at most) 8191x8191 pixels. This change was made inwards March, non for security reasons, but to endure able to back upwards larger drawing surfaces. However, it all the same effectively prevented us from exploiting this number as well as volition also forestall exploiting other cases where a surface larger than 8191 is required to attain the precision fault of a sufficient magnitude.

Still, this põrnikas was exploitable earlier March as well as nosotros recollect it nicely demonstrates the concept of precision errors.

Integer precision fault when converting splines to employment segments

There is some other house where splines are approximated as employment segments when drawing (in this case: filling) paths that was also affected yesteryear a precision error, inwards this instance an exploitable one. Interestingly, hither the precision fault wasn’t inwards floating-point but rather inwards fixed-point arithmetic.

The fault happens inwards SkQuadraticEdge::setQuadraticWithoutUpdate as well as SkCubicEdge::setCubicWithoutUpdate. For simplicity, nosotros are i time to a greater extent than going to concentrate only on the cubic spline version and, again, solely on the x coordinate.

In SkCubicEdge::setCubicWithoutUpdate, the bend coordinates are kickoff converted to SkFDot6 type (integer amongst half dozen bits used for fraction). After that, parameters corresponding to the first, 2nd as well as tertiary derivative of the bend at the initial indicate are going to endure computed:

SkFixed B = SkFDot6UpShift(3 * (x1 - x0), upShift);
SkFixed C = SkFDot6UpShift(3 * (x0 - x1 - x1 + x2), upShift);
SkFixed D = SkFDot6UpShift(x3 + 3 * (x1 - x2) - x0, upShift);

fCx     = SkFDot6ToFixed(x0);
fCDx    = B + (C >> shift) + (D >> 2*shift);    // biased yesteryear shift
fCDDx   = 2*C + (3*D >> (shift - 1));           // biased yesteryear 2*shift
fCDDDx  = 3*D >> (shift - 1);                   // biased yesteryear 2*shift

Where x0, x1, x2 as well as x3 are x coordinates of the iv points that define the cubic spline as well as shift as well as upShift depend on the length of the bend (this corresponds to the number of linear segments the bend is going to endure approximated in). For simplicity, nosotros tin assume shift = upShift = half dozen (maximum possible values).

Now let’s run into what happens for some real unproblematic input values:

x0 = -30
x1 = -31
x2 = -31
x3 = -31

Note that x0, x1, x2 as well as x3 are of the type SkFDot6 so value -30 corresponds to -0.46875 as well as -31 to -0.484375. These are unopen to -0.5 but non quite as well as are thus perfectly security when rounded. Now let’s examine the values of the computed parameters:

B = -192
C = 192
D = -64

fCx = -30720
fCDx = -190
fCDDx = 378
fCDDDx = -6

Do you lot run into where the number is? Hint: it’s inwards the formula for fCDx.

When computing fCDx (first derivation of a curve), the value of D needs is right-shifted yesteryear 12. However, D is besides modest to do that precisely, as well as since D is negative, the right shift

D >> 2*shift

Is going to final result inwards -1, which is larger inwards magnitude than the intended result. (Since D is of type SkFixed its actual value is -0.0009765625 as well as the shift, when interpreted as partition yesteryear 4096, would final result inwards -2.384185e-07). Because of this, the whole fCDx ends upwards as a larger negative value than it should (-190 vs. -189.015).

Afterwards, the value of fCDx gets used when calculating the x value of employment segments. This happens inwards SkCubicEdge::updateCubic on this line:

newx    = oldx + (fCDx >> dshift);

The x values, when approximating the spline amongst 64 employment segments (maximum for this algorithm), are going to endure (expressed as index, integer SkFixed value as well as the corresponding floating indicate value):

index raw      interpretation
0:    -30720   -0.46875
1:    -30768   -0.469482
2:    -30815   -0.470200
3:    -30860   -0.470886
4:    -30904   -0.471558
5:    -30947   -0.472214
...
31:   -31683   -0.483444
32:   -31700   -0.483704
33:   -31716   -0.483948
34:   -31732   -0.484192
35:   -31747   -0.484421
36:   -31762   -0.484650
37:   -31776   -0.484863
38:   -31790   -0.485077
...
60:   -32005   -0.488358
61:   -32013   -0.488480
62:   -32021   -0.488602
63:   -32029   -0.488724
64:   -32037   -0.488846

You tin run into that for the 35th point, the x value (-0.484421) ends upwards existence smaller than the smallest input indicate (-0.484375) as well as the tendency continues for the afterwards points. This value would all the same larn rounded to 0 though, but at that spot is some other problem.

The x values computed inwards SkCubicEdge::updateCubic are passed to SkEdge::updateLine, where they are converted from SkFixed type to SkFDot6 on the following lines:

x0 >>= 10;
x1 >>= 10;

Another right shift! And when, for example, SkFixed value -31747 gets shifted nosotros destination upwards amongst SkFDot6 value of -32 which represents -0.5.

At this indicate nosotros tin utilization the same fob described to a higher house inwards the “Precision fault when multiplying fractions” department to move smaller than -0.5 as well as interruption out of the icon bounds. In other words, nosotros tin brand Skia pull to x = -1 when drawing a path.

But, what tin nosotros do amongst it?

In general, given that Skia allocates icon pixels as a unmarried resources allotment that is organized row yesteryear row (as most other software would allocate bitmaps), at that spot are several cases of what tin move on amongst precision issues. If nosotros assume an width x height icon as well as that nosotros are solely able to move i pixel out of bounds:

  1. Drawing to y = -1 or y = peak similar a shot leads to heap out-of-bounds write
  2. Drawing to x = -1 amongst y = 0 similar a shot leads to a heap underflow of 1 pixel
  3. Drawing to x = width amongst y = peak - 1 similar a shot leads to heap overflow of 1 pixel
  4. Drawing to x = -1 amongst y > 0 leads to a pixel “spilling” to the previous icon row
  5. Drawing to x = peak amongst y < height-1 leads to a pixel “spilling” to the side yesteryear side icon row

What nosotros withdraw hold hither is scenario d) - unfortunately nosotros can’t pull to x = 1 amongst y = 0 because the precision fault needs to accumulate over the growing values of y.

Let’s accept a expression at the next instance SVG image:

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<style>
body {
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
margin-left: 0px
}
</style>
<path d="M -0.46875 -0.484375 C -0.484375 -0.484375, -0.484375 -0.484375, -0.484375 100 L 1 100 L 1 -0.484375" fill="red" shape-rendering="crispEdges" />
</svg>

If nosotros homecoming this inwards an unpatched version of Firefox what nosotros run into is shown inwards the next image. Notice how the SVG solely contains coordinates on the left side of the screen, but some of the ruby-red pixels larn drawn on the right. This is because, due to the way images are allocated, drawing to x = -1 as well as y = row is equal to drawing to x = width - 1 as well as y = row - 1.


Opening an SVG icon that triggers a Skia precision number inwards Firefox. If you lot expression closely you’ll notice some ruby-red pixels on the right side of the image. How did those larn there? :)

Note that nosotros used Mozilla Firefox as well as non Google Chrome because, due to SVG drawing internals (specifically: Skia seems to pull the entire icon at once, piece Chrome uses additional tiling) it is easier to demonstrate the number inwards Firefox. However, both Chrome as well as Firefox were as affected yesteryear this issue.

But, other than drawing a funny image, is at that spot existent security impact to this issue? Here, SkARGB32_Shader_Blitter comes to the rescue (SkARGB32_Shader_Blitter is used whenever shader effects are applied to a color inwards Skia). What is specific nearly SkARGB32_Shader_Blitter is that it allocates a temporary buffer of the same size as a unmarried icon row. When SkARGB32_Shader_Blitter::blitH is used to pull an entire icon row, if nosotros tin move far pull from x = -1 to x = width - 1 (alternately from x = 0 to x = width), it volition demand to write width + 1 pixels into a buffer that tin solely concur width pixels, leading to a buffer overflow as tin endure seen inwards the ASan log inwards the bug report.

Note how the PoCs for Chrome as well as Firefox comprise SVG images amongst a linearGradient chemical component - the linear slope is used specifically to pick out SkARGB32_Shader_Blitter instead of drawing pixels to the icon directly, which would solely final result inwards pixels spilling to the previous row.

Another specific of this number is that it tin solely endure reached when drawing (more specifically: filling) paths amongst antialiasing turned off. As it is non currently possible to pull paths to a HTML sail elements amongst antialiasing off (there is an imageSmoothingEnabled holding but it solely applies to drawing images, non paths), an SVG icon amongst shape-rendering="crispEdges" must endure used to trigger the issue.

All precision issues nosotros reported inwards Skia were fixed by increasing kConservativeRoundBias. While the electrical current bias value is large plenty to encompass the maximum precision errors nosotros know about, nosotros should non dismiss the possibility of other places where precision issues tin occur.

Conclusion

While precision issues, such as described inwards this spider web log post, won’t endure acquaint inwards most software products, where they are acquaint they tin withdraw hold quite serious consequences. To forestall them from occurring:

  • Don’t utilization floating-point arithmetics inwards cases where the final result is security-sensitive. If you lot absolutely withdraw hold to, as well as so you lot demand to brand certain that the maximum possible precision fault cannot endure larger than some security margin. Potentially, interval arithmetic could endure used to create upwards one's withdraw heed the maximum precision fault inwards some cases. Alternately, perform security checks on the final result rather than input.

  • With integer arithmetic, endure wary of whatsoever operations that tin trim down the precision of the result, such as divisions as well as right shifts.

When it comes to finding such issues, unfortunately, at that spot doesn’t seem to endure a dandy way to do it. When nosotros started looking at Skia, initially nosotros wanted to essay using symbolic execution on the drawing algorithms to honor input values that would Pb to drawing out-of-bounds, as, on the surface, it seemed this is a employment symbolic execution would endure good suited for. However, inwards practice, at that spot were besides many issues: most tools don’t back upwards floating indicate symbolic variables and, fifty-fifty when running against only the integer parts of the simplest employment drawing algorithm, nosotros were unsuccessful inwards completing the run inwards a reasonable fourth dimension (we were using KLEE amongst STP as well as Z3 backends).

In the end, what nosotros ended upwards doing was a combination of the to a greater extent than old-school methods: manual source review, fuzzing (especially amongst values unopen to icon boundaries) and, inwards some cases, when nosotros already identified potentially problematic areas of code, fifty-fifty bruteforcing the attain of all possible values.

Do you lot know of other instances where precision errors resulted inwards security issues? Let us know nearly them inwards the comments.

Komentar

Postingan populer dari blog ini

Exception-Oriented Exploitation On Ios

Posted past times Ian Beer, This postal service covers the regain in addition to exploitation of CVE-2017-2370 , a heap buffer overflow inwards the mach_voucher_extract_attr_recipe_trap mach trap. It covers the bug, the evolution of an exploitation technique which involves repeatedly in addition to deliberately crashing in addition to how to build alive meat introspection features using onetime meat exploits. It’s a trap! Alongside a large number of BSD syscalls (like ioctl, mmap, execve in addition to so on) XNU also has a pocket-sized number of extra syscalls supporting the MACH side of the meat called mach traps. Mach trap syscall numbers start at 0x1000000. Here’s a snippet from the syscall_sw.c file where the trap tabular array is defined: /* 12 */ MACH_TRAP(_kernelrpc_mach_vm_deallocate_trap, 3, 5, munge_wll), /* xiii */ MACH_TRAP(kern_invalid, 0, 0, NULL), /* xiv */ MACH_TRAP(_kernelrpc_mach_vm_protect_trap, 5, 7, munge_wllww), Most of the mach traps a

Lifting The (Hyper) Visor: Bypassing Samsung’S Real-Time Total Protection

Posted yesteryear Gal Beniamini, Traditionally, the operating system’s total is the concluding security boundary standing betwixt an assaulter together with total command over a target system. As such, additional aid must hold upwards taken inwards lodge to ensure the integrity of the kernel. First, when a organization boots, the integrity of its primal components, including that of the operating system’s kernel, must hold upwards verified. This is achieved on Android yesteryear the verified kicking chain . However, only booting an authenticated total is insufficient—what most maintaining the integrity of the total spell the organization is executing? Imagine a scenario where an assaulter is able to abide by together with exploit a vulnerability inwards the operating system’s kernel. Using such a vulnerability, the assaulter may endeavor to subvert the integrity of the total itself, either yesteryear modifying the contents of its code, or yesteryear introducing novel attacker-co

Chrome Bone Exploit: 1 Byte Overflow As Well As Symlinks

The next article is an invitee weblog post from an external researcher (i.e. the writer is non a or Google researcher). This post is most a Chrome OS exploit I reported to Chrome VRP inward September. The folks were squeamish to allow me do a invitee post most it, therefore hither goes. The study includes a detailed writeup , therefore this post volition have got less detail. 1 byte overflow inward a DNS library In Apr I constitute a TCP port listening on localhost inward Chrome OS. It was an HTTP proxy built into shill, the Chrome OS network manager. The proxy has at nowadays been removed equally component of a fix, but its source tin give notice nonetheless move seen from an one-time revision: shill/http_proxy.cc . The code is unproblematic in addition to doesn’t seem to incorporate whatever obvious exploitable bugs, although it is real liberal inward what it accepts equally incoming HTTP. It calls into the c-ares library for resolving DNS. There was a possible 1 byte ov