From 84970c40340624ec9f7ce57d57329316dd40f7ba29bb687f842cd528b11849be Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Thu, 31 Aug 2017 07:35:10 +0000 Subject: [PATCH] - Add patch to allow the NVIDIA driver to poke through seccomp and thus not crashing (kde#384005): * 0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch OBS-URL: https://build.opensuse.org/package/show/KDE:Frameworks5/kscreenlocker?expand=0&rev=96 --- ...open-with-write-flag-syscall-on-NVID.patch | 1640 +++++++++++++++++ kscreenlocker.changes | 7 + kscreenlocker.spec | 7 +- 3 files changed, 1650 insertions(+), 4 deletions(-) create mode 100644 0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch diff --git a/0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch b/0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch new file mode 100644 index 0000000..9c9e320 --- /dev/null +++ b/0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch @@ -0,0 +1,1640 @@ +From abe0c021226e5bf97ac61171941e75a75becf0e2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= +Date: Thu, 31 Aug 2017 09:10:28 +0200 +Subject: [PATCH] Don't dissallow open with write flag syscall on NVIDIA + +Summary: +The latest NVIDIA driver crashes the greeter due to our seccomp enabled +sandbox being too restrictive. The driver is now opening files for +writing after our dummy context got created and this causes a crash. In +order to provide our users a working system again we better disable the +seccomp rule for NVIDIA users for the time being. + +To detect whether an NVIDIA driver is used I copied the glplatform from +KWin which is known to work and more reliable than writing new custom +code even if it's a code copy. For master I'll look into splitting that +one out from KWin and putting it into a dedicated library so that we can +link it. + +This of course means that the seccomp based sandbox is now incomplete +for NVIDIA users. An idea is to add an additional apparmor rule in +master to enforce the write restrictions in similar way without forcing +it for /dev. + +BUG: 384005 + +Test Plan: I don't have an NVIDIA + +Reviewers: #plasma, davidedmundson + +Reviewed By: #plasma, davidedmundson + +Subscribers: davidedmundson, jriddell, plasma-devel + +Tags: #plasma + +Differential Revision: https://phabricator.kde.org/D7616 +--- + greeter/CMakeLists.txt | 1 + + greeter/autotests/CMakeLists.txt | 2 +- + greeter/autotests/seccomp_test.cpp | 4 + + greeter/kwinglplatform.cpp | 1062 ++++++++++++++++++++++++++++++++++++ + greeter/kwinglplatform.h | 416 ++++++++++++++ + greeter/seccomp_filter.cpp | 25 +- + 6 files changed, 1506 insertions(+), 4 deletions(-) + create mode 100644 greeter/kwinglplatform.cpp + create mode 100644 greeter/kwinglplatform.h + +diff --git a/greeter/CMakeLists.txt b/greeter/CMakeLists.txt +index c5b639a..49836b8 100644 +--- a/greeter/CMakeLists.txt ++++ b/greeter/CMakeLists.txt +@@ -13,6 +13,7 @@ set(kscreenlocker_greet_SRCS + main.cpp + noaccessnetworkaccessmanagerfactory.cpp + wallpaper_integration.cpp ++ kwinglplatform.cpp + ) + + if(HAVE_SECCOMP) +diff --git a/greeter/autotests/CMakeLists.txt b/greeter/autotests/CMakeLists.txt +index d5cb23d..d44f308 100644 +--- a/greeter/autotests/CMakeLists.txt ++++ b/greeter/autotests/CMakeLists.txt +@@ -32,7 +32,7 @@ target_link_libraries(killTest Qt5::Test) + # Seccomp Test + ####################################### + if(HAVE_SECCOMP) +- add_executable(seccompTest seccomp_test.cpp ../seccomp_filter.cpp) ++ add_executable(seccompTest seccomp_test.cpp ../seccomp_filter.cpp ../kwinglplatform.cpp) + add_test(kscreenlocker-seccompTest seccompTest) + ecm_mark_as_test(seccompTest) + target_link_libraries(seccompTest +diff --git a/greeter/autotests/seccomp_test.cpp b/greeter/autotests/seccomp_test.cpp +index 0006140..571c79d 100644 +--- a/greeter/autotests/seccomp_test.cpp ++++ b/greeter/autotests/seccomp_test.cpp +@@ -19,6 +19,7 @@ along with this program. If not, see . + *********************************************************************/ + #include + #include "../seccomp_filter.h" ++#include "../kwinglplatform.h" + + #include + #include +@@ -55,6 +56,9 @@ void SeccompTest::testCreateFile() + + void SeccompTest::testOpenFile() + { ++ if (KWin::GLPlatform::instance()->driver() == KWin::Driver_NVidia) { ++ QSKIP("Write protection not supported on NVIDIA"); ++ } + QFile file(QStringLiteral(KCHECKPASS_BIN)); + QVERIFY(file.exists()); + QVERIFY(!file.open(QIODevice::WriteOnly)); +diff --git a/greeter/kwinglplatform.cpp b/greeter/kwinglplatform.cpp +new file mode 100644 +index 0000000..ee98b50 +--- /dev/null ++++ b/greeter/kwinglplatform.cpp +@@ -0,0 +1,1062 @@ ++/******************************************************************** ++ KWin - the KDE window manager ++ This file is part of the KDE project. ++ ++Copyright (C) 2010 Fredrik Höglund ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program. If not, see . ++*********************************************************************/ ++ ++#include "kwinglplatform.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++namespace KWin ++{ ++ ++GLPlatform *GLPlatform::s_platform = 0; ++ ++static qint64 parseVersionString(const QByteArray &version) ++{ ++ // Skip any leading non digit ++ int start = 0; ++ while (start < version.length() && !QChar::fromLatin1(version[start]).isDigit()) ++ start++; ++ ++ // Strip any non digit, non '.' characters from the end ++ int end = start; ++ while (end < version.length() && (version[end] == '.' || QChar::fromLatin1(version[end]).isDigit())) ++ end++; ++ ++ const QByteArray result = version.mid(start, end-start); ++ const QList tokens = result.split('.'); ++ const qint64 major = tokens.at(0).toInt(); ++ const qint64 minor = tokens.count() > 1 ? tokens.at(1).toInt() : 0; ++ const qint64 patch = tokens.count() > 2 ? tokens.at(2).toInt() : 0; ++ ++ return kVersionNumber(major, minor, patch); ++} ++ ++static qint64 getKernelVersion() ++{ ++ struct utsname name; ++ uname(&name); ++ ++ if (qstrcmp(name.sysname, "Linux") == 0) ++ return parseVersionString(name.release); ++ ++ return 0; ++} ++ ++// Extracts the portion of a string that matches a regular expression ++static QString extract(const QString &string, const QString &match, int offset = 0) ++{ ++ QString result; ++ QRegExp rx(match); ++ int pos = rx.indexIn(string, offset); ++ if (pos != -1) ++ result = string.mid(pos, rx.matchedLength()); ++ return result; ++} ++ ++static ChipClass detectRadeonClass(const QByteArray &chipset) ++{ ++ if (chipset.isEmpty()) ++ return UnknownRadeon; ++ ++ if (chipset.contains("R100") || ++ chipset.contains("RV100") || ++ chipset.contains("RS100")) ++ return R100; ++ ++ if (chipset.contains("RV200") || ++ chipset.contains("RS200") || ++ chipset.contains("R200") || ++ chipset.contains("RV250") || ++ chipset.contains("RS300") || ++ chipset.contains("RV280")) ++ return R200; ++ ++ if (chipset.contains("R300") || ++ chipset.contains("R350") || ++ chipset.contains("R360") || ++ chipset.contains("RV350") || ++ chipset.contains("RV370") || ++ chipset.contains("RV380")) ++ return R300; ++ ++ if (chipset.contains("R420") || ++ chipset.contains("R423") || ++ chipset.contains("R430") || ++ chipset.contains("R480") || ++ chipset.contains("R481") || ++ chipset.contains("RV410") || ++ chipset.contains("RS400") || ++ chipset.contains("RC410") || ++ chipset.contains("RS480") || ++ chipset.contains("RS482") || ++ chipset.contains("RS600") || ++ chipset.contains("RS690") || ++ chipset.contains("RS740")) ++ return R400; ++ ++ if (chipset.contains("RV515") || ++ chipset.contains("R520") || ++ chipset.contains("RV530") || ++ chipset.contains("R580") || ++ chipset.contains("RV560") || ++ chipset.contains("RV570")) ++ return R500; ++ ++ if (chipset.contains("R600") || ++ chipset.contains("RV610") || ++ chipset.contains("RV630") || ++ chipset.contains("RV670") || ++ chipset.contains("RV620") || ++ chipset.contains("RV635") || ++ chipset.contains("RS780") || ++ chipset.contains("RS880")) ++ return R600; ++ ++ if (chipset.contains("R700") || ++ chipset.contains("RV770") || ++ chipset.contains("RV730") || ++ chipset.contains("RV710") || ++ chipset.contains("RV740")) ++ return R700; ++ ++ if (chipset.contains("EVERGREEN") || // Not an actual chipset, but returned by R600G in 7.9 ++ chipset.contains("CEDAR") || ++ chipset.contains("REDWOOD") || ++ chipset.contains("JUNIPER") || ++ chipset.contains("CYPRESS") || ++ chipset.contains("HEMLOCK") || ++ chipset.contains("PALM")) ++ return Evergreen; ++ ++ if (chipset.contains("SUMO") || ++ chipset.contains("SUMO2") || ++ chipset.contains("BARTS") || ++ chipset.contains("TURKS") || ++ chipset.contains("CAICOS") || ++ chipset.contains("CAYMAN")) ++ return NorthernIslands; ++ ++ const QString chipset16 = QString::fromLatin1(chipset); ++ QString name = extract(chipset16, QStringLiteral("HD [0-9]{4}")); // HD followed by a space and 4 digits ++ if (!name.isEmpty()) { ++ const int id = name.rightRef(4).toInt(); ++ if (id == 6250 || id == 6310) // Palm ++ return Evergreen; ++ ++ if (id >= 6000 && id < 7000) ++ return NorthernIslands; // HD 6xxx ++ ++ if (id >= 5000 && id < 6000) ++ return Evergreen; // HD 5xxx ++ ++ if (id >= 4000 && id < 5000) ++ return R700; // HD 4xxx ++ ++ if (id >= 2000 && id < 4000) // HD 2xxx/3xxx ++ return R600; ++ ++ return UnknownRadeon; ++ } ++ ++ name = extract(chipset16, QStringLiteral("X[0-9]{3,4}")); // X followed by 3-4 digits ++ if (!name.isEmpty()) { ++ const int id = name.midRef(1, -1).toInt(); ++ ++ // X1xxx ++ if (id >= 1300) ++ return R500; ++ ++ // X7xx, X8xx, X12xx, 2100 ++ if ((id >= 700 && id < 1000) || id >= 1200) ++ return R400; ++ ++ // X200, X3xx, X5xx, X6xx, X10xx, X11xx ++ if ((id >= 300 && id < 700) || (id >= 1000 && id < 1200)) ++ return R300; ++ ++ return UnknownRadeon; ++ } ++ ++ name = extract(chipset16, QStringLiteral("\\b[0-9]{4}\\b")); // A group of 4 digits ++ if (!name.isEmpty()) { ++ const int id = name.toInt(); ++ ++ // 7xxx ++ if (id >= 7000 && id < 8000) ++ return R100; ++ ++ // 8xxx, 9xxx ++ if (id >= 8000 && id < 9500) ++ return R200; ++ ++ // 9xxx ++ if (id >= 9500) ++ return R300; ++ ++ if (id == 2100) ++ return R400; ++ } ++ ++ return UnknownRadeon; ++} ++ ++static ChipClass detectNVidiaClass(const QString &chipset) ++{ ++ QString name = extract(chipset, QStringLiteral("\\bNV[0-9,A-F]{2}\\b")); // NV followed by two hexadecimal digits ++ if (!name.isEmpty()) { ++ const int id = chipset.midRef(2, -1).toInt(0, 16); // Strip the 'NV' from the id ++ ++ switch(id & 0xf0) { ++ case 0x00: ++ case 0x10: ++ return NV10; ++ ++ case 0x20: ++ return NV20; ++ ++ case 0x30: ++ return NV30; ++ ++ case 0x40: ++ case 0x60: ++ return NV40; ++ ++ case 0x50: ++ case 0x80: ++ case 0x90: ++ case 0xA0: ++ return G80; ++ ++ default: ++ return UnknownNVidia; ++ } ++ } ++ ++ if (chipset.contains(QLatin1String("GeForce2")) || chipset.contains(QLatin1String("GeForce 256"))) ++ return NV10; ++ ++ if (chipset.contains(QLatin1String("GeForce3"))) ++ return NV20; ++ ++ if (chipset.contains(QLatin1String("GeForce4"))) { ++ if (chipset.contains(QLatin1String("MX 420")) || ++ chipset.contains(QLatin1String("MX 440")) || // including MX 440SE ++ chipset.contains(QLatin1String("MX 460")) || ++ chipset.contains(QLatin1String("MX 4000")) || ++ chipset.contains(QLatin1String("PCX 4300"))) ++ return NV10; ++ ++ return NV20; ++ } ++ ++ // GeForce 5,6,7,8,9 ++ name = extract(chipset, QStringLiteral("GeForce (FX |PCX |Go )?\\d{4}(M|\\b)")).trimmed(); ++ if (!name.isEmpty()) { ++ if (!name[name.length() - 1].isDigit()) ++ name.chop(1); ++ ++ const int id = name.rightRef(4).toInt(); ++ if (id < 6000) ++ return NV30; ++ ++ if (id >= 6000 && id < 8000) ++ return NV40; ++ ++ if (id >= 8000) ++ return G80; ++ ++ return UnknownNVidia; ++ } ++ ++ // GeForce 100/200/300/400/500 ++ name = extract(chipset, QStringLiteral("GeForce (G |GT |GTX |GTS )?\\d{3}(M|\\b)")).trimmed(); ++ if (!name.isEmpty()) { ++ if (!name[name.length() - 1].isDigit()) ++ name.chop(1); ++ ++ const int id = name.rightRef(3).toInt(); ++ if (id >= 100 && id < 600) { ++ if (id >= 400) ++ return GF100; ++ ++ return G80; ++ } ++ return UnknownNVidia; ++ } ++ ++ return UnknownNVidia; ++} ++static inline ChipClass detectNVidiaClass(const QByteArray &chipset) ++{ ++ return detectNVidiaClass(QString::fromLatin1(chipset)); ++} ++ ++static ChipClass detectIntelClass(const QByteArray &chipset) ++{ ++ // see mesa repository: src/mesa/drivers/dri/intel/intel_context.c ++ // GL 1.3, DX8? SM ? ++ if (chipset.contains("845G") || ++ chipset.contains("830M") || ++ chipset.contains("852GM/855GM") || ++ chipset.contains("865G")) ++ return I8XX; ++ ++ // GL 1.4, DX 9.0, SM 2.0 ++ if (chipset.contains("915G") || ++ chipset.contains("E7221G") || ++ chipset.contains("915GM") || ++ chipset.contains("945G") || // DX 9.0c ++ chipset.contains("945GM") || ++ chipset.contains("945GME") || ++ chipset.contains("Q33") || // GL1.5 ++ chipset.contains("Q35") || ++ chipset.contains("G33") || ++ chipset.contains("965Q") || // GMA 3000, but apparently considered gen 4 by the driver ++ chipset.contains("946GZ") || // GMA 3000, but apparently considered gen 4 by the driver ++ chipset.contains("IGD")) ++ return I915; ++ ++ // GL 2.0, DX 9.0c, SM 3.0 ++ if (chipset.contains("965G") || ++ chipset.contains("G45/G43") || // SM 4.0 ++ chipset.contains("965GM") || // GL 2.1 ++ chipset.contains("965GME/GLE") || ++ chipset.contains("GM45") || ++ chipset.contains("Q45/Q43") || ++ chipset.contains("G41") || ++ chipset.contains("B43") || ++ chipset.contains("Ironlake")) ++ return I965; ++ ++ // GL 3.1, CL 1.1, DX 10.1 ++ if (chipset.contains("Sandybridge")) { ++ return SandyBridge; ++ } ++ ++ // GL4.0, CL1.1, DX11, SM 5.0 ++ if (chipset.contains("Ivybridge")) { ++ return IvyBridge; ++ } ++ ++ // GL4.0, CL1.2, DX11.1, SM 5.0 ++ if (chipset.contains("Haswell")) { ++ return Haswell; ++ } ++ ++ return UnknownIntel; ++} ++ ++static ChipClass detectQualcommClass(const QByteArray &chipClass) ++{ ++ if (!chipClass.contains("Adreno")) { ++ return UnknownChipClass; ++ } ++ const auto parts = chipClass.split(' '); ++ if (parts.count() < 3) { ++ return UnknownAdreno; ++ } ++ bool ok = false; ++ const int value = parts.at(2).toInt(&ok); ++ if (ok) { ++ if (value >= 100 && value < 200) { ++ return Adreno1XX; ++ } ++ if (value >= 200 && value < 300) { ++ return Adreno2XX; ++ } ++ if (value >= 300 && value < 400) { ++ return Adreno3XX; ++ } ++ if (value >= 400 && value < 500) { ++ return Adreno4XX; ++ } ++ if (value >= 500 && value < 600) { ++ return Adreno5XX; ++ } ++ } ++ return UnknownAdreno; ++} ++ ++QString GLPlatform::versionToString(qint64 version) ++{ ++ return QString::fromLatin1(versionToString8(version)); ++} ++QByteArray GLPlatform::versionToString8(qint64 version) ++{ ++ int major = (version >> 32); ++ int minor = (version >> 16) & 0xffff; ++ int patch = version & 0xffff; ++ ++ QByteArray string = QByteArray::number(major) + '.' + QByteArray::number(minor); ++ if (patch != 0) ++ string += '.' + QByteArray::number(patch); ++ ++ return string; ++} ++ ++QString GLPlatform::driverToString(Driver driver) ++{ ++ return QString::fromLatin1(driverToString8(driver)); ++} ++QByteArray GLPlatform::driverToString8(Driver driver) ++{ ++ switch(driver) { ++ case Driver_R100: ++ return QByteArrayLiteral("Radeon"); ++ case Driver_R200: ++ return QByteArrayLiteral("R200"); ++ case Driver_R300C: ++ return QByteArrayLiteral("R300C"); ++ case Driver_R300G: ++ return QByteArrayLiteral("R300G"); ++ case Driver_R600C: ++ return QByteArrayLiteral("R600C"); ++ case Driver_R600G: ++ return QByteArrayLiteral("R600G"); ++ case Driver_Nouveau: ++ return QByteArrayLiteral("Nouveau"); ++ case Driver_Intel: ++ return QByteArrayLiteral("Intel"); ++ case Driver_NVidia: ++ return QByteArrayLiteral("NVIDIA"); ++ case Driver_Catalyst: ++ return QByteArrayLiteral("Catalyst"); ++ case Driver_Swrast: ++ return QByteArrayLiteral("Software rasterizer"); ++ case Driver_Softpipe: ++ return QByteArrayLiteral("softpipe"); ++ case Driver_Llvmpipe: ++ return QByteArrayLiteral("LLVMpipe"); ++ case Driver_VirtualBox: ++ return QByteArrayLiteral("VirtualBox (Chromium)"); ++ case Driver_VMware: ++ return QByteArrayLiteral("VMware (SVGA3D)"); ++ case Driver_Qualcomm: ++ return QByteArrayLiteral("Qualcomm"); ++ ++ default: ++ return QByteArrayLiteral("Unknown"); ++ } ++} ++ ++QString GLPlatform::chipClassToString(ChipClass chipClass) ++{ ++ return QString::fromLatin1(chipClassToString8(chipClass)); ++} ++QByteArray GLPlatform::chipClassToString8(ChipClass chipClass) ++{ ++ switch(chipClass) { ++ case R100: ++ return QByteArrayLiteral("R100"); ++ case R200: ++ return QByteArrayLiteral("R200"); ++ case R300: ++ return QByteArrayLiteral("R300"); ++ case R400: ++ return QByteArrayLiteral("R400"); ++ case R500: ++ return QByteArrayLiteral("R500"); ++ case R600: ++ return QByteArrayLiteral("R600"); ++ case R700: ++ return QByteArrayLiteral("R700"); ++ case Evergreen: ++ return QByteArrayLiteral("EVERGREEN"); ++ case NorthernIslands: ++ return QByteArrayLiteral("NI"); ++ ++ case NV10: ++ return QByteArrayLiteral("NV10"); ++ case NV20: ++ return QByteArrayLiteral("NV20"); ++ case NV30: ++ return QByteArrayLiteral("NV30"); ++ case NV40: ++ return QByteArrayLiteral("NV40/G70"); ++ case G80: ++ return QByteArrayLiteral("G80/G90"); ++ case GF100: ++ return QByteArrayLiteral("GF100"); ++ ++ case I8XX: ++ return QByteArrayLiteral("i830/i835"); ++ case I915: ++ return QByteArrayLiteral("i915/i945"); ++ case I965: ++ return QByteArrayLiteral("i965"); ++ case SandyBridge: ++ return QByteArrayLiteral("SandyBridge"); ++ case IvyBridge: ++ return QByteArrayLiteral("IvyBridge"); ++ case Haswell: ++ return QByteArrayLiteral("Haswell"); ++ ++ case Adreno1XX: ++ return QByteArrayLiteral("Adreno 1xx series"); ++ case Adreno2XX: ++ return QByteArrayLiteral("Adreno 2xx series"); ++ case Adreno3XX: ++ return QByteArrayLiteral("Adreno 3xx series"); ++ case Adreno4XX: ++ return QByteArrayLiteral("Adreno 4xx series"); ++ case Adreno5XX: ++ return QByteArrayLiteral("Adreno 5xx series"); ++ ++ default: ++ return QByteArrayLiteral("Unknown"); ++ } ++} ++ ++ ++ ++// ------- ++ ++ ++ ++GLPlatform::GLPlatform() ++ : m_driver(Driver_Unknown), ++ m_chipClass(UnknownChipClass), ++ m_glVersion(0), ++ m_glslVersion(0), ++ m_mesaVersion(0), ++ m_driverVersion(0), ++ m_galliumVersion(0), ++ m_serverVersion(0), ++ m_kernelVersion(0), ++ m_looseBinding(false), ++ m_supportsGLSL(false), ++ m_limitedGLSL(false), ++ m_textureNPOT(false), ++ m_limitedNPOT(false), ++ m_virtualMachine(false), ++ m_preferBufferSubData(false), ++ m_gles(false) ++{ ++} ++ ++GLPlatform::~GLPlatform() ++{ ++} ++ ++void GLPlatform::detect() ++{ ++ QOpenGLFunctions gl; ++ gl.initializeOpenGLFunctions(); ++ ++ m_vendor = (const char*)gl.glGetString(GL_VENDOR); ++ m_renderer = (const char*)gl.glGetString(GL_RENDERER); ++ m_version = (const char*)gl.glGetString(GL_VERSION); ++ ++ // Parse the OpenGL version ++ const QList versionTokens = m_version.split(' '); ++ if (versionTokens.count() > 0) { ++ const QByteArray version = QByteArray(m_version); ++ m_glVersion = parseVersionString(version); ++ if (version.startsWith("OpenGL ES")) { ++ // from GLES 2: "Returns a version or release number of the form OpenGLES." ++ // from GLES 3: "Returns a version or release number." and "The version number uses one of these forms: major_number.minor_number major_number.minor_number.release_number" ++ m_gles = true; ++ } ++ } ++ ++ const QByteArray extensions = (const char *) gl.glGetString(GL_EXTENSIONS); ++ m_extensions = QSet::fromList(extensions.split(' ')); ++ ++ // Parse the Mesa version ++ const int mesaIndex = versionTokens.indexOf("Mesa"); ++ if (mesaIndex != -1) { ++ const QByteArray version = versionTokens.at(mesaIndex + 1); ++ m_mesaVersion = parseVersionString(version); ++ } ++ ++ if (isGLES()) { ++ m_supportsGLSL = true; ++ m_textureNPOT = true; ++ } else { ++ m_supportsGLSL = m_extensions.contains("GL_ARB_shader_objects") && ++ m_extensions.contains("GL_ARB_fragment_shader") && ++ m_extensions.contains("GL_ARB_vertex_shader"); ++ ++ m_textureNPOT = m_extensions.contains("GL_ARB_texture_non_power_of_two"); ++ } ++ ++ m_kernelVersion = getKernelVersion(); ++ ++ m_glslVersion = 0; ++ m_glsl_version.clear(); ++ ++ if (m_supportsGLSL) { ++ // Parse the GLSL version ++ m_glsl_version = (const char*)gl.glGetString(GL_SHADING_LANGUAGE_VERSION); ++ m_glslVersion = parseVersionString(m_glsl_version); ++ } ++ ++ m_chipset = QByteArrayLiteral("Unknown"); ++ m_preferBufferSubData = false; ++ ++ ++ // Mesa classic drivers ++ // ==================================================== ++ ++ // Radeon ++ if (m_renderer.startsWith("Mesa DRI R")) { ++ // Sample renderer string: Mesa DRI R600 (RV740 94B3) 20090101 x86/MMX/SSE2 TCL DRI2 ++ const QList tokens = m_renderer.split(' '); ++ const QByteArray chipClass = tokens.at(2); ++ m_chipset = tokens.at(3).mid(1, -1); // Strip the leading '(' ++ ++ if (chipClass == "R100") ++ // Vendor: Tungsten Graphics, Inc. ++ m_driver = Driver_R100; ++ ++ else if (chipClass == "R200") ++ // Vendor: Tungsten Graphics, Inc. ++ m_driver = Driver_R200; ++ ++ else if (chipClass == "R300") ++ // Vendor: DRI R300 Project ++ m_driver = Driver_R300C; ++ ++ else if (chipClass == "R600") ++ // Vendor: Advanced Micro Devices, Inc. ++ m_driver = Driver_R600C; ++ ++ m_chipClass = detectRadeonClass(m_chipset); ++ } ++ ++ // Intel ++ else if (m_renderer.contains("Intel")) { ++ // Vendor: Tungsten Graphics, Inc. ++ // Sample renderer string: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100328 2010Q1 ++ ++ QByteArray chipset; ++ if (m_renderer.startsWith("Intel(R) Integrated Graphics Device")) ++ chipset = "IGD"; ++ else ++ chipset = m_renderer; ++ ++ m_driver = Driver_Intel; ++ m_chipClass = detectIntelClass(chipset); ++ } ++ ++ // Gallium drivers ++ // ==================================================== ++ else if (m_renderer.contains("Gallium")) { ++ // Sample renderer string: Gallium 0.4 on AMD RV740 ++ const QList tokens = m_renderer.split(' '); ++ m_galliumVersion = parseVersionString(tokens.at(1)); ++ m_chipset = (tokens.at(3) == "AMD" || tokens.at(3) == "ATI") ? ++ tokens.at(4) : tokens.at(3); ++ ++ // R300G ++ if (m_vendor == QByteArrayLiteral("X.Org R300 Project")) { ++ m_chipClass = detectRadeonClass(m_chipset); ++ m_driver = Driver_R300G; ++ } ++ ++ // R600G ++ else if (m_vendor == "X.Org" && ++ (m_renderer.contains("R6") || ++ m_renderer.contains("R7") || ++ m_renderer.contains("RV6") || ++ m_renderer.contains("RV7") || ++ m_renderer.contains("RS780") || ++ m_renderer.contains("RS880") || ++ m_renderer.contains("CEDAR") || ++ m_renderer.contains("REDWOOD") || ++ m_renderer.contains("JUNIPER") || ++ m_renderer.contains("CYPRESS") || ++ m_renderer.contains("HEMLOCK") || ++ m_renderer.contains("PALM") || ++ m_renderer.contains("EVERGREEN") || ++ m_renderer.contains("SUMO") || ++ m_renderer.contains("SUMO2") || ++ m_renderer.contains("BARTS") || ++ m_renderer.contains("TURKS") || ++ m_renderer.contains("CAICOS") || ++ m_renderer.contains("CAYMAN"))) { ++ m_chipClass = detectRadeonClass(m_chipset); ++ m_driver = Driver_R600G; ++ } ++ ++ // Nouveau ++ else if (m_vendor == "nouveau") { ++ m_chipClass = detectNVidiaClass(m_chipset); ++ m_driver = Driver_Nouveau; ++ } ++ ++ // softpipe ++ else if (m_vendor == "VMware, Inc." && m_chipset == "softpipe" ) { ++ m_driver = Driver_Softpipe; ++ } ++ ++ // llvmpipe ++ else if (m_vendor == "VMware, Inc." && m_chipset == "llvmpipe") { ++ m_driver = Driver_Llvmpipe; ++ } ++ ++ // SVGA3D ++ else if (m_vendor == "VMware, Inc." && m_chipset.contains("SVGA3D")) { ++ m_driver = Driver_VMware; ++ } ++ } ++ ++ ++ // Properietary drivers ++ // ==================================================== ++ else if (m_vendor == "ATI Technologies Inc.") { ++ m_chipClass = detectRadeonClass(m_renderer); ++ m_driver = Driver_Catalyst; ++ ++ if (versionTokens.count() > 1 && versionTokens.at(2)[0] == '(') ++ m_driverVersion = parseVersionString(versionTokens.at(1)); ++ else if (versionTokens.count() > 0) ++ m_driverVersion = parseVersionString(versionTokens.at(0)); ++ else ++ m_driverVersion = 0; ++ } ++ ++ else if (m_vendor == "NVIDIA Corporation") { ++ m_chipClass = detectNVidiaClass(m_renderer); ++ m_driver = Driver_NVidia; ++ ++ int index = versionTokens.indexOf("NVIDIA"); ++ if (versionTokens.count() > index) ++ m_driverVersion = parseVersionString(versionTokens.at(index + 1)); ++ else ++ m_driverVersion = 0; ++ } ++ ++ else if (m_vendor == "Qualcomm") { ++ m_driver = Driver_Qualcomm; ++ m_chipClass = detectQualcommClass(m_renderer); ++ } ++ ++ else if (m_renderer == "Software Rasterizer") { ++ m_driver = Driver_Swrast; ++ } ++ ++ // Virtual Hardware ++ // ==================================================== ++ else if (m_vendor == "Humper" && m_renderer == "Chromium") { ++ // Virtual Box ++ m_driver = Driver_VirtualBox; ++ ++ const int index = versionTokens.indexOf("Chromium"); ++ if (versionTokens.count() > index) ++ m_driverVersion = parseVersionString(versionTokens.at(index + 1)); ++ else ++ m_driverVersion = 0; ++ } ++ ++ ++ // Driver/GPU specific features ++ // ==================================================== ++ if (isRadeon()) { ++ // R200 technically has a programmable pipeline, but since it's SM 1.4, ++ // it's too limited to to be of any practical value to us. ++ if (m_chipClass < R300) ++ m_supportsGLSL = false; ++ ++ m_limitedGLSL = false; ++ m_limitedNPOT = false; ++ ++ if (m_chipClass < R600) { ++ if (driver() == Driver_Catalyst) ++ m_textureNPOT = m_limitedNPOT = false; // Software fallback ++ else if (driver() == Driver_R300G) ++ m_limitedNPOT = m_textureNPOT; ++ ++ m_limitedGLSL = m_supportsGLSL; ++ } ++ ++ if (driver() == Driver_R600G || ++ (driver() == Driver_R600C && m_renderer.contains("DRI2"))) { ++ m_looseBinding = true; ++ } ++ } ++ ++ if (isNvidia()) { ++ if (m_driver == Driver_NVidia && m_chipClass < NV40) ++ m_supportsGLSL = false; // High likelihood of software emulation ++ ++ if (m_driver == Driver_NVidia) { ++ m_looseBinding = true; ++ m_preferBufferSubData = true; ++ } ++ ++ m_limitedNPOT = m_textureNPOT && m_chipClass < NV40; ++ m_limitedGLSL = m_supportsGLSL && m_chipClass < G80; ++ } ++ ++ if (isIntel()) { ++ if (m_chipClass < I915) ++ m_supportsGLSL = false; ++ ++ m_limitedGLSL = m_supportsGLSL && m_chipClass < I965; ++ // see https://bugs.freedesktop.org/show_bug.cgi?id=80349#c1 ++ m_looseBinding = false; ++ } ++ ++ if (isSoftwareEmulation()) { ++ if (m_driver < Driver_Llvmpipe) { ++ // Software emulation does not provide GLSL ++ m_limitedGLSL = m_supportsGLSL = false; ++ } else { ++ m_limitedGLSL = false; ++ m_supportsGLSL = true; ++ } ++ } ++ ++ if (m_chipClass == UnknownChipClass && m_driver == Driver_Unknown) { ++ // we don't know the hardware. Let's be optimistic and assume OpenGL compatible hardware ++ m_supportsGLSL = true; ++ } ++ ++ if (isVirtualBox()) { ++ m_virtualMachine = true; ++ } ++ ++ if (isVMware()) { ++ m_virtualMachine = true; ++ } ++ ++ // and force back to shader supported on gles, we wouldn't have got a context if not supported ++ if (isGLES()) { ++ m_supportsGLSL = true; ++ m_limitedGLSL = false; ++ } ++} ++ ++static void print(const QByteArray &label, const QByteArray &setting) ++{ ++ std::cout << std::setw(40) << std::left ++ << label.data() << setting.data() << std::endl; ++} ++ ++void GLPlatform::printResults() const ++{ ++ print(QByteArrayLiteral("OpenGL vendor string:"), m_vendor); ++ print(QByteArrayLiteral("OpenGL renderer string:"), m_renderer); ++ print(QByteArrayLiteral("OpenGL version string:"), m_version); ++ ++ if (m_supportsGLSL) ++ print(QByteArrayLiteral("OpenGL shading language version string:"), m_glsl_version); ++ ++ print(QByteArrayLiteral("Driver:"), driverToString8(m_driver)); ++ if (!isMesaDriver()) ++ print(QByteArrayLiteral("Driver version:"), versionToString8(m_driverVersion)); ++ ++ print(QByteArrayLiteral("GPU class:"), chipClassToString8(m_chipClass)); ++ ++ print(QByteArrayLiteral("OpenGL version:"), versionToString8(m_glVersion)); ++ ++ if (m_supportsGLSL) ++ print(QByteArrayLiteral("GLSL version:"), versionToString8(m_glslVersion)); ++ ++ if (isMesaDriver()) ++ print(QByteArrayLiteral("Mesa version:"), versionToString8(mesaVersion())); ++ //if (galliumVersion() > 0) ++ // print("Gallium version:", versionToString(m_galliumVersion)); ++ if (serverVersion() > 0) ++ print(QByteArrayLiteral("X server version:"), versionToString8(m_serverVersion)); ++ if (kernelVersion() > 0) ++ print(QByteArrayLiteral("Linux kernel version:"), versionToString8(m_kernelVersion)); ++ ++ print(QByteArrayLiteral("Requires strict binding:"), !m_looseBinding ? QByteArrayLiteral("yes") : QByteArrayLiteral("no")); ++ print(QByteArrayLiteral("GLSL shaders:"), m_supportsGLSL ? (m_limitedGLSL ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no")); ++ print(QByteArrayLiteral("Texture NPOT support:"), m_textureNPOT ? (m_limitedNPOT ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no")); ++ print(QByteArrayLiteral("Virtual Machine:"), m_virtualMachine ? QByteArrayLiteral("yes") : QByteArrayLiteral("no")); ++} ++ ++bool GLPlatform::supports(GLFeature feature) const ++{ ++ switch(feature) { ++ case LooseBinding: ++ return m_looseBinding; ++ ++ case GLSL: ++ return m_supportsGLSL; ++ ++ case LimitedGLSL: ++ return m_limitedGLSL; ++ ++ case TextureNPOT: ++ return m_textureNPOT; ++ ++ case LimitedNPOT: ++ return m_limitedNPOT; ++ ++ default: ++ return false; ++ } ++} ++ ++qint64 GLPlatform::glVersion() const ++{ ++ return m_glVersion; ++} ++ ++qint64 GLPlatform::glslVersion() const ++{ ++ return m_glslVersion; ++} ++ ++qint64 GLPlatform::mesaVersion() const ++{ ++ return m_mesaVersion; ++} ++ ++qint64 GLPlatform::galliumVersion() const ++{ ++ return m_galliumVersion; ++} ++ ++qint64 GLPlatform::serverVersion() const ++{ ++ return m_serverVersion; ++} ++ ++qint64 GLPlatform::kernelVersion() const ++{ ++ return m_kernelVersion; ++} ++ ++qint64 GLPlatform::driverVersion() const ++{ ++ if (isMesaDriver()) ++ return mesaVersion(); ++ ++ return m_driverVersion; ++} ++ ++Driver GLPlatform::driver() const ++{ ++ return m_driver; ++} ++ ++ChipClass GLPlatform::chipClass() const ++{ ++ return m_chipClass; ++} ++ ++bool GLPlatform::isMesaDriver() const ++{ ++ return mesaVersion() > 0; ++} ++ ++bool GLPlatform::isGalliumDriver() const ++{ ++ return galliumVersion() > 0; ++} ++ ++bool GLPlatform::isRadeon() const ++{ ++ return m_chipClass >= R100 && m_chipClass <= UnknownRadeon; ++} ++ ++bool GLPlatform::isNvidia() const ++{ ++ return m_chipClass >= NV10 && m_chipClass <= UnknownNVidia; ++} ++ ++bool GLPlatform::isIntel() const ++{ ++ return m_chipClass >= I8XX && m_chipClass <= UnknownIntel; ++} ++ ++bool GLPlatform::isVirtualBox() const ++{ ++ return m_driver == Driver_VirtualBox; ++} ++ ++bool GLPlatform::isVMware() const ++{ ++ return m_driver == Driver_VMware; ++} ++ ++bool GLPlatform::isSoftwareEmulation() const ++{ ++ return m_driver == Driver_Softpipe || m_driver == Driver_Swrast || m_driver == Driver_Llvmpipe; ++} ++ ++bool GLPlatform::isAdreno() const ++{ ++ return m_chipClass >= Adreno1XX && m_chipClass <= UnknownAdreno; ++} ++ ++const QByteArray &GLPlatform::glRendererString() const ++{ ++ return m_renderer; ++} ++ ++const QByteArray &GLPlatform::glVendorString() const ++{ ++ return m_vendor; ++} ++ ++const QByteArray &GLPlatform::glVersionString() const ++{ ++ return m_version; ++} ++ ++const QByteArray &GLPlatform::glShadingLanguageVersionString() const ++{ ++ return m_glsl_version; ++} ++ ++bool GLPlatform::isLooseBinding() const ++{ ++ return m_looseBinding; ++} ++ ++bool GLPlatform::isVirtualMachine() const ++{ ++ return m_virtualMachine; ++} ++ ++bool GLPlatform::preferBufferSubData() const ++{ ++ return m_preferBufferSubData; ++} ++ ++bool GLPlatform::isGLES() const ++{ ++ return m_gles; ++} ++ ++void GLPlatform::cleanup() ++{ ++ delete s_platform; ++ s_platform = nullptr; ++} ++ ++} // namespace KWin ++ +diff --git a/greeter/kwinglplatform.h b/greeter/kwinglplatform.h +new file mode 100644 +index 0000000..60bebe1 +--- /dev/null ++++ b/greeter/kwinglplatform.h +@@ -0,0 +1,416 @@ ++/******************************************************************** ++ KWin - the KDE window manager ++ This file is part of the KDE project. ++ ++Copyright (C) 2010 Fredrik Höglund ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program. If not, see . ++*********************************************************************/ ++ ++#ifndef KWIN_GLPLATFORM_H ++#define KWIN_GLPLATFORM_H ++ ++#include ++#include ++ ++namespace KWin ++{ ++// forward declare method ++void cleanupGL(); ++ ++inline qint64 kVersionNumber(qint64 major, qint64 minor, qint64 patch = 0) ++{ ++ return ((major & 0xffff) << 32) | ((minor & 0xffff) << 16) | (patch & 0xffff); ++} ++ ++enum GLFeature { ++ /** ++ * Set when a texture bound to a pixmap uses the same storage as the pixmap, ++ * and thus doesn't need to be rebound when the contents of the pixmap ++ * has changed. ++ */ ++ LooseBinding, ++ ++ /** ++ * Set if the driver supports the following extensions: ++ * - GL_ARB_shader_objects ++ * - GL_ARB_fragment_shader ++ * - GL_ARB_vertex_shader ++ * - GL_ARB_shading_language_100 ++ */ ++ GLSL, ++ ++ /** ++ * If set, assume the following: ++ * - No flow control or branches ++ * - No loops, unless the loops have a fixed iteration count and can be unrolled ++ * - No functions, unless they can be inlined ++ * - No indirect indexing of arrays ++ * - No support for gl_ClipVertex or gl_FrontFacing ++ * - No texture fetches in vertex shaders ++ * - Max 32 texture fetches in fragment shaders ++ * - Max 4 texture indirections ++ */ ++ LimitedGLSL, ++ ++ /** ++ * Set when the driver supports GL_ARB_texture_non_power_of_two. ++ */ ++ TextureNPOT, ++ ++ /** ++ * If set, the driver supports GL_ARB_texture_non_power_of_two with the ++ * GL_ARB_texture_rectangle limitations. ++ * ++ * This means no support for mipmap filters, and that only the following ++ * wrap modes are supported: ++ * - GL_CLAMP ++ * - GL_CLAMP_TO_EDGE ++ * - GL_CLAMP_TO_BORDER ++ */ ++ LimitedNPOT ++}; ++ ++enum Driver { ++ Driver_R100, // Technically "Radeon" ++ Driver_R200, ++ Driver_R300C, ++ Driver_R300G, ++ Driver_R600C, ++ Driver_R600G, ++ Driver_Nouveau, ++ Driver_Intel, ++ Driver_NVidia, ++ Driver_Catalyst, ++ Driver_Swrast, ++ Driver_Softpipe, ++ Driver_Llvmpipe, ++ Driver_VirtualBox, ++ Driver_VMware, ++ Driver_Qualcomm, ++ Driver_Unknown ++}; ++ ++enum ChipClass { ++ // Radeon ++ R100 = 0, // GL1.3 DX7 2000 ++ R200, // GL1.4 DX8.1 SM 1.4 2001 ++ R300, // GL2.0 DX9 SM 2.0 2002 ++ R400, // GL2.0 DX9b SM 2.0b 2004 ++ R500, // GL2.0 DX9c SM 3.0 2005 ++ R600, // GL3.3 DX10 SM 4.0 2006 ++ R700, // GL3.3 DX10.1 SM 4.1 2008 ++ Evergreen, // GL4.0 CL1.0 DX11 SM 5.0 2009 ++ NorthernIslands, // GL4.0 CL1.1 DX11 SM 5.0 2010 ++ UnknownRadeon = 999, ++ ++ // NVIDIA ++ NV10 = 1000, // GL1.2 DX7 1999 ++ NV20, // GL1.3 DX8 SM 1.1 2001 ++ NV30, // GL1.5 DX9a SM 2.0 2003 ++ NV40, // GL2.1 DX9c SM 3.0 2004 ++ G80, // GL3.3 DX10 SM 4.0 2006 ++ GF100, // GL4.1 CL1.1 DX11 SM 5.0 2010 ++ UnknownNVidia = 1999, ++ ++ // Intel ++ I8XX = 2000, // GL1.3 DX7 2001 ++ I915, // GL1.4/1.5 DX9/DX9c SM 2.0 2004 ++ I965, // GL2.0/2.1 DX9/DX10 SM 3.0/4.0 2006 ++ SandyBridge, // GL3.1 CL1.1 DX10.1 SM 4.0 2010 ++ IvyBridge, // GL4.0 CL1.1 DX11 SM 5.0 2012 ++ Haswell, // GL4.0 CL1.2 DX11.1 SM 5.0 2013 ++ UnknownIntel = 2999, ++ ++ // Qualcomm Adreno ++ // from https://en.wikipedia.org/wiki/Adreno ++ Adreno1XX = 3000, // GLES1.1 ++ Adreno2XX, // GLES2.0 DX9c ++ Adreno3XX, // GLES3.0 CL1.1 DX11.1 ++ Adreno4XX, // GLES3.1 CL1.2 DX11.2 ++ Adreno5XX, // GLES3.1 CL2.0 DX11.2 ++ UnknownAdreno = 3999, ++ ++ UnknownChipClass = 99999 ++}; ++ ++ ++class GLPlatform ++{ ++public: ++ ~GLPlatform(); ++ ++ /** ++ * Runs the detection code using the current OpenGL context. ++ */ ++ void detect(); ++ ++ /** ++ * Prints the results of the detection code. ++ */ ++ void printResults() const; ++ ++ /** ++ * Returns a pointer to the GLPlatform instance. ++ */ ++ static GLPlatform *instance(); ++ ++ /** ++ * Returns true if the driver support the given feature, and false otherwise. ++ */ ++ bool supports(GLFeature feature) const; ++ ++ /** ++ * Returns the OpenGL version. ++ */ ++ qint64 glVersion() const; ++ ++ /** ++ * Returns the GLSL version if the driver supports GLSL, and 0 otherwise. ++ */ ++ qint64 glslVersion() const; ++ ++ /** ++ * Returns the Mesa version if the driver is a Mesa driver, and 0 otherwise. ++ */ ++ qint64 mesaVersion() const; ++ ++ /** ++ * Returns the Gallium version if the driver is a Gallium driver, and 0 otherwise. ++ */ ++ qint64 galliumVersion() const; ++ ++ /** ++ * Returns the X server version. ++ * ++ * Note that the version number changed from 7.2 to 1.3 in the first release ++ * following the doupling of the X server from the katamari. ++ * ++ * For non X.org servers, this method returns 0. ++ */ ++ qint64 serverVersion() const; ++ ++ /** ++ * Returns the Linux kernel version. ++ * ++ * If the kernel is not a Linux kernel, this method returns 0. ++ */ ++ qint64 kernelVersion() const; ++ ++ /** ++ * Returns the driver version. ++ * ++ * For Mesa drivers, this is the same as the Mesa version number. ++ */ ++ qint64 driverVersion() const; ++ ++ /** ++ * Returns the driver. ++ */ ++ Driver driver() const; ++ ++ /** ++ * Returns the chip class. ++ */ ++ ChipClass chipClass() const; ++ ++ /** ++ * Returns true if the driver is a Mesa driver, and false otherwise. ++ */ ++ bool isMesaDriver() const; ++ ++ /** ++ * Returns true if the driver is a Gallium driver, and false otherwise. ++ */ ++ bool isGalliumDriver() const; ++ ++ /** ++ * Returns true if the GPU is a Radeon GPU, and false otherwise. ++ */ ++ bool isRadeon() const; ++ ++ /** ++ * Returns true if the GPU is an NVIDIA GPU, and false otherwise. ++ */ ++ bool isNvidia() const; ++ ++ /** ++ * Returns true if the GPU is an Intel GPU, and false otherwise. ++ */ ++ bool isIntel() const; ++ ++ /** ++ * @returns @c true if the "GPU" is a VirtualBox GPU, and @c false otherwise. ++ * @since 4.10 ++ **/ ++ bool isVirtualBox() const; ++ ++ /** ++ * @returns @c true if the "GPU" is a VMWare GPU, and @c false otherwise. ++ * @since 4.10 ++ **/ ++ bool isVMware() const; ++ ++ /** ++ * @returns @c true if OpenGL is emulated in software. ++ * @since 4.7 ++ **/ ++ bool isSoftwareEmulation() const; ++ ++ /** ++ * @returns @c true if the driver is known to be from a virtual machine. ++ * @since 4.10 ++ **/ ++ bool isVirtualMachine() const; ++ ++ /** ++ * @returns @c true if the GPU is a Qualcomm Adreno GPU, and false otherwise ++ * @since 5.8 ++ **/ ++ bool isAdreno() const; ++ ++ /** ++ * @returns the GL_VERSION string as provided by the driver. ++ * @since 4.9 ++ **/ ++ const QByteArray &glVersionString() const; ++ /** ++ * @returns the GL_RENDERER string as provided by the driver. ++ * @since 4.9 ++ **/ ++ const QByteArray &glRendererString() const; ++ /** ++ * @returns the GL_VENDOR string as provided by the driver. ++ * @since 4.9 ++ **/ ++ const QByteArray &glVendorString() const; ++ /** ++ * @returns the GL_SHADING_LANGUAGE_VERSION string as provided by the driver. ++ * If the driver does not support the OpenGL Shading Language a null bytearray is returned. ++ * @since 4.9 ++ **/ ++ const QByteArray &glShadingLanguageVersionString() const; ++ /** ++ * @returns Whether the driver supports loose texture binding. ++ * @since 4.9 ++ **/ ++ bool isLooseBinding() const; ++ /** ++ * @returns Whether OpenGL ES is used ++ */ ++ bool isGLES() const; ++ ++ /** ++ * Returns true if glMapBufferRange() is likely to perform worse than glBufferSubData() ++ * when updating an unused range of a buffer object, and false otherwise. ++ * ++ * @since 4.11 ++ */ ++ bool preferBufferSubData() const; ++ ++ /** ++ * @returns a human readable form of the @p version as a QString. ++ * @since 4.9 ++ * @see glVersion ++ * @see glslVersion ++ * @see driverVersion ++ * @see mesaVersion ++ * @see galliumVersion ++ * @see kernelVersion ++ * @see serverVersion ++ **/ ++ static QString versionToString(qint64 version); ++ /** ++ * @returns a human readable form of the @p version as a QByteArray. ++ * @since 5.5 ++ * @see glVersion ++ * @see glslVersion ++ * @see driverVersion ++ * @see mesaVersion ++ * @see galliumVersion ++ * @see kernelVersion ++ * @see serverVersion ++ **/ ++ static QByteArray versionToString8(qint64 version); ++ ++ /** ++ * @returns a human readable form for the @p driver as a QString. ++ * @since 4.9 ++ * @see driver ++ **/ ++ static QString driverToString(Driver driver); ++ /** ++ * @returns a human readable form for the @p driver as a QByteArray. ++ * @since 5.5 ++ * @see driver ++ **/ ++ static QByteArray driverToString8(Driver driver); ++ ++ /** ++ * @returns a human readable form for the @p chipClass as a QString. ++ * @since 4.9 ++ * @see chipClass ++ **/ ++ static QString chipClassToString(ChipClass chipClass); ++ /** ++ * @returns a human readable form for the @p chipClass as a QByteArray. ++ * @since 5.5 ++ * @see chipClass ++ **/ ++ static QByteArray chipClassToString8(ChipClass chipClass); ++ ++private: ++ GLPlatform(); ++ friend void KWin::cleanupGL(); ++ static void cleanup(); ++ ++private: ++ QByteArray m_renderer; ++ QByteArray m_vendor; ++ QByteArray m_version; ++ QByteArray m_glsl_version; ++ QByteArray m_chipset; ++ QSet m_extensions; ++ Driver m_driver; ++ ChipClass m_chipClass; ++ qint64 m_glVersion; ++ qint64 m_glslVersion; ++ qint64 m_mesaVersion; ++ qint64 m_driverVersion; ++ qint64 m_galliumVersion; ++ qint64 m_serverVersion; ++ qint64 m_kernelVersion; ++ bool m_looseBinding: 1; ++ bool m_supportsGLSL: 1; ++ bool m_limitedGLSL: 1; ++ bool m_textureNPOT: 1; ++ bool m_limitedNPOT: 1; ++ bool m_virtualMachine: 1; ++ bool m_preferBufferSubData: 1; ++ bool m_gles: 1; ++ static GLPlatform *s_platform; ++}; ++ ++inline GLPlatform *GLPlatform::instance() ++{ ++ if (!s_platform) ++ s_platform = new GLPlatform; ++ ++ return s_platform; ++} ++ ++} // namespace KWin ++ ++#endif // KWIN_GLPLATFORM_H ++ +diff --git a/greeter/seccomp_filter.cpp b/greeter/seccomp_filter.cpp +index 79244f9..9d61d4a 100644 +--- a/greeter/seccomp_filter.cpp ++++ b/greeter/seccomp_filter.cpp +@@ -21,9 +21,11 @@ You should have received a copy of the GNU General Public License + along with this program. If not, see . + *********************************************************************/ + #include "seccomp_filter.h" ++#include "kwinglplatform.h" + + #include + #include ++#include + + #include + #include +@@ -38,7 +40,22 @@ void init() + { + // trigger OpenGL context creation + // we need this to ensure that all required files are opened for write +- QOpenGLContext::supportsThreadedOpenGL(); ++ // on NVIDIA we need to keep write around, otherwise BUG 384005 happens ++ bool writeSupported = true; ++ QScopedPointer dummySurface(new QOffscreenSurface); ++ dummySurface->create(); ++ QOpenGLContext dummyGlContext; ++ if (dummyGlContext.create()) { ++ if (dummyGlContext.makeCurrent(dummySurface.data())) { ++ auto gl = KWin::GLPlatform::instance(); ++ gl->detect(); ++ gl->printResults(); ++ if (gl->driver() == KWin::Driver_NVidia) { ++ // BUG: 384005 ++ writeSupported = false; ++ } ++ } ++ } + + // access DBus to have the socket open + QDBusConnection::sessionBus(); +@@ -57,8 +74,10 @@ void init() + + // instead disallow opening new files for writing + // they should fail with EPERM error +- seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)); +- seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)); ++ if (writeSupported) { ++ seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)); ++ seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)); ++ } + seccomp_rule_add(context, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT)); + + // disallow going to a socket +-- +2.14.1 + diff --git a/kscreenlocker.changes b/kscreenlocker.changes index 2c286fb..cbde6e0 100644 --- a/kscreenlocker.changes +++ b/kscreenlocker.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Aug 31 07:33:23 UTC 2017 - fabian@ritter-vogt.de + +- Add patch to allow the NVIDIA driver to poke through seccomp and + thus not crashing (kde#384005): + * 0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch + ------------------------------------------------------------------- Tue Aug 22 19:11:30 CEST 2017 - fabian@ritter-vogt.de diff --git a/kscreenlocker.spec b/kscreenlocker.spec index 73536d9..f06aa71 100644 --- a/kscreenlocker.spec +++ b/kscreenlocker.spec @@ -27,6 +27,8 @@ Url: https://projects.kde.org/kscreenlocker Source: http://download.kde.org/stable/plasma/%{version}/kscreenlocker-%{version}.tar.xz # PATCH-FIX-OPENSUSE fix-wayland-version-requirement.diff -- Changes wayland requirement from 1.3 to 1.2.1 Patch0: fix-wayland-version-requirement.diff +# PATCH-FIX-UPSTREAM 0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch +Patch1: 0001-Don-t-dissallow-open-with-write-flag-syscall-on-NVID.patch BuildRequires: cmake >= 2.8.12 BuildRequires: extra-cmake-modules >= 1.8.0 BuildRequires: kf5-filesystem @@ -59,11 +61,7 @@ BuildRequires: pkgconfig(xcursor) BuildRequires: pkgconfig(xi) Requires(post): pam-config Requires(post): /usr/bin/killall -%if %{with lang} Recommends: %{name}-lang -%else -Obsoletes: %{name}-lang -%endif BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -93,6 +91,7 @@ Development files for Library and components for secure lock screen architecture # SLE12 has a patched 1.2.1 wayland with all features KDE needs from up to 1.7.0 %patch0 -p1 %endif +%patch1 -p1 %build %cmake_kf5 -d build -- -DKDE4_COMMON_PAM_SERVICE=xdm -DCMAKE_INSTALL_LOCALEDIR=%{_kf5_localedir}