Skip to content

gallium: fix surface->destroy use-after-free

Yujun Liu requested to merge liuyujun/mesa:main into main

demo: tested on radeonsi && nouveau

I think its small security issue

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

// g++ egl.cpp -lEGL -lGLESv2 && ./a.out

#include <EGL/egl.h>
#include <GLES2/gl2.h>

void fatalEGL(const char *msg) {
  printf("EGL: %s %d\n", msg, eglGetError());
  exit(-1);
}

#define ENSURE(condition)                                                      \
  if (!(condition))                                                            \
    fatalEGL(#condition);

int main(void) {
  EGLDisplay display;
  EGLint eglMaj, eglMin;
  EGLContext ctx1, ctx2;

  ENSURE((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) != EGL_NO_DISPLAY);
  ENSURE(eglInitialize(display, &eglMaj, &eglMin));
  ENSURE(eglBindAPI(EGL_OPENGL_ES_API));

  // sleep(5);

  // Get an EGL config.
  const EGLint attribs[] = {EGL_SURFACE_TYPE,
                            EGL_WINDOW_BIT,
                            EGL_RENDERABLE_TYPE,
                            EGL_OPENGL_ES3_BIT,
                            EGL_BLUE_SIZE,
                            8,
                            EGL_GREEN_SIZE,
                            8,
                            EGL_RED_SIZE,
                            8,
                            EGL_DEPTH_SIZE,
                            16,
                            EGL_NONE};
  EGLint numConfig = 0;
  EGLConfig eglConfig;
  ENSURE(eglChooseConfig(display, attribs, &eglConfig, 1, &numConfig) &&
         numConfig > 0);

  // Create a context.
  const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
  ENSURE((ctx2 = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT,
                                  contextAttribs)) != EGL_NO_CONTEXT);
  ENSURE((ctx1 = eglCreateContext(display, eglConfig, ctx2, contextAttribs)) !=
         EGL_NO_CONTEXT);

  ENSURE(eglMakeCurrent(display, 0, 0, ctx1));
  GLuint fb = 0;
  glGenFramebuffers(1, &fb);
  GLuint rbDepthStencil, rbColor;
  glGenRenderbuffers(1, &rbDepthStencil);
  glGenRenderbuffers(1, &rbColor);
  glBindFramebuffer(GL_FRAMEBUFFER, fb);
  glBindRenderbuffer(GL_RENDERBUFFER, rbDepthStencil);
  glRenderbufferStorage(GL_RENDERBUFFER, 0x88F0, 64, 64);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  glBindRenderbuffer(GL_RENDERBUFFER, rbColor);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 64, 64);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                            GL_RENDERBUFFER, rbDepthStencil);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                            GL_RENDERBUFFER, rbDepthStencil);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                            GL_RENDERBUFFER, rbColor);
  ENSURE(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  ENSURE(eglMakeCurrent(display, 0, 0, ctx2));
  glBindFramebuffer(GL_FRAMEBUFFER, fb);
  ENSURE(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  ENSURE(eglMakeCurrent(display, 0, 0, 0));
  ENSURE(eglDestroyContext(display, ctx1));
  printf("BUG\n");
  ENSURE((ctx1 = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT,
                                  contextAttribs)) != EGL_NO_CONTEXT);
  ENSURE(eglDestroyContext(display, ctx2)); // 这里的zsbuf已经是use-after-free了

  return 0;
}

Merge request reports