Upload
lehuong
View
234
Download
0
Embed Size (px)
Citation preview
GraphicsFuzzSecure and Robust Graphics Rendering
Hugues Evrard [email protected], Paul Thomson [email protected]
Challenge 1: is there a bug? (oracle problem)
graphics drivershader compiler
originalshader
1. Compiler crash
Crash
Challenge 1: is there a bug? (oracle problem)
graphics drivershader compiler
GPUoriginalshader
image
1. Compiler crash2. Miscompilation: much harder to detect
• bad image• security issues
????
Challenge 2: where is the bug?
graphics drivershader compiler
GPUoriginalshader
badimage
WebGL OpenGL IR GPU asm
Challenge 3: is the bug important?
graphics drivershader compiler
randomshader
high-valueshader
• Randomly searching may be ineffective• We start searching from high-value shaders
• Prioritizes issues that are likely to affect end-users
imageimage
Generate bug-inducing shader
graphics driver(shader compiler)
GPU
variantshader
originalshader
image
x = y + 0 ;
z = x * 1 ;
semantics preservingtransformations
imageimage
Generate bug-inducing shader
graphics driver(shader compiler)
GPU
variantshader
originalshader
semantics preservingtransformations
image
imageimageimage
imageimage
Generate bug-inducing shader
graphics driver(shader compiler)
GPU
variantshader
originalshader
image
imageimageimage
comparisonsemantics preservingtransformations
GPU
imageimage
Generate bug-inducing shader
graphics driver(shader compiler)
variantshader
originalshader
image
imageimageimage
diff/crashsemantics preservingtransformations
imageimage
Generate bug-inducing shader
graphics driver(shader compiler)
GPU
variantshader
originalshader
image
imageimageimage
comparisonsemantics preservingtransformations
metamorphic testing
Semantics-preserving transformations
• prelude: opaque expression [host] vec2 opaq = { 0.0, 1.0 };
[device] kernel main (…, opaq) {
( opaq.x < opaq.y ) opaq_True
( opaq.x > opaq.y ) opaq_False
opaq.x opaq_0
opaq.y opaq_1
}
Opaque value unknown at shader compilation time
Semantics-preserving transformations
• prelude: opaque expression
• dead code injection
int orig_y;
…
if (opaq_False) {
float donor_x;
// code from donor shader
…
orig_y = donor_x;
…
}
Donor code variables are either:• declared at start of block (donor_x)• replaced by existing variable with same type (orig_y)
Semantics-preserving transformations
• prelude: opaque expression
• dead code injection
• dead jump injection
if (opaq_False) {
jump;
}
Complicate the control flow graphjump: break / continue / return / discard
(special case of dead code injection)
Semantics-preserving transformations
• prelude: opaque expression
• dead code injection
• dead jump injection
• live code injection
// … original code
// donor code to be executed
// … original code
Add donor code at random position:• rename variables to avoid name clashes• declare variables• remove: break / continue / return / discard
Semantics-preserving transformations
• prelude: opaque expression
• dead code injection
• dead jump injection
• live code injection
• expression mutation
(opaq_True ?
[original expression]
: [random expression]
)
Random expression via “traditional” fuzzing
[original expression] + opaq_0;
For numeric expressions:
( [original expression] || opaq_False);
For boolean expressions:
Semantics-preserving transformations
• prelude: opaque expression
• dead code injection
• dead jump injection
• live code injection
• expression mutation
• vectorization
float a, c;
vec2 b;
…
b.x = a + b.y + c;
Pack variables into a merged variable:
vec4 abc; // abc == { a, b.x, b.y, c }
…
abc.yz.x = abc.x + abc.yz.y + abc.w;
• prelude: opaque expression
• dead code injection
• dead jump injection
• live code injection
• expression mutation
• vectorization
• control flow wrapping
if (opaq_True) { [original code] }
for (int tmp = opaq_0; tmp < opaq_1; tmp++) {
[original code]
}
do { [original code] } while (opaq_False);
Semantics-preserving transformations
Semantics-preserving transformations
• prelude: opaque expression
• dead code injection
• dead jump injection
• live code injection
• expression mutation
• vectorization
• control flow wrapping
if (opaq_True) { [original code] }
for (int tmp = opaq_0; tmp < opaq_1; tmp++) {
[original code]
}
do { [original code] } while (opaq_False);
Transformations can be applied recursively!
void main(void){
vec2 uv = (gl_FragCoord.xy / resolution.xy) * 2.0 - 1.0;uv.x *= resolution.x / resolution.y;if(_GLF_DEAD(_GLF_FALSE(false, (injectionSwitch.x > injectionSwitch.y))))
return;vec3 finalColor = RenderScene(uv);if(_GLF_DEAD(_GLF_IDENTITY(false, (false) || false)))
{vec3 donor_replacementp = _GLF_FUZZED(faceforward(((++ finalColor) - faceforward(vec3(4.8, 7582.5251, -
3.4), vec3(-369.491, -9.0, 6172.7474), finalColor)), vec3(6108.1119, -181.078, 495.885), (finalColor).yzx));float donor_replacementtw = _GLF_FUZZED(sign(dot((EPS / vec3(53.44, 6.0, -752.725)), fract(finalColor))));float donor_replacementstrength = _GLF_FUZZED(38.04);float donor_replacementprev = _GLF_FUZZED(clamp((+ distance(time, -47.91)), (-- finalColor.g), (mouse /
EPS)[1]));if(_GLF_DEAD(_GLF_FALSE(false, (injectionSwitch.x > injectionSwitch.y))))
return;float donor_replacementaccum = _GLF_FUZZED(distance(vec2(-349.170, -4419.3875), (- vec4(-359.006, 69.29, -
96.95, -243.116)).wz));if(_GLF_DEAD(_GLF_IDENTITY(false, (false ? _GLF_FUZZED((-28449 < shadowType)) : false))))
return;for(
int i = 0;i < 16;++ i
){
float mag = dot(donor_replacementp, donor_replacementp);donor_replacementp = abs(donor_replacementp) / mag + vec3(- .5, - .8 + 0.1 * sin(time * 0.7 + 2.0),
- 1.1 + 0.3 * cos(time * 0.3));float w = exp(- float(i) / 7.);donor_replacementaccum += w * exp(- donor_replacementstrength * pow(abs(mag -
$ diff recipient_reduced_final.frag variant_27_reduced_final.frag6a7,8> uniform vec2 injectionSwitch;>168a171,174> if(injectionSwitch.x > injectionSwitch.y)> {> return vec3(1.0);> }194a201,204> if(injectionSwitch.x > injectionSwitch.y)> {> return;> }
GPU
Reduce to a minimal difference test case
graphics driver(shader compiler)
Bug-induc.shader
originalshader
image
image
diff/crash
while (diff/crash) {random_remove_transformation()
}
GPU
Minimal difference test case
graphics driver(shader compiler)
Bug-induc.shader
originalshader
image
image
diff/crashsame semanticssmall syntax diff
isolates the bug
GraphicsFuzz: bug gallery
• AMD
if(injSwitch.x > injSwitch.y) {if(injSwitch.x > injSwitch.y) { return; }int f = 1;
}[..]if(injSwitch.x > injSwitch.y) { return; }
GraphicsFuzz: bug gallery
• AMD
• Apple
for(int c = 0; c < 1; c++) {if(j == 0) {return vec4(0.8, 0.5, 0.5, 1.0);
}}return vec4(0.8 * injSwitch.y, 0.7, 0.4, 1.0);
GraphicsFuzz: bug gallery
• AMD
• Apple
• ARM
if(injSwitch.x > injSwitch.y) {for(int i = 0; i < 1; i ++) {k = 0.0;
}}
GraphicsFuzz: bug gallery
• AMD
• Apple
• ARM
• Imagination
if(injSwitch.x > injSwitch.y) {for(int i = 0; i < 10; i ++) { continue; }
}[..]if(injSwitch.x > injSwitch.y) {if((p.z > 60.)) { break; }
}
GraphicsFuzz: bug gallery
• AMD
• Apple
• ARM
• Imagination
• Intel[..]vec2 uvs = [..];vec4 uvs_vec = vec4(0.0, uvs, 0.0);/* Replace uvs with uvs_vec.yz after */
GraphicsFuzz: bug gallery
• AMD
• Apple
• ARM
• Imagination
• Intel
• Nvidia vec3 hsbToRGB(float h, float s, float b) {return b * ((false ? (--s) : 1.0 ) - s)+ (b - (false ? (--s) : b * (1.0 - s) ))* clamp(abs(abs((false ? (--s) : 6.0 ) * [..];
}
GraphicsFuzz: bug gallery
• AMD
• Apple
• ARM
• Imagination
• Intel
• Nvidia
• Qualcomm
/* Multiple instances of the following,where v is a literal value */
if(injSwitch.x > injSwitch.y)return v;
Security bugs
• AMD: bluescreen
• Apple: iPhone rendering garbage
• Imagination: garbage rendering on Nexus Player
• Intel: bluescreen
• Nvidia: Ubuntu freeze
• Qualcomm: HTC One M7 restart via WebGL
Blog post series by Alastair on Medium : https://medium.com/@afd_icl/crashes-hangs-and-crazy-images-by-adding-zero-689d15ce922b
Team gallery
Alastair DonaldsonGroup Leader
Andrei LascuPhD student
Hugues EvrardPostDoc
Paul ThomsonPostDoc
MulticoreProgrammingGroup
http://multicore.doc.ic.ac.uk
Conclusion
• Our approach:• Automatically finds bugs• Produces a minimal difference test case
• C1: Is there a bug? Detect differences• metamorphic testing• semantics-preserving transformations
• C2: Where is the bug? Minimal difference test cases• Help to pinpoint bug location
• C3: Is the bug important/relevant? Start from high-value shaders• Prioritizes bugs that are close to being found in practice by developers
• Generic approach• beyond GLSL: HLSL, SPIR-V, Metal, …
• Can be used to amplify existing test suite